Decompiled source of PeakStranding v0.9.3
plugins/com.github.wafflecomposite.PeakStranding.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PeakStranding.Components; using PeakStranding.Data; using PeakStranding.Online; using PeakStranding.UI; using Photon.Pun; using Photon.Realtime; using Steamworks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("com.github.wafflecomposite.PeakStranding")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.9.3.0")] [assembly: AssemblyInformationalVersion("0.9.3+352eb678edc38ccc798c2bae5303d3ba4654296b")] [assembly: AssemblyProduct("com.github.wafflecomposite.PeakStranding")] [assembly: AssemblyTitle("PeakStranding")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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; } } [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; } } } public class BiDictionary : IEnumerable<KeyValuePair<string, string>>, IEnumerable { private readonly Dictionary<string, string> _forward = new Dictionary<string, string>(); private readonly Dictionary<string, string> _reverse = new Dictionary<string, string>(); public void Add(string first, string second) { if (_forward.ContainsKey(first) || _reverse.ContainsKey(second)) { throw new ArgumentException("Duplicate key or value."); } _forward[first] = second; _reverse[second] = first; } public bool TryGetByFirst(string first, out string second) { return _forward.TryGetValue(first, out second); } public bool TryGetBySecond(string second, out string first) { return _reverse.TryGetValue(second, out first); } public bool RemoveByFirst(string first) { if (!_forward.TryGetValue(first, out string value)) { return false; } _forward.Remove(first); _reverse.Remove(value); return true; } public bool RemoveBySecond(string second) { if (!_reverse.TryGetValue(second, out string value)) { return false; } _reverse.Remove(second); _forward.Remove(value); return true; } public List<string> GetAllFirsts() { return new List<string>(_forward.Keys); } public List<string> GetAllSeconds() { return new List<string>(_reverse.Keys); } public IEnumerator<KeyValuePair<string, string>> GetEnumerator() { return _forward.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } internal string TryGetByFirst(string prefabName) { throw new NotImplementedException(); } } public class RestoredInteractable : MonoBehaviour, IInteractible { public string RestoredName = "Restored Interactable"; public string GetName() { return RestoredName; } public bool IsInteractible(Character interactor) { return true; } public void Interact(Character interactor) { } public void HoverEnter() { } public void HoverExit() { } public Vector3 Center() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return ((Component)this).transform.position; } public Transform GetTransform() { return ((Component)this).transform; } public string GetInteractionText() { return string.Empty; } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace PeakStranding { [BepInPlugin("com.github.wafflecomposite.PeakStranding", "PeakStranding", "0.9.3")] public class Plugin : BaseUnityPlugin, IOnEventCallback { internal static ConfigEntry<bool> saveStructuresLocallyConfig; internal static ConfigEntry<bool> loadLocalStructuresConfig; internal static ConfigEntry<int> localStructuresLimitConfig; internal static ConfigEntry<bool> sendStructuresToRemoteConfig; internal static ConfigEntry<bool> loadRemoteStructuresConfig; internal static ConfigEntry<int> remoteStructuresLimitConfig; internal static ConfigEntry<string> remoteApiUrlConfig; internal static ConfigEntry<bool> showStructureOverlayConfig; internal static ConfigEntry<bool> showToastsConfig; internal static ConfigEntry<bool> ropeOptimizerExperimentalConfig; internal static ConfigEntry<string> structureAllowListConfig; internal static ConfigEntry<bool> allowClientsLikeConfig; internal static ConfigEntry<bool> allowClientsDeleteConfig; internal static ConfigEntry<KeyCode> overlayLikeKeyConfig; internal static ConfigEntry<KeyCode> overlayRemoveKeyConfig; public const string Id = "com.github.wafflecomposite.PeakStranding"; internal static ManualLogSource Log { get; private set; } public static bool CfgLocalSaveStructures => saveStructuresLocallyConfig.Value; public static bool CfgLocalLoadStructures => loadLocalStructuresConfig.Value; public static int CfgLocalStructuresLimit => localStructuresLimitConfig.Value; public static bool CfgRemoteSaveStructures => sendStructuresToRemoteConfig.Value; public static bool CfgRemoteLoadStructures => loadRemoteStructuresConfig.Value; public static int CfgRemoteStructuresLimit => remoteStructuresLimitConfig.Value; public static string CfgRemoteApiUrl => remoteApiUrlConfig.Value; public static bool CfgShowStructureOverlay => showStructureOverlayConfig.Value; public static bool CfgRopeOptimizerExperimental => ropeOptimizerExperimentalConfig.Value; public static string CfgStructureAllowList => structureAllowListConfig.Value; public static bool CfgAllowClientLike => allowClientsLikeConfig.Value; public static bool CfgAllowClientDelete => allowClientsDeleteConfig.Value; public static bool CfgShowToasts => showToastsConfig.Value; public static string Name => "PeakStranding"; public static string Version => "0.9.3"; private void Awake() { //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: 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_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Expected O, but got Unknown //IL_02da: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; saveStructuresLocallyConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Local", "Save_Structures_Locally", true, "Whether to save structures placed in your lobby locally"); loadLocalStructuresConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Local", "Load_Local_Structures", false, "Whether to load previously saved structures at the start of a new run"); localStructuresLimitConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Local", "Local_Structures_Limit", -1, "How many local structures to load at the start of a new run (-1 for no limit). If you have more than this, only the most recent ones will be loaded."); sendStructuresToRemoteConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Online", "Send_Structures_To_Online", true, "Whether to send structures placed in your lobby to other players"); loadRemoteStructuresConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Online", "Load_Online_Structures", true, "Whether to load random structures placed by other players"); remoteStructuresLimitConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Online", "Online_Structures_Limit", 40, "How many remote structures to load at the start of a new run"); showStructureOverlayConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show_Structure_Overlay", true, "Whether to show the overlay for structures placed by other players in the world"); showToastsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show_Toasts", true, "Enable or disable toast notifications in the UI."); structureAllowListConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Online", "Structure_Allow_List", string.Join(" ", DataHelper.prefabMapping.GetAllSeconds()), "A space-separated list of structure prefab names that are allowed to be placed by other players. Leave empty to allow all structures."); ropeOptimizerExperimentalConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Experimental", "Experimental_Rope_Optimizer", true, "Enable experimental optimizations for the ropes."); remoteApiUrlConfig = ((BaseUnityPlugin)this).Config.Bind<string>("Online", "Custom_Server_Api_BaseUrl", "", "Custom Server URL. Leave empty to use official Peak Stranding server"); allowClientsLikeConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Online", "Allow_Clients_Like", true, "Allow clients to like structures."); allowClientsDeleteConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Online", "Allow_Clients_Delete", true, "Allow clients to delete structures."); overlayLikeKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Overlay_Like_Key", (KeyCode)108, "Key used to like structures from the overlay."); overlayRemoveKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Overlay_Remove_Key", (KeyCode)127, "Key used to remove structures from the overlay."); OverlayManager.LikeShortcut = overlayLikeKeyConfig.Value; OverlayManager.RemoveShortcut = overlayRemoveKeyConfig.Value; overlayLikeKeyConfig.SettingChanged += delegate { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) OverlayManager.LikeShortcut = overlayLikeKeyConfig.Value; }; overlayRemoveKeyConfig.SettingChanged += delegate { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) OverlayManager.RemoveShortcut = overlayRemoveKeyConfig.Value; }; PhotonNetwork.AddCallbackTarget((object)this); Log.LogInfo((object)("Plugin " + Name + " is patching...")); Harmony val = new Harmony("com.github.wafflecomposite.PeakStranding"); val.PatchAll(); Log.LogInfo((object)("Plugin " + Name + " is loaded!")); if ((Object)(object)ToastController.Instance == (Object)null) { new GameObject("PeakStranding UI Toasts").AddComponent<ToastController>(); } List<string> allSeconds = DataHelper.prefabMapping.GetAllSeconds(); if (string.IsNullOrWhiteSpace(CfgStructureAllowList)) { return; } string[] array = CfgStructureAllowList.ToLower().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { if (!allSeconds.Contains(text)) { Log.LogWarning((object)("Unrecognized prefab name in allow list: '" + text + "'. Please check your structure allow list.")); } } } private void OnDestroy() { PhotonNetwork.RemoveCallbackTarget((object)this); } public void OnEvent(EventData photonEvent) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0049: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: 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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if (photonEvent.Code != 202) { return; } Hashtable val = (Hashtable)photonEvent.CustomData; string prefabName = (string)val[(byte)0]; Vector3 val2 = (Vector3)(val.ContainsKey((byte)1) ? ((Vector3)val[(byte)1]) : Vector3.zero); Quaternion rotation = (Quaternion)(val.ContainsKey((byte)2) ? ((Quaternion)val[(byte)2]) : Quaternion.identity); object[] array = (val.ContainsKey((byte)5) ? ((object[])val[(byte)5]) : null); if (array == null || array.Length == 0 || !(array[0] as string == "PEAK_STRANDING_RESTORED")) { string[] array2 = new string[7] { "0_Items/ClimbingSpikeHammered", "0_Items/ShelfShroomSpawn", "0_Items/BounceShroomSpawn", "Flag_planted_seagull", "Flag_planted_turtle", "PortableStovetop_Placed", "ScoutCannon_Placed" }; if (Array.Exists(array2, (string p) => p == prefabName)) { Log.LogInfo((object)$"Player {photonEvent.Sender} placed {prefabName} at {val2}, saving it..."); PlacedItemData placedItemData = new PlacedItemData { PrefabName = prefabName, Position = val2, Rotation = rotation }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } } public static class SaveManager { [CompilerGenerated] private sealed class <>c__DisplayClass20_0 { public PlacedItemData itemData; public object[] instantiationData; public Action<GameObject> onSpawned; public Rope rope; public string anchorPrefabName; public float seg; public RopeSpool spool; public GameObject ropeObj; public GameObject spoolObj; } [CompilerGenerated] private sealed class <SetAntigravWhenReady>d__21 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public RopeAnchorWithRope rapw; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SetAntigravWhenReady>d__21(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; break; case 1: <>1__state = -1; break; } if ((Object)(object)rapw.rope == (Object)null) { <>2__current = null; <>1__state = 1; return true; } rapw.rope.antigrav = true; 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 const string RESTORED_ITEM_MARKER = "PEAK_STRANDING_RESTORED"; private static readonly List<PlacedItemData> SessionPlacedItems = new List<PlacedItemData>(); private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings { Converters = new List<JsonConverter> { (JsonConverter)(object)new Vector3Converter(), (JsonConverter)(object)new QuaternionConverter() } }; private static readonly Dictionary<int, List<(PlacedItemData data, string label, ulong id, int likes, ulong user_id)>> CachedStructures = new Dictionary<int, List<(PlacedItemData, string, ulong, int, ulong)>>(); private static readonly Dictionary<int, List<GameObject>> SpawnedInstances = new Dictionary<int, List<GameObject>>(); public static bool IsRestoring { get; private set; } public static void BeginRestore() { IsRestoring = true; } public static void EndRestore() { IsRestoring = false; } private static string GetSaveFilePath(int mapId) { string text = Path.Combine(Paths.ConfigPath, "PeakStranding", "PlacedItems"); Directory.CreateDirectory(text); return Path.Combine(text, $"PlacedItems_{mapId}.json"); } public static void ClearCache() { SessionPlacedItems.Clear(); CachedStructures.Clear(); foreach (int item in SpawnedInstances.Keys.ToList()) { DespawnStructuresForSegment(item); } SpawnedInstances.Clear(); } public static void SaveItem(PlacedItemData data) { if ((!Plugin.CfgLocalSaveStructures && !Plugin.CfgRemoteSaveStructures) || data == null || !PhotonNetwork.IsMasterClient) { return; } SessionPlacedItems.Add(data); int currentLevelIndex = DataHelper.GetCurrentLevelIndex(); if (Plugin.CfgLocalSaveStructures) { string saveFilePath = GetSaveFilePath(currentLevelIndex); List<PlacedItemData> savedItemsForSeed = GetSavedItemsForSeed(currentLevelIndex); savedItemsForSeed.Add(data); string contents = JsonConvert.SerializeObject((object)savedItemsForSeed, (Formatting)1, JsonSettings); File.WriteAllText(saveFilePath, contents); Plugin.Log.LogInfo((object)$"Saved local item {data.PrefabName}. Total items for map {currentLevelIndex}: {savedItemsForSeed.Count}"); } if (!Plugin.CfgRemoteSaveStructures) { return; } try { RemoteApi.Upload(currentLevelIndex, data); } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to upload item " + data.PrefabName + ": " + ex.Message)); } } private static List<PlacedItemData> GetSavedItemsForSeed(int mapId) { string saveFilePath = GetSaveFilePath(mapId); if (File.Exists(saveFilePath)) { string text = File.ReadAllText(saveFilePath); return JsonConvert.DeserializeObject<List<PlacedItemData>>(text, JsonSettings) ?? new List<PlacedItemData>(); } return new List<PlacedItemData>(); } public static void CacheLocalStructures() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } int currentLevelIndex = DataHelper.GetCurrentLevelIndex(); List<PlacedItemData> savedItemsForSeed = GetSavedItemsForSeed(currentLevelIndex); List<PlacedItemData> list = savedItemsForSeed; if (Plugin.CfgLocalStructuresLimit > 0 && savedItemsForSeed.Count > Plugin.CfgLocalStructuresLimit) { list = savedItemsForSeed.Skip(savedItemsForSeed.Count - Plugin.CfgLocalStructuresLimit).ToList(); } Plugin.Log.LogInfo((object)$"Caching {list.Count} local items for map {currentLevelIndex}."); foreach (PlacedItemData item in list) { if (!CachedStructures.ContainsKey(item.MapSegment)) { CachedStructures[item.MapSegment] = new List<(PlacedItemData, string, ulong, int, ulong)>(); } CachedStructures[item.MapSegment].Add((item, "You", 0uL, 0, SteamUser.GetSteamID().m_SteamID)); } } public static void CacheRemoteStructures(List<ServerStructureDto> items) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsMasterClient) { return; } if (items == null || items.Count == 0) { Plugin.Log.LogInfo((object)"No remote structures to cache."); ToastController.Instance.Toast("PeakStranding: no online items found for current map!?", Color.yellow, 5f, 3f); return; } foreach (ServerStructureDto item in items) { PlacedItemData placedItemData = item.ToPlacedItemData(); if (!CachedStructures.ContainsKey(placedItemData.MapSegment)) { CachedStructures[placedItemData.MapSegment] = new List<(PlacedItemData, string, ulong, int, ulong)>(); } CachedStructures[placedItemData.MapSegment].Add((placedItemData, item.username, item.id, item.likes, item.user_id)); } ToastController.Instance.Toast($"PeakStranding: {items.Count} online items have been loaded!", Color.green, 5f, 3f); } public static void SpawnStructuresForSegment(int segmentIndex) { if (!PhotonNetwork.IsMasterClient) { return; } if (!CachedStructures.TryGetValue(segmentIndex, out List<(PlacedItemData, string, ulong, int, ulong)> value)) { Plugin.Log.LogInfo((object)$"No cached structures to spawn for segment {segmentIndex}."); return; } BeginRestore(); try { Plugin.Log.LogInfo((object)$"Spawning {value.Count} structures for segment {segmentIndex}."); foreach (var item in value) { var (itemData, label, id, likes, user_id) = item; SpawnItem(itemData, label, delegate(GameObject spawnedGo) { if ((Object)(object)spawnedGo == (Object)null) { Plugin.Log.LogWarning((object)"SpawnItem resulted in a null GameObject. Skipping registration."); } else { if (!SpawnedInstances.ContainsKey(segmentIndex)) { SpawnedInstances[segmentIndex] = new List<GameObject>(); } SpawnedInstances[segmentIndex].Add(spawnedGo); if (!((Object)(object)spawnedGo.GetComponent<Rope>() != (Object)null) || !((Object)(object)spawnedGo.GetComponent<RopeAnchor>() == (Object)null) || !((Object)(object)spawnedGo.GetComponent<RopeAnchorWithRope>() == (Object)null)) { OverlayManager.RegisterInfo info = default(OverlayManager.RegisterInfo); info.target = spawnedGo; info.username = label; info.likes = likes; info.id = id; info.user_id = user_id; info.canLike = true; OverlayManager.Register(info); PeakStrandingSyncManager.Instance?.RegisterNewStructure(spawnedGo, label, likes, id, user_id); } } }); } } finally { EndRestore(); } } public static void DespawnStructuresForSegment(int segmentIndex) { if (!PhotonNetwork.IsMasterClient) { return; } if (!SpawnedInstances.TryGetValue(segmentIndex, out List<GameObject> value)) { Plugin.Log.LogInfo((object)$"No spawned instances to despawn for segment {segmentIndex}."); return; } Plugin.Log.LogInfo((object)$"Despawning {value.Count} structures for segment {segmentIndex}."); foreach (GameObject item in value) { if ((Object)(object)item != (Object)null) { DeletionUtility.Delete(item); } } SpawnedInstances.Remove(segmentIndex); } public static void CleanupRunStructures() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (!PhotonNetwork.IsMasterClient) { return; } Plugin.Log.LogInfo((object)"Cleaning up all structures from the run."); int num = 0; ValueIterator<int, PhotonView> enumerator = PhotonNetwork.PhotonViewCollection.GetEnumerator(); try { while (enumerator.MoveNext()) { PhotonView current = enumerator.Current; if (!((Object)(object)current == (Object)null) && current.InstantiationData != null && current.InstantiationData.Length != 0 && current.InstantiationData[0] is string text && text == "PEAK_STRANDING_RESTORED") { PhotonNetwork.Destroy(((Component)current).gameObject); num++; } } } finally { ((IDisposable)enumerator).Dispose(); } Plugin.Log.LogInfo((object)$"Cleaned up {num} spawned structures and their buffered RPCs."); SpawnedInstances.Clear(); CachedStructures.Clear(); SessionPlacedItems.Clear(); } public static void SpawnItem(PlacedItemData itemData, string label = "", Action<GameObject>? onSpawned = null) { //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0228: 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_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_0528: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: 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_0282: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) <>c__DisplayClass20_0 CS$<>8__locals0 = new <>c__DisplayClass20_0(); CS$<>8__locals0.itemData = itemData; CS$<>8__locals0.onSpawned = onSpawned; string prefabName = CS$<>8__locals0.itemData.PrefabName; if (!DataHelper.IsPrefabAllowed(prefabName)) { Plugin.Log.LogError((object)("Prefab '" + prefabName + "' is not allowed by the structure allow list.")); CS$<>8__locals0.onSpawned?.Invoke(null); return; } CS$<>8__locals0.instantiationData = new object[1] { "PEAK_STRANDING_RESTORED" }; if (!prefabName.StartsWith("PeakStranding/")) { GameObject val = Resources.Load<GameObject>(prefabName); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Prefab not found in Resources: " + prefabName)); CS$<>8__locals0.onSpawned?.Invoke(null); return; } GameObject val2 = PhotonNetwork.Instantiate(prefabName, CS$<>8__locals0.itemData.Position, CS$<>8__locals0.itemData.Rotation, (byte)0, CS$<>8__locals0.instantiationData); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)("Failed to instantiate prefab via Photon: " + prefabName)); CS$<>8__locals0.onSpawned?.Invoke(null); } else { val2.AddComponent<RestoredItem>(); CS$<>8__locals0.onSpawned?.Invoke(val2); } } else if (prefabName.StartsWith("PeakStranding/JungleVine")) { GameObject val3 = PhotonNetwork.Instantiate("ChainShootable", CS$<>8__locals0.itemData.RopeStart, Quaternion.identity, (byte)0, CS$<>8__locals0.instantiationData); CS$<>8__locals0.onSpawned?.Invoke(val3); JungleVine component = val3.GetComponent<JungleVine>(); if ((Object)(object)component != (Object)null) { component.photonView.RPC("ForceBuildVine_RPC", (RpcTarget)3, new object[4] { CS$<>8__locals0.itemData.RopeStart, CS$<>8__locals0.itemData.RopeEnd, CS$<>8__locals0.itemData.RopeLength, CS$<>8__locals0.itemData.RopeFlyingRotation }); } else { Plugin.Log.LogError((object)"Failed to instantiate JungleVine prefab: vine == null"); } } else if (prefabName.StartsWith("PeakStranding/RopeShooter")) { string text = (CS$<>8__locals0.itemData.RopeAntiGrav ? "RopeAnchorForRopeShooterAnti" : "RopeAnchorForRopeShooter"); GameObject val4 = PhotonNetwork.Instantiate(text, CS$<>8__locals0.itemData.RopeStart, CS$<>8__locals0.itemData.RopeAnchorRotation, (byte)0, CS$<>8__locals0.instantiationData); CS$<>8__locals0.onSpawned?.Invoke(val4); RopeAnchorProjectile component2 = val4.GetComponent<RopeAnchorProjectile>(); if ((Object)(object)component2 == (Object)null) { Plugin.Log.LogError((object)"Failed to instantiate Rope: Prefab lacks RopeAnchorProjectile"); return; } float num = Vector3.Distance(CS$<>8__locals0.itemData.RopeStart, CS$<>8__locals0.itemData.RopeEnd) * 0.01f; component2.photonView.RPC("GetShot", (RpcTarget)3, new object[4] { CS$<>8__locals0.itemData.RopeEnd, num, CS$<>8__locals0.itemData.RopeLength, CS$<>8__locals0.itemData.RopeFlyingRotation }); if (CS$<>8__locals0.itemData.RopeAntiGrav) { RopeAnchorWithRope component3 = val4.GetComponent<RopeAnchorWithRope>(); if ((Object)(object)component3 != (Object)null) { ((MonoBehaviour)component2).StartCoroutine(SetAntigravWhenReady(component3)); } } } else if (prefabName.StartsWith("PeakStranding/RopeSpool")) { string text2 = (CS$<>8__locals0.itemData.RopeAntiGrav ? "0_Items/Anti-Rope Spool" : "0_Items/RopeSpool"); CS$<>8__locals0.anchorPrefabName = (CS$<>8__locals0.itemData.RopeAntiGrav ? "RopeAnchorAnti" : "RopeAnchor"); CS$<>8__locals0.spoolObj = PhotonNetwork.Instantiate(text2, CS$<>8__locals0.itemData.Position, CS$<>8__locals0.itemData.Rotation, (byte)0, CS$<>8__locals0.instantiationData); CS$<>8__locals0.spoolObj.AddComponent<RestoredItem>(); CS$<>8__locals0.spool = CS$<>8__locals0.spoolObj.GetComponent<RopeSpool>(); CS$<>8__locals0.ropeObj = PhotonNetwork.Instantiate(((Object)CS$<>8__locals0.spool.ropePrefab).name, CS$<>8__locals0.spool.ropeBase.position, CS$<>8__locals0.spool.ropeBase.rotation, (byte)0, CS$<>8__locals0.instantiationData); CS$<>8__locals0.ropeObj.AddComponent<RestoredItem>(); CS$<>8__locals0.rope = CS$<>8__locals0.ropeObj.GetComponent<Rope>(); ((MonoBehaviourPun)CS$<>8__locals0.rope).photonView.RPC("AttachToSpool_Rpc", (RpcTarget)3, new object[1] { ((ItemComponent)CS$<>8__locals0.spool).photonView }); CS$<>8__locals0.seg = Mathf.Max(CS$<>8__locals0.itemData.RopeLength, CS$<>8__locals0.spool.minSegments); CS$<>8__locals0.spool.Segments = CS$<>8__locals0.seg; CS$<>8__locals0.rope.Segments = CS$<>8__locals0.seg; if (CS$<>8__locals0.itemData.RopeAntiGrav) { CS$<>8__locals0.spool.isAntiRope = true; CS$<>8__locals0.rope.antigrav = true; } ((MonoBehaviour)CS$<>8__locals0.spool).StartCoroutine(FinaliseRope()); } else if (prefabName.StartsWith("PeakStranding/MagicBeanVine")) { GameObject val5 = PhotonNetwork.Instantiate("0_Items/MagicBean", CS$<>8__locals0.itemData.Position, Quaternion.identity, (byte)0, CS$<>8__locals0.instantiationData); val5.AddComponent<RestoredItem>(); MagicBean component4 = val5.GetComponent<MagicBean>(); if ((Object)(object)component4 == (Object)null) { Plugin.Log.LogError((object)"Failed to instantiate MagicBean: prefab missing MagicBean script"); return; } Vector3 val6 = CS$<>8__locals0.itemData.Rotation * Vector3.forward; ((ItemComponent)component4).photonView.RPC("GrowVineRPC", (RpcTarget)3, new object[3] { CS$<>8__locals0.itemData.Position, val6, CS$<>8__locals0.itemData.RopeLength }); CS$<>8__locals0.onSpawned?.Invoke(val5); } else { Plugin.Log.LogError((object)("Failed to instantiate some prefab: Unhandled type: " + prefabName)); CS$<>8__locals0.onSpawned?.Invoke(null); } [IteratorStateMachine(typeof(<>c__DisplayClass20_0.<<SpawnItem>g__FinaliseRope|0>d))] IEnumerator FinaliseRope() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <>c__DisplayClass20_0.<<SpawnItem>g__FinaliseRope|0>d(0) { <>4__this = CS$<>8__locals0 }; } } [IteratorStateMachine(typeof(<SetAntigravWhenReady>d__21))] private static IEnumerator SetAntigravWhenReady(RopeAnchorWithRope rapw) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SetAntigravWhenReady>d__21(0) { rapw = rapw }; } } public class Vector3Converter : JsonConverter<Vector3> { public override void WriteJson(JsonWriter writer, Vector3 value, JsonSerializer serializer) { //IL_0012: 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) //IL_0040: Unknown result type (might be due to invalid IL or missing references) writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.x); writer.WritePropertyName("y"); writer.WriteValue(value.y); writer.WritePropertyName("z"); writer.WriteValue(value.z); writer.WriteEndObject(); } public override Vector3 ReadJson(JsonReader reader, Type objectType, Vector3 existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) JObject val = JObject.Load(reader); JToken obj = val["x"]; float num = ((obj != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj) : 0f); JToken obj2 = val["y"]; float num2 = ((obj2 != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj2) : 0f); JToken obj3 = val["z"]; float num3 = ((obj3 != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj3) : 0f); return new Vector3(num, num2, num3); } } public class QuaternionConverter : JsonConverter<Quaternion> { public override void WriteJson(JsonWriter writer, Quaternion value, JsonSerializer serializer) { //IL_0012: 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) //IL_0040: 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) writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.x); writer.WritePropertyName("y"); writer.WriteValue(value.y); writer.WritePropertyName("z"); writer.WriteValue(value.z); writer.WritePropertyName("w"); writer.WriteValue(value.w); writer.WriteEndObject(); } public override Quaternion ReadJson(JsonReader reader, Type objectType, Quaternion existingValue, bool hasExistingValue, JsonSerializer serializer) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) JObject val = JObject.Load(reader); JToken obj = val["x"]; float num = ((obj != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj) : 0f); JToken obj2 = val["y"]; float num2 = ((obj2 != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj2) : 0f); JToken obj3 = val["z"]; float num3 = ((obj3 != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj3) : 0f); JToken obj4 = val["w"]; float num4 = ((obj4 != null) ? Extensions.Value<float>((IEnumerable<JToken>)obj4) : 0f); return new Quaternion(num, num2, num3, num4); } } } namespace PeakStranding.UI { public static class FontUtility { private static TMP_FontAsset _font; public static bool TryGetFont(out TMP_FontAsset font) { if ((Object)(object)_font == (Object)null && (Object)(object)GUIManager.instance != (Object)null && (Object)(object)GUIManager.instance.heroDayText != (Object)null && (Object)(object)((TMP_Text)GUIManager.instance.heroDayText).font != (Object)null) { _font = ((TMP_Text)GUIManager.instance.heroDayText).font; } font = _font; return (Object)(object)font != (Object)null; } } public class ToastController : MonoBehaviour { [CompilerGenerated] private sealed class <ClearToast>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ToastController <>4__this; public float duration; public float fadeTime; private float <timeElapsed>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ClearToast>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown int num = <>1__state; ToastController toastController = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if ((Object)(object)toastController.textMesh == (Object)null) { return false; } if (duration > 0f) { <>2__current = (object)new WaitForSeconds(duration); <>1__state = 1; return true; } goto IL_0067; case 1: <>1__state = -1; goto IL_0067; case 2: { <>1__state = -1; break; } IL_0067: <timeElapsed>5__2 = 0f; break; } if (<timeElapsed>5__2 < fadeTime) { <timeElapsed>5__2 += Time.deltaTime; float num2 = ((fadeTime <= 0f) ? 1f : Mathf.Clamp01(<timeElapsed>5__2 / fadeTime)); ((TMP_Text)toastController.textMesh).alpha = Mathf.Lerp(1f, 0f, num2); <>2__current = null; <>1__state = 2; return true; } ((TMP_Text)toastController.textMesh).alpha = 0f; toastController.clearCoroutine = null; 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 <FindFontEventually>d__8 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public ToastController <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FindFontEventually>d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ToastController toastController = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (!FontUtility.TryGetFont(out TMP_FontAsset font)) { <>2__current = null; <>1__state = 1; return true; } if ((Object)(object)toastController.textMesh != (Object)null) { ((TMP_Text)toastController.textMesh).font = font; } toastController.fontCoroutine = null; 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 static ToastController Instance; private TextMeshProUGUI textMesh; private Coroutine clearCoroutine; private Coroutine fontCoroutine; private void Awake() { Instance = this; Object.DontDestroyOnLoad((Object)(object)this); } private void Start() { //IL_0014: 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_0059: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)"Initializing Toast Controller..."); Canvas val = new GameObject("canvas").AddComponent<Canvas>(); ((Component)val).transform.SetParent(((Component)this).transform); val.renderMode = (RenderMode)0; val.sortingOrder = 32767; ((Component)val).gameObject.AddComponent<CanvasScaler>(); GameObject val2 = new GameObject("text"); val2.transform.SetParent(((Component)val).transform, false); RectTransform val3 = val2.AddComponent<RectTransform>(); val3.sizeDelta = new Vector2(1000f, 100f); val3.anchorMin = new Vector2(1f, 1f); val3.anchorMax = new Vector2(1f, 1f); val3.pivot = new Vector2(1f, 1f); val3.anchoredPosition = new Vector2(-5f, -20f); textMesh = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)textMesh).fontSize = 26f; ((TMP_Text)textMesh).fontSizeMin = 26f; ((TMP_Text)textMesh).fontSizeMax = 26f; ((TMP_Text)textMesh).alignment = (TextAlignmentOptions)260; Plugin.Log.LogInfo((object)"Toast Controller Initialized!"); fontCoroutine = ((MonoBehaviour)this).StartCoroutine(FindFontEventually()); } public void Toast(string text, Color color, float duration = 2f, float fadeTime = 1f) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (Plugin.CfgShowToasts && !((Object)(object)textMesh == (Object)null)) { if (clearCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(clearCoroutine); clearCoroutine = null; } ((TMP_Text)textMesh).text = text; ((Graphic)textMesh).color = color; ((TMP_Text)textMesh).alpha = 1f; clearCoroutine = ((MonoBehaviour)this).StartCoroutine(ClearToast(duration, fadeTime)); } } [IteratorStateMachine(typeof(<ClearToast>d__7))] private IEnumerator ClearToast(float duration, float fadeTime = 1f) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ClearToast>d__7(0) { <>4__this = this, duration = duration, fadeTime = fadeTime }; } [IteratorStateMachine(typeof(<FindFontEventually>d__8))] private IEnumerator FindFontEventually() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FindFontEventually>d__8(0) { <>4__this = this }; } } } namespace PeakStranding.Patches { [HarmonyPatch(typeof(GameOverHandler), "LoadAirportMaster")] public static class GameOverHandlerLoadAirportPatch { [HarmonyPrefix] private static void Prefix() { PeakStrandingSyncManager.DestroyInstance(); if (PhotonNetwork.IsMasterClient) { Plugin.Log.LogInfo((object)"Run is over, cleaning up all spawned structures and buffered RPCs."); SaveManager.CleanupRunStructures(); } } } [HarmonyPatch(typeof(JungleVine), "ForceBuildVine_RPC")] public class JungleVineForceBuildPatch { private static void Postfix(Vector3 from, Vector3 to, float hang, Vector3 mid) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && !SaveManager.IsRestoring) { PlacedItemData placedItemData = new PlacedItemData { PrefabName = "PeakStranding/JungleVine", RopeStart = from, RopeEnd = to, RopeLength = hang, RopeFlyingRotation = mid }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } [HarmonyPatch(typeof(MagicBean), "GrowVineRPC")] public static class MagicBeanGrowVinePatch { private static readonly ConditionalWeakTable<MagicBean, object> saved = new ConditionalWeakTable<MagicBean, object>(); private static readonly object s_token = new object(); private static void Postfix(MagicBean __instance, Vector3 pos, Vector3 direction, float maxLength) { //IL_0041: 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) //IL_0048: 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_004e: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && !SaveManager.IsRestoring && !saved.TryGetValue(__instance, out object _)) { saved.Add(__instance, s_token); PlacedItemData placedItemData = new PlacedItemData { PrefabName = "PeakStranding/MagicBeanVine", Position = pos, Rotation = Quaternion.LookRotation(direction), RopeLength = maxLength }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } [HarmonyPatch(typeof(MagicBean), "GrowVineRPC")] public static class MagicBean_GrowAndTrackVine_Patch { private static bool Prefix(MagicBean __instance, Vector3 pos, Vector3 direction, float maxLength) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) MagicBeanLink magicBeanLink = ((Component)__instance).GetComponent<MagicBeanLink>(); RestoredItem component = ((Component)__instance).GetComponent<RestoredItem>(); bool isRestoredBean = (Object)(object)component != (Object)null; if ((Object)(object)magicBeanLink != (Object)null && (Object)(object)magicBeanLink.vine != (Object)null) { return false; } if ((Object)(object)magicBeanLink == (Object)null) { magicBeanLink = ((Component)__instance).gameObject.AddComponent<MagicBeanLink>(); } MagicBeanVine val = Object.Instantiate<MagicBeanVine>(__instance.plantPrefab, pos, Quaternion.identity); ((Component)val).transform.up = direction; val.maxLength = maxLength; magicBeanLink.vine = val; magicBeanLink.isRestoredBean = isRestoredBean; return false; } } [HarmonyPatch(typeof(MapHandler), "GoToSegment")] public static class MapHandlerGoToSegmentPatch { [HarmonyPostfix] private static void Postfix(MapHandler __instance, Segment s) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected I4, but got Unknown if (PhotonNetwork.IsMasterClient) { int num = (int)s; int segmentIndex = num - 1; Plugin.Log.LogInfo((object)$"Map segment changing to {num}. Updating structures."); SaveManager.DespawnStructuresForSegment(segmentIndex); SaveManager.SpawnStructuresForSegment(num); } } } [HarmonyPatch(typeof(PhotonNetwork), "Instantiate")] public class PhotonInstantiatePatch { private static void Postfix(string prefabName, Vector3 position, Quaternion rotation, byte group, object[]? data = null) { //IL_00a1: 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) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) string prefabName2 = prefabName; if (PhotonNetwork.IsMasterClient && !SaveManager.IsRestoring && (data == null || data.Length == 0 || !(data[0] as string == "PEAK_STRANDING_RESTORED"))) { string[] array = new string[7] { "0_Items/ClimbingSpikeHammered", "0_Items/ShelfShroomSpawn", "0_Items/BounceShroomSpawn", "Flag_planted_seagull", "Flag_planted_turtle", "PortableStovetop_Placed", "ScoutCannon_Placed" }; if (Array.Exists(array, (string p) => p == prefabName2)) { PlacedItemData placedItemData = new PlacedItemData { PrefabName = prefabName2, Position = position, Rotation = rotation }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } } [HarmonyPatch(typeof(RopeAnchorProjectile), "GetShot")] public static class RopeAnchorProjectileGetShotPatch { private static void Postfix(RopeAnchorProjectile __instance, Vector3 to, float travelTime, float ropeLength, Vector3 flyingRotation) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsMasterClient && !SaveManager.IsRestoring) { RopeAnchorWithRope component = ((Component)__instance).GetComponent<RopeAnchorWithRope>(); int num; if (component == null) { num = 0; } else { GameObject ropePrefab = component.ropePrefab; num = (((ropePrefab == null) ? null : ropePrefab.GetComponent<Rope>()?.antigrav).GetValueOrDefault() ? 1 : 0); } bool ropeAntiGrav = (byte)num != 0; PlacedItemData placedItemData = new PlacedItemData { PrefabName = "PeakStranding/RopeShooter", RopeStart = ((Component)__instance).transform.position, RopeEnd = to, RopeLength = ropeLength, RopeFlyingRotation = flyingRotation, RopeAnchorRotation = ((Component)__instance).transform.rotation, RopeAntiGrav = ropeAntiGrav }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } [HarmonyPatch(typeof(RopeAnchorWithRope), "SpawnRope")] public static class RopeAnchorWithRope_SpawnRope_Patch { private static void Postfix(RopeAnchorWithRope __instance, ref Rope __result) { if (!PhotonNetwork.IsMasterClient || (Object)(object)__instance == (Object)null) { return; } PhotonView photonView = ((MonoBehaviourPun)__instance).photonView; if (!((Object)(object)photonView == (Object)null)) { DeletableGroup deletableGroup = ((Component)__instance).GetComponent<DeletableGroup>(); if ((Object)(object)deletableGroup == (Object)null) { deletableGroup = ((Component)__instance).gameObject.AddComponent<DeletableGroup>(); } deletableGroup.Add(photonView); if ((Object)(object)__result != (Object)null && (Object)(object)((MonoBehaviourPun)__result).photonView != (Object)null) { deletableGroup.Add(((MonoBehaviourPun)__result).photonView); } PhotonView pv = default(PhotonView); if ((Object)(object)__instance.anchor != (Object)null && ((Component)__instance.anchor).TryGetComponent<PhotonView>(ref pv)) { deletableGroup.Add(pv); } } } } [HarmonyPatch(typeof(Rope), "AttachToAnchor_Rpc")] public static class RopeAttachToAnchorPatch { private static readonly ConditionalWeakTable<Rope, object> saved = new ConditionalWeakTable<Rope, object>(); private static readonly object s_token = new object(); private static void Prefix(Rope __instance, PhotonView anchorView) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017b: 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) //IL_0182: 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) if (!PhotonNetwork.IsMasterClient || SaveManager.IsRestoring || saved.TryGetValue(__instance, out object _)) { return; } object? value2 = AccessTools.Field(typeof(Rope), "spool").GetValue(__instance); RopeSpool val = (RopeSpool)((value2 is RopeSpool) ? value2 : null); RopeAnchor val2 = default(RopeAnchor); if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).GetComponent<RestoredItem>() != (Object)null) && !((Object)(object)anchorView == (Object)null) && ((Component)anchorView).TryGetComponent<RopeAnchor>(ref val2) && !((Object)(object)val2 == (Object)null)) { Vector3 position = ((Component)val2).transform.position; Quaternion rotation = ((Component)val2).transform.rotation; saved.Add(__instance, s_token); GameObject gameObject = ((Component)anchorView).gameObject; DeletableGroup deletableGroup = gameObject.GetComponent<DeletableGroup>(); if ((Object)(object)deletableGroup == (Object)null) { deletableGroup = gameObject.AddComponent<DeletableGroup>(); } deletableGroup.Add(anchorView); if ((Object)(object)__instance != (Object)null && (Object)(object)((MonoBehaviourPun)__instance).photonView != (Object)null) { deletableGroup.Add(((MonoBehaviourPun)__instance).photonView); } float ropeLength = ((val.Segments > 0.01f) ? val.Segments : Mathf.Max((float)__instance.SegmentCount, val.minSegments)); PlacedItemData placedItemData = new PlacedItemData { PrefabName = "PeakStranding/RopeSpool", Position = ((Component)val).transform.position, Rotation = ((Component)val).transform.rotation, RopeLength = ropeLength, RopeAntiGrav = (val.isAntiRope || __instance.antigrav), RopeStart = val.ropeBase.position, RopeEnd = position, RopeAnchorRotation = rotation }; placedItemData.AddCurrentRunContext(); SaveManager.SaveItem(placedItemData); } } } [HarmonyPatch(typeof(RopeBoneVisualizer), "LateUpdate")] public static class RopeBoneVisualizer_LateUpdate_Patch { private static bool Prefix(RopeBoneVisualizer __instance) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown if (PhotonNetwork.IsMasterClient && Plugin.CfgRopeOptimizerExperimental) { Rope val = (Rope)AccessTools.Field(typeof(RopeBoneVisualizer), "rope").GetValue(__instance); if ((Object)(object)val != (Object)null && val.GetData().IsSleeping) { return false; } return true; } return true; } } [HarmonyPatch(typeof(RopeSegment), "Interact")] public static class RopeSegment_Interact_Patch { private static void Prefix(RopeSegment __instance) { if ((Object)(object)__instance.rope != (Object)null && Plugin.CfgRopeOptimizerExperimental) { __instance.rope.WakeUp(); } } } public class RopeSleepManager : MonoBehaviourPunCallbacks { private static bool initialized; public static void Initialize() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!initialized && Plugin.CfgRopeOptimizerExperimental) { GameObject val = new GameObject("RopeSleepManager"); val.AddComponent<RopeSleepManager>(); Object.DontDestroyOnLoad((Object)(object)val); initialized = true; } } public override void OnPlayerEnteredRoom(Player newPlayer) { if (!PhotonNetwork.IsMasterClient || !Plugin.CfgRopeOptimizerExperimental) { return; } Plugin.Log.LogError((object)("[RopeOptimizer] Player " + newPlayer.NickName + " entered. Waking up all ropes for synchronization.")); Rope[] array = Object.FindObjectsByType<Rope>((FindObjectsSortMode)0); Rope[] array2 = array; foreach (Rope rope in array2) { if (rope.GetData().IsSleeping) { rope.WakeUp(); } } } } [HarmonyPatch(typeof(RopeSyncer), "ShouldSendData")] public static class RopeSyncer_ShouldSendData_Patch { private static bool Prefix(RopeSyncer __instance, ref bool __result) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown Rope val = (Rope)AccessTools.Field(typeof(RopeSyncer), "rope").GetValue(__instance); if ((Object)(object)val == (Object)null) { return true; } RopeData data = val.GetData(); if (!data.IsSleeping) { return true; } float unscaledTime = Time.unscaledTime; if (unscaledTime >= data.NextSleepSyncTime) { data.NextSleepSyncTime = unscaledTime + 1f; __result = true; } else { __result = false; } return false; } } [HarmonyPatch(typeof(Rope), "AttachToAnchor_Rpc")] public static class Rope_AttachToAnchor_Rpc_Patch { private static void Postfix(Rope __instance) { if (PhotonNetwork.IsMasterClient && Plugin.CfgRopeOptimizerExperimental) { RopeData data = __instance.GetData(); data.SleepCountdown = 15f; } } } [HarmonyPatch(typeof(Rope), "Awake")] public static class Rope_Awake_Patch { private static void Postfix(Rope __instance) { if (Plugin.CfgRopeOptimizerExperimental) { Rope_SleepRPCs rope_SleepRPCs = ((Component)__instance).gameObject.AddComponent<Rope_SleepRPCs>(); rope_SleepRPCs.rope = __instance; } } } public class RopeData { public bool IsSleeping; public float SleepCountdown = -1f; public bool WasBeingClimbed; public float NextSleepSyncTime; } public static class Rope_ExtendedData { private static readonly ConditionalWeakTable<Rope, RopeData> AllRopeData = new ConditionalWeakTable<Rope, RopeData>(); public const float SleepDelay = 15f; public static RopeData GetData(this Rope rope) { return AllRopeData.GetValue(rope, (Rope _) => new RopeData()); } public static void GoToSleep(this Rope rope) { RopeData data = rope.GetData(); if (!data.IsSleeping) { data.IsSleeping = true; data.SleepCountdown = -1f; data.WasBeingClimbed = false; data.NextSleepSyncTime = Time.unscaledTime + 1f; ((Component)rope).GetComponent<PhotonView>().RPC("EnterSleepState_RPC", (RpcTarget)0, Array.Empty<object>()); } } public static void WakeUp(this Rope rope) { RopeData data = rope.GetData(); if (data.IsSleeping) { data.IsSleeping = false; data.SleepCountdown = 15f; data.WasBeingClimbed = false; data.NextSleepSyncTime = 0f; ((Component)rope).GetComponent<PhotonView>().RPC("ExitSleepState_RPC", (RpcTarget)0, Array.Empty<object>()); } } public static void UpdateSleepLogic(Rope rope) { RopeData data = rope.GetData(); if (data.IsSleeping) { return; } bool flag = rope.charactersClimbing.Count > 0; if (data.WasBeingClimbed && !flag) { data.SleepCountdown = 15f; } data.WasBeingClimbed = flag; if (data.SleepCountdown > 0f && !flag) { data.SleepCountdown -= Time.deltaTime; if (data.SleepCountdown <= 0f) { rope.GoToSleep(); data.SleepCountdown = -1f; } } } } [HarmonyPatch(typeof(Rope), "FixedUpdate")] public static class Rope_FixedUpdate_Patch { private static bool Prefix(Rope __instance) { RopeData data = __instance.GetData(); return !data.IsSleeping; } } public class Rope_SleepRPCs : MonoBehaviourPun { public Rope rope; [PunRPC] private void EnterSleepState_RPC() { if (!Plugin.CfgRopeOptimizerExperimental) { return; } RopeData data = rope.GetData(); data.IsSleeping = true; data.SleepCountdown = -1f; data.WasBeingClimbed = false; List<Transform> list = (List<Transform>)AccessTools.Field(typeof(Rope), "simulationSegments").GetValue(rope); foreach (Transform item in list) { Rigidbody component = ((Component)item).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.isKinematic = true; } } Debug.Log((object)$"Rope {((MonoBehaviourPun)rope).photonView.ViewID} is now sleeping."); } [PunRPC] private void ExitSleepState_RPC() { if (!Plugin.CfgRopeOptimizerExperimental) { return; } RopeData data = rope.GetData(); data.IsSleeping = false; data.SleepCountdown = 15f; data.WasBeingClimbed = false; List<Transform> list = (List<Transform>)AccessTools.Field(typeof(Rope), "simulationSegments").GetValue(rope); foreach (Transform item in list) { Rigidbody component = ((Component)item).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.isKinematic = false; component.WakeUp(); } } Debug.Log((object)$"Rope {((MonoBehaviourPun)rope).photonView.ViewID} has woken up."); } } [HarmonyPatch(typeof(Rope), "Update")] public static class Rope_Update_Patch { private static void Postfix(Rope __instance) { if (PhotonNetwork.IsMasterClient && Plugin.CfgRopeOptimizerExperimental) { Rope_ExtendedData.UpdateSleepLogic(__instance); } } } [HarmonyPatch(typeof(RunManager), "Start")] public static class RunManager_Start_Patch { private static void Postfix() { if (Plugin.CfgRopeOptimizerExperimental) { Plugin.Log.LogInfo((object)"Experimental Rope Optimizer enabled! Enjoy the performance boost. Looking forward to your feedback!"); RopeSleepManager.Initialize(); } } } [HarmonyPatch(typeof(RunManager), "StartRun")] public class RunManagerStartRunPatch { [CompilerGenerated] private sealed class <>c__DisplayClass2_0 { public Task<GlobalStatsDto> globalTask; public Task<UserStatsDto> userTask; internal bool <FetchAndLogStats>b__0() { if (globalTask.IsCompleted) { return userTask.IsCompleted; } return false; } } [CompilerGenerated] private sealed class <FetchAndLogStats>d__2 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private <>c__DisplayClass2_0 <>8__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FetchAndLogStats>d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //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_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass2_0(); <>8__1.globalTask = RemoteApi.FetchGlobalStatsAsync(); <>8__1.userTask = RemoteApi.FetchUserStatsAsync(); <>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.globalTask.IsCompleted && <>8__1.userTask.IsCompleted)); <>1__state = 1; return true; case 1: { <>1__state = -1; string text = "PeakStranding Stats:\n\n"; Color color = Color.green; if (<>8__1.userTask.Status == TaskStatus.RanToCompletion && <>8__1.userTask.Result != null) { UserStatsDto result = <>8__1.userTask.Result; Plugin.Log.LogInfo((object)$"Your stats: {result.TotalStructuresUploaded} structures uploaded (last 24h: {result.StructuresUploadedLast24H}), {result.TotalLikesReceived} likes received, {result.TotalLikesSent} likes sent."); text = text + $"You:\nitems uploaded total: {result.TotalStructuresUploaded}\nitems uploaded last day: {result.StructuresUploadedLast24H}\n" + $"likes received: {result.TotalLikesReceived}\nlikes sent: {result.TotalLikesSent}\n"; } else if (<>8__1.userTask.IsFaulted) { string text2 = "Failed to fetch user stats: " + DescribeTaskFailure(<>8__1.userTask); Plugin.Log.LogWarning((object)text2); } else if (<>8__1.userTask.IsCanceled) { string text3 = "Failed to fetch user stats: request was cancelled."; Plugin.Log.LogWarning((object)text3); } if (<>8__1.globalTask.Status == TaskStatus.RanToCompletion && <>8__1.globalTask.Result != null) { GlobalStatsDto result2 = <>8__1.globalTask.Result; Plugin.Log.LogInfo((object)$"Global stats: {result2.TotalUniquePlayersAllTime} unique players all-time, {result2.TotalStructuresUploadedAllTime} structures uploaded (last 24h: {result2.TotalStructuresUploadedLast24H} from {result2.TotalUniquePlayersLast24H} players), {result2.TotalLikesGivenAllTime} likes given. Server version {result2.ServerVersion}."); text = text + $"\nGlobal:\ntotal items uploaded: {result2.TotalStructuresUploadedAllTime}\nitems uploaded last day: {result2.TotalStructuresUploadedLast24H}\n" + $"total players: {result2.TotalUniquePlayersAllTime}\nplayers last day: {result2.TotalUniquePlayersLast24H}\ntotal likes given: {result2.TotalLikesGivenAllTime}\nserver version: {result2.ServerVersion}"; } else if (<>8__1.globalTask.IsFaulted) { string text4 = "Failed to fetch global stats: " + DescribeTaskFailure(<>8__1.globalTask); Plugin.Log.LogWarning((object)text4); color = Color.red; text = text + text4 + "\n"; } else if (<>8__1.globalTask.IsCanceled) { string text5 = "Failed to fetch global stats: request was cancelled."; Plugin.Log.LogWarning((object)text5); color = Color.red; text = text + text5 + "\n"; } ToastController.Instance.Toast(text, color, 15f, 4f); 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 <FetchCacheAndSpawnInitial>d__1 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public int mapId; private Task<List<ServerStructureDto>> <task>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FetchCacheAndSpawnInitial>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <task>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <task>5__2 = RemoteApi.FetchStructuresAsync(mapId); break; case 1: <>1__state = -1; break; } if (!<task>5__2.IsCompleted) { <>2__current = null; <>1__state = 1; return true; } if (<task>5__2.IsFaulted) { Plugin.Log.LogError((object)$"Failed to fetch remote structures: {<task>5__2.Exception}"); ToastController.Instance.Toast($"PeakStranding: failed to fetch online items!\n{<task>5__2.Exception}", Color.red, 5f, 3f); } else { SaveManager.CacheRemoteStructures(<task>5__2.Result); } Plugin.Log.LogInfo((object)"Initial caching complete. Spawning structures for segment 0."); SaveManager.SpawnStructuresForSegment(0); 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 static void Postfix(RunManager __instance) { PeakStrandingSyncManager peakStrandingSyncManager = ((Component)__instance).GetComponent<PeakStrandingSyncManager>(); if ((Object)(object)peakStrandingSyncManager == (Object)null) { peakStrandingSyncManager = ((Component)__instance).gameObject.AddComponent<PeakStrandingSyncManager>(); } peakStrandingSyncManager.ResetRunLikes(); if (!PhotonNetwork.IsMasterClient) { Plugin.Log.LogInfo((object)"New run started as a CLIENT, structures will be synced by the host."); return; } Plugin.Log.LogInfo((object)"New run started as a HOST. Caching structures."); SaveManager.ClearCache(); if (Plugin.CfgLocalLoadStructures) { Plugin.Log.LogInfo((object)"Caching local structures from save."); SaveManager.CacheLocalStructures(); } else { Plugin.Log.LogInfo((object)"Caching local structures is disabled, skipping."); } if (Plugin.CfgRemoteLoadStructures && DataHelper.GetCurrentSceneName() != "Airport") { Plugin.Log.LogInfo((object)"Fetching and caching remote structures from server."); ((MonoBehaviour)__instance).StartCoroutine(FetchCacheAndSpawnInitial(DataHelper.GetCurrentLevelIndex())); } else { Plugin.Log.LogInfo((object)"Remote structures disabled or in Airport. Spawning initial local structures."); ((MonoBehaviour)__instance).StartCoroutine(FetchAndLogStats()); SaveManager.SpawnStructuresForSegment(0); } } [IteratorStateMachine(typeof(<FetchCacheAndSpawnInitial>d__1))] private static IEnumerator FetchCacheAndSpawnInitial(int mapId) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FetchCacheAndSpawnInitial>d__1(0) { mapId = mapId }; } [IteratorStateMachine(typeof(<FetchAndLogStats>d__2))] private static IEnumerator FetchAndLogStats() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FetchAndLogStats>d__2(0); } private static string DescribeTaskFailure(Task task) { return task.Exception?.GetBaseException().Message ?? "Unknown error"; } } } namespace PeakStranding.Online { internal class ApiException : HttpRequestException { public new HttpStatusCode StatusCode { get; } public ApiException(HttpStatusCode statusCode) : base($"Request failed with status code {statusCode}") { StatusCode = statusCode; } } internal static class RemoteApi { private static string _cachedSteamAuthTicket = string.Empty; private static readonly HttpClient http = new HttpClient { Timeout = TimeSpan.FromSeconds(10.0) }; private static readonly string DefaultBaseUrl = "https://peakstranding.burning.homes/api/v1"; internal static string StructuresUrl => GetBaseUrl() + "/structures"; internal static string GlobalStatsUrl => GetBaseUrl() + "/stats/global"; internal static string UserStatsUrl => GetBaseUrl() + "/stats/me"; internal static string GetBaseUrl() { if (!string.IsNullOrEmpty(Plugin.CfgRemoteApiUrl)) { return Plugin.CfgRemoteApiUrl.TrimEnd('/'); } return DefaultBaseUrl; } internal static string StructureUrl(ulong id) { return $"{GetBaseUrl()}/structures/{id}"; } private static string GetAuthTicket(bool forceRefresh = false) { if (forceRefresh || string.IsNullOrEmpty(_cachedSteamAuthTicket)) { _cachedSteamAuthTicket = SteamAuthTicketService.GetSteamAuthTicket().Item1; } return _cachedSteamAuthTicket; } private static void InvalidateAuthTicket() { _cachedSteamAuthTicket = string.Empty; } public static void Upload(int mapId, PlacedItemData item) { PlacedItemData item2 = item; Task.Run(async delegate { try { await ExecuteWithAuthRetry(async delegate(string authTicket) { string content = JsonConvert.SerializeObject((object)item2.ToServerDto(SteamUser.GetSteamID().m_SteamID, SteamFriends.GetPersonaName(), mapId)); Plugin.Log.LogInfo((object)"Uploading item to remote"); using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, StructuresUrl) { Content = new StringContent(content, Encoding.UTF8, "application/json") }; req.Headers.Add("X-Steam-Auth", authTicket); HttpResponseMessage httpResponseMessage = await http.SendAsync(req).ConfigureAwait(continueOnCapturedContext: false); if (!httpResponseMessage.IsSuccessStatusCode) { throw new ApiException(httpResponseMessage.StatusCode); } return true; }); } catch (Exception ex) { Plugin.Log.LogInfo((object)("Remote upload failed: " + ex.Message)); } return Task.CompletedTask; }); } public static async Task<List<ServerStructureDto>> FetchStructuresAsync(int mapId) { return await ExecuteWithAuthRetry(async delegate(string authTicket) { string text = Uri.EscapeDataString(DataHelper.GetCurrentSceneName()); StringBuilder stringBuilder = new StringBuilder($"{StructuresUrl}?scene={text}&map_id={mapId}&limit={Plugin.CfgRemoteStructuresLimit}"); List<string> excludedPrefabs = DataHelper.GetExcludedPrefabs(); if (excludedPrefabs.Count > 0) { string text2 = Uri.EscapeDataString(string.Join(",", excludedPrefabs)); stringBuilder.Append("&exclude_prefabs=" + text2); } string text3 = stringBuilder.ToString(); Plugin.Log.LogInfo((object)("Fetching structures from remote: " + text3)); using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, text3); req.Headers.Add("X-Steam-Auth", authTicket); using HttpResponseMessage resp = await http.SendAsync(req).ConfigureAwait(continueOnCapturedContext: false); if (!resp.IsSuccessStatusCode) { throw new ApiException(resp.StatusCode); } List<ServerStructureDto> list = JsonConvert.DeserializeObject<List<ServerStructureDto>>(await resp.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false)) ?? new List<ServerStructureDto>(); HashSet<ulong> hashSet = new HashSet<ulong>(); foreach (ServerStructureDto item in list) { hashSet.Add(item.user_id); } Plugin.Log.LogInfo((object)$"Received {list.Count} online structures from {hashSet.Count} users for map_id {mapId}"); return list; }); } public static async Task<GlobalStatsDto> FetchGlobalStatsAsync() { return await ExecuteWithAuthRetry(async delegate(string authTicket) { Plugin.Log.LogInfo((object)"Fetching global stats from remote"); using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, GlobalStatsUrl); req.Headers.Add("X-Steam-Auth", authTicket); using HttpResponseMessage resp = await http.SendAsync(req).ConfigureAwait(continueOnCapturedContext: false); if (!resp.IsSuccessStatusCode) { throw new ApiException(resp.StatusCode); } GlobalStatsDto globalStatsDto = JsonConvert.DeserializeObject<GlobalStatsDto>(await resp.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false)); if (globalStatsDto == null) { throw new InvalidOperationException("Failed to deserialize global stats response."); } return globalStatsDto; }); } public static async Task<UserStatsDto> FetchUserStatsAsync() { return await ExecuteWithAuthRetry(async delegate(string authTicket) { Plugin.Log.LogInfo((object)"Fetching user stats from remote"); using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, UserStatsUrl); req.Headers.Add("X-Steam-Auth", authTicket); using HttpResponseMessage resp = await http.SendAsync(req).ConfigureAwait(continueOnCapturedContext: false); if (!resp.IsSuccessStatusCode) { throw new ApiException(resp.StatusCode); } UserStatsDto userStatsDto = JsonConvert.DeserializeObject<UserStatsDto>(await resp.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false)); if (userStatsDto == null) { throw new InvalidOperationException("Failed to deserialize user stats response."); } return userStatsDto; }); } public static async Task<bool> LikeStructureAsync(ulong id) { return await LikeStructureAsync(id, 1).ConfigureAwait(continueOnCapturedContext: false); } public static async Task<bool> LikeStructureAsync(ulong id, int count) { if (count <= 0) { return true; } return await ExecuteWithAuthRetry(async delegate(string authTicket) { string requestUri = StructureUrl(id) + "/like"; string content = JsonConvert.SerializeObject((object)new { count }); using HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, requestUri) { Content = new StringContent(content, Encoding.UTF8, "application/json") }; req.Headers.Add("X-Steam-Auth", authTicket); using HttpResponseMessage httpResponseMessage = await http.SendAsync(req).ConfigureAwait(continueOnCapturedContext: false); if (!httpResponseMessage.IsSuccessStatusCode) { throw new ApiException(httpResponseMessage.StatusCode); } return true; }); } private static async Task<T> ExecuteWithAuthRetry<T>(Func<string, Task<T>> action, int maxRetries = 1) { int attempt = 0; bool shouldRetry; Exception ex2; do { shouldRetry = false; try { string authTicket = GetAuthTicket(attempt > 0); return await action(authTicket).ConfigureAwait(continueOnCapturedContext: false); } catch (ApiException ex) { ex2 = ex; if (ex.StatusCode == HttpStatusCode.TooManyRequests) { Plugin.Log.LogWarning((object)"Request failed due to rate limiting. No retry will be attempted."); shouldRetry = false; } else if (attempt < maxRetries) { Plugin.Log.LogInfo((object)$"Request failed with HTTP status {ex.StatusCode}, refreshing auth ticket and retrying..."); InvalidateAuthTicket(); shouldRetry = true; attempt++; } } catch (HttpRequestException ex3) { ex2 = ex3; if (attempt < maxRetries) { Plugin.Log.LogInfo((object)("Request failed with " + ex3.Message + ", refreshing auth ticket and retrying...")); InvalidateAuthTicket(); shouldRetry = true; attempt++; } } catch (Exception ex4) { ex2 = ex4; if (attempt < maxRetries) { shouldRetry = true; attempt++; } } } while (shouldRetry); Plugin.Log.LogInfo((object)$"Request failed after {attempt} attempts: {ex2?.Message}"); if (ex2 != null) { throw ex2; } return default(T); } } internal class GlobalStatsDto { [JsonProperty("total_unique_players_all_time")] public long TotalUniquePlayersAllTime { get; set; } [JsonProperty("total_structures_uploaded_all_time")] public long TotalStructuresUploadedAllTime { get; set; } [JsonProperty("total_likes_given_all_time")] public long TotalLikesGivenAllTime { get; set; } [JsonProperty("total_unique_players_last_24h")] public long TotalUniquePlayersLast24H { get; set; } [JsonProperty("total_structures_uploaded_last_24h")] public long TotalStructuresUploadedLast24H { get; set; } [JsonProperty("server_version")] public string ServerVersion { get; set; } = string.Empty; } internal class UserStatsDto { [JsonProperty("total_structures_uploaded")] public long TotalStructuresUploaded { get; set; } [JsonProperty("structures_uploaded_last_24h")] public long StructuresUploadedLast24H { get; set; } [JsonProperty("total_likes_received")] public long TotalLikesReceived { get; set; } [JsonProperty("total_likes_sent")] public long TotalLikesSent { get; set; } } public class LikeBuffer : MonoBehaviour { private struct Entry { public int Count; public float LastLikeAt; } private static LikeBuffer? _instance; private readonly Dictionary<ulong, Entry> _buffer = new Dictionary<ulong, Entry>(); private readonly Queue<(ulong id, int count)> _readyToSend = new Queue<(ulong, int)>(); private float _lastSentAt = -999f; private const float InactivitySeconds = 2f; private const float GlobalCooldown = 2f; private static readonly List<ulong> s_tempIds = new List<ulong>(16); public static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("PeakStranding_LikeBuffer"); _instance = val.AddComponent<LikeBuffer>(); Object.DontDestroyOnLoad((Object)(object)val); } } public static void Enqueue(ulong structureId) { Ensure(); _instance.EnqueueInternal(structureId); } private void EnqueueInternal(ulong id) { if (_buffer.TryGetValue(id, out var value)) { value.Count++; value.LastLikeAt = Time.realtimeSinceStartup; _buffer[id] = value; } else { _buffer[id] = new Entry { Count = 1, LastLikeAt = Time.realtimeSinceStartup }; } } private void Update() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (_buffer.Count > 0) { s_tempIds.Clear(); foreach (KeyValuePair<ulong, Entry> item3 in _buffer) { if (realtimeSinceStartup - item3.Value.LastLikeAt >= 2f) { s_tempIds.Add(item3.Key); } } foreach (ulong s_tempId in s_tempIds) { Entry entry = _buffer[s_tempId]; _buffer.Remove(s_tempId); if (entry.Count > 0) { _readyToSend.Enqueue((s_tempId, entry.Count)); } } } if (_readyToSend.Count > 0 && realtimeSinceStartup - _lastSentAt >= 2f) { (ulong id, int count) tuple = _readyToSend.Dequeue(); ulong item = tuple.id; int item2 = tuple.count; _lastSentAt = realtimeSinceStartup; SendAsync(item, item2); } } private async Task SendAsync(ulong id, int count) { try { await RemoteApi.LikeStructureAsync(id, count).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception ex) { Plugin.Log.LogInfo((object)$"Batched like request failed for {id} x{count}: {ex.Message}"); } } } } namespace PeakStranding.Data { public static class DataHelper { public static BiDictionary prefabMapping = new BiDictionary { { "0_Items/BounceShroomSpawn", "bounceshroom" }, { "0_Items/ClimbingSpikeHammered", "piton" }, { "0_Items/ShelfShroomSpawn", "shelfshroom" }, { "Flag_planted_seagull", "flagseagull" }, { "Flag_planted_turtle", "flagturtle" }, { "PeakStranding/JungleVine", "chainshooter" }, { "PeakStranding/MagicBeanVine", "magicbean" }, { "PeakStranding/RopeShooter", "ropeshooter" }, { "PeakStranding/RopeSpool", "ropespool" }, { "PortableStovetop_Placed", "stove" }, { "ScoutCannon_Placed", "scoutcannon" } }; public static string GetCurrentSceneName() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name; } public static int GetCurrentMapSegment() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected I4, but got Unknown if ((Object)(object)Singleton<MapHandler>.Instance == (Object)null) { return -1; } return (int)Singleton<MapHandler>.Instance.GetCurrentSegment(); } public static int GetCurrentLevelIndex() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return GameHandler.GetService<NextLevelService>().Data.Value.CurrentLevelIndex; } public static bool IsPrefabAllowed(string prefabName) { if (string.IsNullOrWhiteSpace(prefabName)) { return false; } prefabMapping.TryGetByFirst(prefabName, out string second); if (string.IsNullOrWhiteSpace(second)) { return false; } if (string.IsNullOrWhiteSpace(Plugin.CfgStructureAllowList)) { return true; } return Plugin.CfgStructureAllowList.ToLower().Contains(second.ToLower()); } public static List<string> GetExcludedPrefabs() { List<string> list = new List<string>(); if (string.IsNullOrWhiteSpace(Plugin.CfgStructureAllowList)) { return list; } HashSet<string> hashSet = new HashSet<string>(Plugin.CfgStructureAllowList.ToLower().Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)); foreach (KeyValuePair<string, string> item in prefabMapping) { string key = item.Key; string value = item.Value; if (!hashSet.Contains(value.ToLower())) { list.Add(key); } } return list; } } [Serializable] public class PlacedItemData { public string PrefabName = string.Empty; public Vector3 Position; public Quaternion Rotation; public Vector3 RopeStart; public Vector3 RopeEnd; public float RopeLength; public Vector3 RopeFlyingRotation; public Quaternion RopeAnchorRotation; public bool RopeAntiGrav; public string Scene = string.Empty; public int MapSegment; public void AddCurrentRunContext() { Scene = DataHelper.GetCurrentSceneName(); MapSegment = DataHelper.GetCurrentMapSegment(); } } public class RestoredItem : MonoBehaviour { } public class RestoredItemCredits : MonoBehaviour { private Camera _mainCam; public string displayText = ""; private const float kDistanceSqr = 100f; private const int kLazyInterval = 30; private bool _isNear; private int _nextCheckFrame; private void Awake() { _mainCam = Camera.main; if ((Object)(object)_mainCam == (Object)null) { Plugin.Log.LogError((object)"Main camera not found."); } _nextCheckFrame = 30; } private void Update() { //IL_003d: 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) if ((Object)(object)_mainCam == (Object)null || string.IsNullOrEmpty(displayText) || (!_isNear && Time.frameCount < _nextCheckFrame)) { return; } Vector3 val = ((Component)_mainCam).transform.position - ((Component)this).transform.position; bool flag = ((Vector3)(ref val)).sqrMagnitude <= 100f; if (_isNear != flag) { _isNear = flag; if (!_isNear) { _nextCheckFrame = Time.frameCount + 30; } } else if (!_isNear) { _nextCheckFrame = Time.frameCount + 30; } } private void OnGUI() { //IL_0030: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if (_isNear && !((Object)(object)_mainCam == (Object)null) && !string.IsNullOrEmpty(displayText)) { Vector3 val = _mainCam.WorldToScreenPoint(((Component)this).transform.position); if (!(val.z < 0f)) { val.y = (float)Screen.height - val.y; GUIContent val2 = new GUIContent(displayText); GUIStyle label = GUI.skin.label; label.fontSize = 18; label.alignment = (TextAnchor)4; label.wordWrap = true; label.normal.textColor = Color.white; float num = 200f; float num2 = label.CalcHeight(val2, num); float num3 = 2f; Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(val.x - num * 0.5f, val.y - num2 * 0.5f - num3, num, num2 + num3 * 2f); GUI.color = new Color(0f, 0f, 0f, 0.15f); GUI.DrawTexture(val3, (Texture)(object)Texture2D.whiteTexture); GUI.color = Color.white; GUI.Label(val3, val2, label); } } } } [Serializable] public class ServerStructureDto { public ulong id; public ulong user_id; public string username = string.Empty; public int map_id; public string scene = string.Empty; public int segment; public string prefab = string.Empty; public float pos_x; public float pos_y; public float pos_z; public float rot_x; public float rot_y; public float rot_z; public float rot_w; public float rope_start_x; public float rope_start_y; public float rope_start_z; public float rope_end_x; public float rope_end_y; public float rope_end_z; public float rope_length; public float rope_flying_rotation_x; public float rope_flying_rotation_y; public float rope_flying_rotation_z; public float rope_anchor_rotation_x; public float rope_anchor_rotation_y; public float rope_anchor_rotation_z; public float rope_anchor_rotation_w; public bool antigrav; public int likes; } public static class ServerStructureConverters { public static ServerStructureDto ToServerDto(this PlacedItemData item, ulong userSteamId, string username, int mapId) { return new ServerStructureDto { user_id = userSteamId, username = username, map_id = mapId, scene = item.Scene, segment = item.MapSegment, prefab = item.PrefabName, pos_x = item.Position.x, pos_y = item.Position.y, pos_z = item.Position.z, rot_x = item.Rotation.x, rot_y = item.Rotation.y, rot_z = item.Rotation.z, rot_w = item.Rotation.w, rope_start_x = item.RopeStart.x, rope_start_y = item.RopeStart.y, rope_start_z = item.RopeStart.z, rope_end_x = item.RopeEnd.x, rope_end_y = item.RopeEnd.y, rope_end_z = item.RopeEnd.z, rope_length = item.RopeLength, rope_flying_rotation_x = item.RopeFlyingRotation.x, rope_flying_rotation_y = item.RopeFlyingRotation.y, rope_flying_rotation_z = item.RopeFlyingRotation.z, rope_anchor_rotation_x = item.RopeAnchorRotation.x, rope_anchor_rotation_y = item.RopeAnchorRotation.y, rope_anchor_rotation_z = item.RopeAnchorRotation.z, rope_anchor_rotation_w = item.RopeAnchorRotation.w, antigrav = item.RopeAntiGrav }; } public static PlacedItemData ToPlacedItemData(this ServerStructureDto s) { //IL_0024: 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) //IL_0047: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) return new PlacedItemData { PrefabName = s.prefab, Position = new Vector3(s.pos_x, s.pos_y, s.pos_z), Rotation = new Quaternion(s.rot_x, s.rot_y, s.rot_z, s.rot_w), RopeStart = new Vector3(s.rope_start_x, s.rope_start_y, s.rope_start_z), RopeEnd = new Vector3(s.rope_end_x, s.rope_end_y, s.rope_end_z), RopeLength = s.rope_length, RopeFlyingRotation = new Vector3(s.rope_flying_rotation_x, s.rope_flying_rotation_y, s.rope_flying_rotation_z), RopeAnchorRotation = new Quaternion(s.rope_anchor_rotation_x, s.rope_anchor_rotation_y, s.rope_anchor_rotation_z, s.rope_anchor_rotation_w), RopeAntiGrav = s.antigrav, Scene = s.scene, MapSegment = s.segment }; } public static List<PlacedItemData> ToPlacedItemList(this IEnumerable<ServerStructureDto> rows) { return rows.Select((ServerStructureDto dto) => dto.ToPlacedItemData()).ToList(); } } [Serializable] public class StructureSyncData { public int ViewID { get; set; } public string? Username { get; set; } public int Likes { get; set; } public ulong ServerId { get; set; } public ulong UserId { get; set; } public bool LikeEnabled { get; set; } } } namespace PeakStranding.Components { public class DeletableGroup : MonoBehaviourPun { [SerializeField] private List<PhotonView> _pvs = new List<PhotonView>(); [SerializeField] private List<GameObject> _gos = new List<GameObject>(); public void Add(PhotonView pv) { if (!((Object)(object)pv == (Object)null) && !_pvs.Contains(pv)) { _pvs.Add(pv); } } public void Add(GameObject go) { if (!((Object)(object)go == (Object)null) && !_gos.Contains(go)) { _gos.Add(go); } } [PunRPC] public void PS_Delete() { for (int num = _pvs.Count - 1; num >= 0; num--) { PhotonView val = _pvs[num]; if ((Object)(object)val == (Object)null) { _pvs.RemoveAt(num); } else if ((Object)(object)val != (Object)null) { PhotonNetwork.Destroy(val); } } for (int num2 = _gos.Count - 1; num2 >= 0; num2--) { GameObject val2 = _gos[num2]; if ((Object)(object)val2 == (Object)null) { _gos.RemoveAt(num2); } else { Object.Destroy((Object)(object)val2); } } } } public static class DeletionUtility { private static GameObject? TryGetRopeAnchorObject(Rope rope) { try { FieldInfo field = typeof(Rope).GetField("attachedToAnchor", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { return null; } object? value = field.GetValue(rope); RopeAnchor val = (RopeAnchor)((value is RopeAnchor) ? value : null); return ((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null; } catch { return null; } } public static void Delete(GameObject go) { if ((Object)(object)go == (Object)null) { return; } if (((Object)go).name.Contains("ChainShootable")) { Plugin.Log.LogInfo((object)"We are NOT deleting the Chain. Like NO. Main game bugs."); return; } DeletableGroup componentInParent = go.GetComponentInParent<DeletableGroup>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)((MonoBehaviourPun)componentInParent).photonView != (Object)null) { if (PhotonNetwork.IsMasterClient) { ((MonoBehaviourPun)componentInParent).photonView.RPC("PS_Delete", (RpcTarget)3, Array.Empty<object>()); } else { Plugin.Log.LogInfo((object)"Remove requested by non-host; only host can remove globally."); } return; } if (PhotonNetwork.IsMasterClient) { RopeAnchorWithRope componentInChildren = go.GetComponentInChildren<RopeAnchorWithRope>(); if ((Object)(object)componentInChildren != (Object)null) { if ((Object)(object)componentInChildren.rope != (Object)null && (Object)(object)((MonoBehaviourPun)componentInChildren.rope).photonView != (Object)null) { PhotonNetwork.Destroy(((MonoBehaviourPun)componentInChildren.rope).photonView); } PhotonView component = ((Component)componentInChildren).GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null) { PhotonNetwork.Destroy(component); } return; } RopeAnchor componentInChildren2 = go.GetComponentInChildren<RopeAnchor>(); if ((Object)(object)componentInChildren2 != (Object)null) { Rope val = FindRopeForAnchor(componentInChildren2); if ((Object)(object)val != (Object)null && (Object)(object)((MonoBehaviourPun)val).photonView != (Object)null) { PhotonNetwork.Destroy(((MonoBehaviourPun)val).photonView); } PhotonView val2 = default(PhotonView); if (((Component)componentInChildren2).TryGetComponent<PhotonView>(ref val2)) { PhotonNetwork.Destroy(val2); } return; } Rope componentInChildren3 = go.GetComponentInChildren<Rope>(); if ((Object)(object)componentInChildren3 != (Object)null) { GameObject val3 = TryGetRopeAnchorObject(componentInChildren3); PhotonView val4 = default(PhotonView); if ((Object)(object)val3 != (Object)null && val3.TryGetComponent<PhotonView>(ref val4)) { PhotonNetwork.Destroy(val4); } if ((Object)(object)((MonoBehaviourPun)componentInChildren3).photonView != (Object)null) { PhotonNetwork.Destroy(((MonoBehaviourPun)component