The BepInEx console will not appear when launching like it does for other games on Thunderstore (you can turn it back on in your BepInEx.cfg file). If your PEAK crashes on startup, add -dx12 to your launch parameters.
Decompiled source of PeakStranding v0.9.0
plugins/com.github.wafflecomposite.PeakStranding.dll
Decompiled 32 minutes 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 Photon.Pun; using Photon.Realtime; using Steamworks; using UnityEngine; using UnityEngine.SceneManagement; 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.0.0")] [assembly: AssemblyInformationalVersion("0.9.0+9819bb06b56722c9c8ebcfd5fd62ba6dedefb9a6")] [assembly: AssemblyProduct("com.github.wafflecomposite.PeakStranding")] [assembly: AssemblyTitle("PeakStranding")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.0.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.0")] 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> showStructureCreditsConfig; internal static ConfigEntry<bool> ropeOptimizerExperimentalConfig; internal static ConfigEntry<string> structureAllowListConfig; internal static ConfigEntry<bool> allowClientsLikeConfig; internal static ConfigEntry<bool> allowClientsDeleteConfig; 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 CfgShowStructureCredits => showStructureCreditsConfig.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 string Name => "PeakStranding"; public static string Version => "0.9.0"; private void Awake() { //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Expected O, but got Unknown 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"); showStructureCreditsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Show_Structure_Credits", true, "Whether to show usernames for structures placed by other players 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."); 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!")); 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) { if (!PhotonNetwork.IsMasterClient) { return; } if (items == null || items.Count == 0) { Plugin.Log.LogInfo((object)"No remote structures to cache."); 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)); } } 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.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 = 10f; } } } [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 = 10f; 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 = 10f; 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 = 10f; } 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 = 10f; 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 <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() { 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}"); } 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."); 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 }; } } } 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 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<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); } } 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)componentInChildren3).photonView); } return; } } PhotonView component2 = go.GetComponent<PhotonView>(); if (PhotonNetwork.IsMasterClient) { if ((Object)(object)component2 != (Object)null) { PhotonNetwork.Destroy(component2); } else { Object.Destroy((Object)(object)go); } } else { Plugin.Log.LogInfo((object)"Remove requested by non-host; only host can remove globally."); } } private static Rope? FindRopeForAnchor(RopeAnchor anchor) { if ((Object)(object)anchor == (Object)null) { return null; } try { Rope[] array = Object.FindObjectsByType<Rope>((FindObjectsSortMode)0); Rope[] array2 = array; foreach (Rope val in array2) { GameObject val2 = TryGetRopeAnchorObject(val); if (!((Object)(object)val2 == (Object)null)) { if ((Object)(object)val2 == (Object)(object)((Component)anchor).gameObject) { return val; } RopeAnchor component = val2.GetComponent<RopeAnchor>(); if ((Object)(object)component == (Object)(object)anchor) { return val; } } } } catch { } return null; } } public class MagicBeanLink : MonoBehaviour { public MagicBeanVine? vine; public bool isRestoredBean; private void OnDestroy() { if (isRestoredBean && (Object)(object)vine != (Object)null) { Object.Destroy((Object)(object)((Component)vine).gameObject); vine = null; } } } public class OverlayManager : MonoBehaviour { public struct RegisterInfo { public GameObject target; public string username; public int likes; public ulong id; public ulong user_id; public bool canLike; } public class Entry { public Transform t; public string username = string.Empty; public int likes; public ulong id; public ulong user_id; public bool canLike = true; public GameObject go; public List<Floater> floaters = new List<Floater>(); public float likeTickT; public float removeS; public bool removing; } public struct Floater { public float t; public float duration; public float xJitter; public float scale; } private static OverlayManager? _instance; public const int MaxOverlays = 10; public const float MaxDistance = 10f; private const float MaxDistanceSqr = 100f; private const int ThrottleFrames = 10; public static bool DebugShowAll = false; private readonly List<Entry> _entries = new List<Entry>(); private readonly List<Entry> _visible = new List<Entry>(); private Camera _cam; private int _nextCullFrame; private GUIStyle _labelStyle; private Texture2D _bgTex = Texture2D.whiteTexture; public static float UiScale = 1.2f; public static int MaxNameChars = 20; public static KeyCode LikeKey = (KeyCode)108; public static KeyCode RemoveKey = (KeyCode)127; public static float RemoveHoldSeconds = 0.6f; public static bool ClientsCanLike = true; public static bool ClientsCanDelete = true; private Entry? _focused; private float _removeHeldTime; private Entry? _lastFocused; public static OverlayManager Instance { get { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("PeakStranding_OverlayManager"); _instance = val.AddComponent<OverlayManager>(); Object.DontDestroyOnLoad((Object)(object)val); } return _instance; } } 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; } } private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } _instance = this; _cam = Camera.main; _bgTex = Texture2D.whiteTexture; } private void EnsureGui() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown if (_labelStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = Mathf.RoundToInt(14f * UiScale), alignment = (TextAnchor)4, wordWrap = false }; val.normal.textColor = Color.white; _labelStyle = val; } } public static void Register(RegisterInfo info) { if ((Object)(object)info.target == (Object)null) { return; } OverlayManager instance = Instance; DeletableGroup componentInParent = info.target.GetComponentInParent<DeletableGroup>(); if ((Object)(object)componentInParent != (Object)null) { GameObject root2 = ((Component)componentInParent).gameObject; if (!instance._entries.Any((Entry e) => (Object)(object)e.go == (Object)(object)root2)) { instance._entries.Add(new Entry { go = root2, t = root2.transform, username = (info.username ?? ""), likes = Mathf.Max(0, info.likes), id = info.id, user_id = info.user_id, canLike = info.canLike }); } return; } Rope component = info.target.GetComponent<Rope>(); if ((Object)(object)component != (Object)null) { GameObject val = TryGetRopeAnchorObject(component); if ((Object)(object)val != (Object)null) { DeletableGroup component2 = val.GetComponent<DeletableGroup>(); if ((Object)(object)component2 != (Object)null) { GameObject root = ((Component)component2).gameObject; if (!instance._entries.Any((Entry e) => (Object)(object)e.go == (Object)(object)root)) { instance._entries.Add(new Entry { go = root, t = root.transform, username = (info.username ?? ""), likes = Mathf.Max(0, info.likes), id = info.id, user_id = info.user_id, canLike = info.canLike }); } return; } } } if (!instance._entries.Any((Entry e) => (Object)(object)e.go == (Object)(object)info.target)) { instance._entries.Add(new Entry { go = info.target, t = info.target.transform, username = (info.username ?? ""), likes = Mathf.Max(0, info.likes), id = info.id, user_id = info.user_id, canLike = info.canLike }); } } public static void Unregister(GameObject target) { GameObject target2 = target; if (!((Object)(object)target2 == (Object)null) && !((Object)(object)_instance == (Object)null)) { _instance._entries.RemoveAll((Entry e) => (Object)(object)e.go == (Object)(object)target2); _instance._visible.RemoveAll((Entry e) => (Object)(object)e.go == (Object)(object)target2); } } public List<Entry> GetAllEntriesForSync() { return new List<Entry>(_entries); } public void ApplyLikeBroadcast(GameObject target, int newLikeCount, bool canLike) { GameObject target2 = target; Entry entry = _entries.FirstOrDefault((Entry e) => (Object)(object)e.go == (Object)(object)target2); if (entry != null) { entry.likes = newLikeCount; entry.canLike = canLike; if (entry.floaters == null) { entry.floaters = new List<Floater>(4); } Floater floater = default(Floater); floater.t = 0f; floater.duration = 0.5f; floater.xJitter = Random.Range(-8f * UiScale, 8f * UiScale); floater.scale = Random.Range(0.9f, 1.1f); Floater item = floater; entry.floaters.Add(item); entry.likeTickT = 1f; } } public Entry FindEntry(GameObject target) { GameObject target2 = target; return _entries.FirstOrDefault((Entry e) => (Object)(object)e.go == (Object)(object)target2); } private void Update() { if ((Object)(object)_cam == (Object)null) { _cam = Camera.main; } if ((Object)(object)_cam == (Object)null) { return; } for (int num = _entries.Count - 1; num >= 0; num--) { if ((Object)(object)_entries[num].go == (Object)null) { _entries.RemoveAt(num); } } for (int i = 0; i < _entries.Count; i++) { Entry entry = _entries[i]; if ((Object)(object)entry.go == (Object)null) { continue; } DeletableGroup componentInParent = entry.go.GetComponentInParent<DeletableGroup>(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)((Component)componentInParent).gameObject != (Object)(object)entry.go) { GameObject root = ((Component)componentInParent).gameObject; if (_entries.Any((Entry x) => (Object)(object)x.go == (Object)(object)root)) { _entries.RemoveAt(i); i--; } else { entry.go = root; entry.t = root.transform; _entries[i] = entry; } continue; } Rope component = entry.go.GetComponent<Rope>(); if (!((Object)(object)component != (Object)null)) { continue; } GameObject val = TryGetRopeAnchorObject(component); if (!((Object)(object)val != (Object)null)) { continue; } DeletableGroup component2 = val.GetComponent<DeletableGroup>(); if ((Object)(object)component2 != (Object)null) { GameObject root2 = ((Component)component2).gameObject; if (_entries.Any((Entry x) => (Object)(object)x.go == (Object)(object)root2)) { _entries.RemoveAt(i); i--; } else { entry.go = root2; entry.t = root2.transform; _entries[i] = entry; } } } if (Time.frameCount >= _nextCullFrame) { _nextCullFrame = Time.frameCount + 10; RebuildVisible(); } UpdateFocus(); HandleInput(); } private void RebuildVisible() { //IL_0044: 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) _visible.Clear(); if (_entries.Count == 0) { return; } if (DebugShowAll) { _visible.AddRange(_entries); return; } Vector3 camPos = ((Component)_cam).transform.position; IEnumerable<Entry> collection = from x in (from x in _entries.Select(delegate(Entry e) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Vector3 val = e.t.position - camPos; return (e, ((Vector3)(ref val)).sqrMagnitude); }) where x.d2 <= 100f orderby x.d2 select x).Take(10) select x.e; _visible.AddRange(collection); } private void UpdateFocus() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) _focused = null; if (_visible.Count == 0 || (Object)(object)_cam == (Object)null) { return; } Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor((float)Screen.width * 0.5f, (float)Screen.height * 0.5f); float num = float.MaxValue; Vector2 val3 = default(Vector2); foreach (Entry item in _visible) { if ((Object)(object)item.t == (Object)null) { continue; } Vector3 val2 = _cam.WorldToScreenPoint(item.t.position + Vector3.up * 0.6f); if (!(val2.z < 0f)) { ((Vector2)(ref val3))..ctor(val2.x, (float)Screen.height - val2.y); float num2 = Vector2.SqrMagnitude(val3 - val); if (num2 < num) { num = num2; _focused = item; } } } if (_focused == null) { _removeHeldTime = 0f; } } private void HandleInput() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (_focused == null) { _removeHeldTime = 0f; return; } bool flag = _focused.canLike && (PhotonNetwork.IsMasterClient || ClientsCanLike); bool flag2 = PhotonNetwork.IsMasterClient || ClientsCanDelete; if (flag && Input.GetKeyDown(LikeKey)) { TryLike(_focused); } if (flag2 && Input.GetKey(RemoveKey)) { _removeHeldTime += Time.unscaledDeltaTime; if (_removeHeldTime >= RemoveHoldSeconds) { TryRemove(_focused); _removeHeldTime = 0f; } } else { _removeHeldTime = 0f; } } private void OnGUI() { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Expected O, but got Unknown //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Expected O, but got Unknown //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_04c2: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Expected O, but got Unknown //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_05ce: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Expected O, but got Unknown //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_0611: Unknown result type (might be due to invalid IL or missing references) //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_0642: Unknown result type (might be due to invalid IL or missing references) //IL_0649: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Unknown result type (might be due to invalid IL or missing references) //IL_065e: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_083c: Unknown result type (might be due to invalid IL or missing references) //IL_0841: Unknown result type (might be due to invalid IL or missing references) //IL_0857: Unknown result type (might be due to invalid IL or missing references) //IL_085e: Unknown result type (might be due to invalid IL or missing references) //IL_0864: Unknown result type (might be due to invalid IL or missing references) //IL_0870: Expected O, but got Unknown //IL_08e9: Unknown result type (might be due to