Decompiled source of PEAKLevelLoader v0.4.6
off_grid.PEAKLevelLoader.dll
Decompiled 3 months 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.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Collections.Generic; using PEAKLevelLoader; using PEAKLevelLoader.Core; using Photon.Pun; using Photon.Realtime; using UnityEngine; using Zorro.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("off_grid.PEAKLevelLoader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.4.6.0")] [assembly: AssemblyInformationalVersion("0.4.6")] [assembly: AssemblyProduct("PEAKLevelLoader")] [assembly: AssemblyTitle("off_grid.PEAKLevelLoader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.6.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 PEAKPackSyncPhoton : MonoBehaviour, IOnEventCallback { [Serializable] private class LevelPackDTO { public int index; public bool replace; public bool isVariant; public string? biome; public string? bundlePath; public string? prefabName; public string? campfirePrefabName; public string? packName; public string? id; } [Serializable] private class LevelPackCollectionDTO { public string? sendId; public LevelPackDTO[]? packs; } [Serializable] private class PackAppliedAck { public string? sendId; public int senderActorNumber; } private const byte EVENT_SYNC_PACKS = 200; private const byte EVENT_PACKS_APPLIED_ACK = 201; private static PEAKPackSyncPhoton? _instance; private readonly HashSet<int> lastReceivedAcks = new HashSet<int>(); private int expectedAckCount; private string lastMasterSendId = Guid.Empty.ToString(); public static PEAKPackSyncPhoton? Instance => _instance; private void Awake() { if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } _instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void OnEnable() { PhotonNetwork.AddCallbackTarget((object)this); } private void OnDisable() { PhotonNetwork.RemoveCallbackTarget((object)this); } public void SendPacksToClients(LevelPack[] packs, bool waitForAcks = true, Action<bool> onComplete = null) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00a7: 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) //IL_00af: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.InRoom) { Debug.LogWarning((object)"PEAKPackSyncPhoton: not in a Photon room; skipping send."); onComplete?.Invoke(obj: false); return; } if (!PhotonNetwork.IsMasterClient) { Debug.LogWarning((object)"PEAKPackSyncPhoton: only master should call SendPacksToClients."); onComplete?.Invoke(obj: false); return; } LevelPackCollectionDTO levelPackCollectionDTO = new LevelPackCollectionDTO { sendId = Guid.NewGuid().ToString(), packs = packs.Select((LevelPack p) => new LevelPackDTO { index = p.index, replace = p.replace, isVariant = p.isVariant, biome = (p.biome ?? string.Empty), bundlePath = (p.bundlePath ?? string.Empty), prefabName = (p.prefabName ?? string.Empty), campfirePrefabName = (p.campfirePrefabName ?? string.Empty), packName = (p.packName ?? string.Empty), id = (p.id ?? string.Empty) }).ToArray() }; string s = JsonUtility.ToJson((object)levelPackCollectionDTO); byte[] bytes = Encoding.UTF8.GetBytes(s); RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0, CachingOption = (EventCaching)0 }; SendOptions val2 = default(SendOptions); ((SendOptions)(ref val2)).Reliability = true; SendOptions val3 = val2; lastReceivedAcks.Clear(); expectedAckCount = PhotonNetwork.CurrentRoom.PlayerCount - 1; lastMasterSendId = levelPackCollectionDTO.sendId; PhotonNetwork.RaiseEvent((byte)200, (object)bytes, val, val3); Debug.Log((object)$"PEAKPackSyncPhoton: Master sent {levelPackCollectionDTO.packs.Length} packs (sendId={levelPackCollectionDTO.sendId}) to clients. WaitingForAcks={waitForAcks}"); if (waitForAcks) { ((MonoBehaviour)this).StartCoroutine(WaitForAcksCoroutine(12f, onComplete)); } else { onComplete?.Invoke(obj: true); } } private IEnumerator WaitForAcksCoroutine(float timeout, Action<bool> onComplete) { float start = Time.realtimeSinceStartup; while (Time.realtimeSinceStartup - start < timeout) { if (lastReceivedAcks.Count >= expectedAckCount) { Debug.Log((object)$"PEAKPackSyncPhoton: received all {lastReceivedAcks.Count}/{expectedAckCount} ACKs."); onComplete?.Invoke(obj: true); yield break; } yield return (object)new WaitForSeconds(0.15f); } Debug.LogWarning((object)$"PEAKPackSyncPhoton: Timeout waiting for ACKs ({lastReceivedAcks.Count}/{expectedAckCount})."); onComplete?.Invoke(obj: false); } public void OnEvent(EventData photonEvent) { try { if (photonEvent.Code == 200) { if (photonEvent.CustomData is byte[] bytes) { string @string = Encoding.UTF8.GetString(bytes); LevelPackCollectionDTO levelPackCollectionDTO = JsonUtility.FromJson<LevelPackCollectionDTO>(@string); if (levelPackCollectionDTO == null || levelPackCollectionDTO.packs == null || levelPackCollectionDTO.packs.Length == 0) { Debug.LogWarning((object)"PEAKPackSyncPhoton: empty pack payload received"); return; } Debug.Log((object)$"PEAKPackSyncPhoton: client received {levelPackCollectionDTO.packs.Length} packs (sendId={levelPackCollectionDTO.sendId}). Starting apply..."); ((MonoBehaviour)this).StartCoroutine(ClientHandleReceivedPacks(levelPackCollectionDTO.sendId, levelPackCollectionDTO.packs)); } } else { if (photonEvent.Code != 201 || !(photonEvent.CustomData is byte[] bytes2)) { return; } string string2 = Encoding.UTF8.GetString(bytes2); PackAppliedAck packAppliedAck = JsonUtility.FromJson<PackAppliedAck>(string2); if (packAppliedAck == null || !PhotonNetwork.IsMasterClient) { return; } if (!string.Equals(packAppliedAck.sendId, lastMasterSendId, StringComparison.OrdinalIgnoreCase)) { Debug.Log((object)("PEAKPackSyncPhoton: received ACK for unknown sendId " + packAppliedAck.sendId + " (current " + lastMasterSendId + "). Ignoring.")); } else { lock (lastReceivedAcks) { lastReceivedAcks.Add(packAppliedAck.senderActorNumber); } Debug.Log((object)$"PEAKPackSyncPhoton: master received ACK from Actor {packAppliedAck.senderActorNumber} (total {lastReceivedAcks.Count}/{expectedAckCount})"); } } } catch (Exception ex) { Debug.LogError((object)("PEAKPackSyncPhoton.OnEvent error: " + ex)); } } private IEnumerator ClientHandleReceivedPacks(string sendId, LevelPackDTO[] dtos) { LevelPack[] packs = dtos.Select((LevelPackDTO d) => new LevelPack { index = d.index, replace = d.replace, isVariant = d.isVariant, biome = (d.biome ?? string.Empty), bundlePath = (d.bundlePath ?? string.Empty), prefabName = (d.prefabName ?? string.Empty), campfirePrefabName = (d.campfirePrefabName ?? string.Empty), packName = (d.packName ?? string.Empty), id = (d.id ?? string.Empty) }).ToArray(); float timeout = 10f; float start = Time.realtimeSinceStartup; while (Time.realtimeSinceStartup - start < timeout) { bool flag = true; LevelPack[] array = packs; foreach (LevelPack levelPack in array) { if (!string.IsNullOrEmpty(levelPack.bundlePath) && !IsBundleGroupAvailableAndLoaded(levelPack.bundlePath)) { flag = false; break; } } if (flag) { break; } yield return (object)new WaitForSeconds(0.25f); } try { if ((Object)(object)global::PEAKLevelLoader.PEAKLevelLoader.Instance != (Object)null) { global::PEAKLevelLoader.PEAKLevelLoader.Instance.AddPacks(new LevelPackCollection { packs = packs }); global::PEAKLevelLoader.PEAKLevelLoader.Instance.ApplyPacksToMapHandler(Singleton<MapHandler>.Instance); Debug.Log((object)$"PEAKPackSyncPhoton: client applied {packs.Length} packs locally (sendId={sendId}). Sending ACK."); } else { Debug.LogError((object)"PEAKPackSyncPhoton: client PEAKLevelLoader.Instance null; cannot apply packs."); } } catch (Exception ex) { Debug.LogError((object)("PEAKPackSyncPhoton.ClientHandleReceivedPacks error: " + ex)); } PackAppliedAck packAppliedAck = new PackAppliedAck { sendId = sendId, senderActorNumber = PhotonNetwork.LocalPlayer.ActorNumber }; string s = JsonUtility.ToJson((object)packAppliedAck); byte[] bytes = Encoding.UTF8.GetBytes(s); RaiseEventOptions val = new RaiseEventOptions(); if (PhotonNetwork.MasterClient != null) { val.TargetActors = new int[1] { PhotonNetwork.MasterClient.ActorNumber }; } SendOptions val2 = default(SendOptions); ((SendOptions)(ref val2)).Reliability = true; SendOptions val3 = val2; PhotonNetwork.RaiseEvent((byte)201, (object)bytes, val, val3); } private bool IsBundleGroupAvailableAndLoaded(string groupName) { if (string.IsNullOrEmpty(groupName)) { return true; } Type type = Type.GetType("AssetBundleLoader") ?? Type.GetType("PEAKLevelLoader.AssetBundleLoader"); if (type == null) { return false; } object obj = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null); if (obj == null) { return false; } if (!(type.GetProperty("AssetBundleGroups", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj) is IEnumerable enumerable)) { return false; } foreach (object item in enumerable) { Type type2 = item.GetType(); string a = ((type2.GetProperty("GroupName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(item) as string) ?? string.Empty; if (!string.Equals(a, groupName, StringComparison.OrdinalIgnoreCase)) { continue; } PropertyInfo propertyInfo = type2.GetProperty("LoadedStatus", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperty("IsLoaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type2.GetProperty("Loaded", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo != null) { object value = propertyInfo.GetValue(item); if (value == null) { return false; } string text = value.ToString(); if (text.IndexOf("load", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } return true; } return false; } } public class Placeholder : MonoBehaviour { [Tooltip("Key name used by SpawnableRegistry or the prefab name to look for in bundles.")] public string? spawnableName; [Tooltip("Optional role (e.g. 'campfire', 'spawner', 'fogOrigin', etc.).")] public string? role; [Tooltip("Optional JSON/options string used by loader (e.g. for fog size).")] [TextArea(2, 6)] public string? options; [Tooltip("Optional author notes.")] public string? notes; } public static class AssetBundleGroupDebugger { public static class BundleResolveHelper { public static GameObject? ResolvePrefabFromLoadedGroups(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } Type typeFromHandle = typeof(AssetBundleLoader); AssetBundleLoader instance = AssetBundleLoader.Instance; if ((Object)(object)instance == (Object)null) { return null; } List<AssetBundleGroup> assetBundleGroups = instance.AssetBundleGroups; if (assetBundleGroups == null) { return null; } foreach (AssetBundleGroup item in assetBundleGroups) { if (item == null) { continue; } try { GameObject val = ResolvePrefabFromGroup(item, prefabName); if ((Object)(object)val != (Object)null) { return val; } } catch { } } return null; } } private static readonly Type[] GenericTryTypes = new Type[3] { typeof(GameObject), typeof(TextAsset), typeof(Object) }; public static void LogGroupContents(object group) { if (group == null) { Debug.Log((object)"AssetBundleGroupDebugger: group is null"); return; } Type type = group.GetType(); Debug.Log((object)("AssetBundleGroupDebugger: Inspecting group type: " + type.FullName)); string text = ((type.GetProperty("GroupName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))?.GetValue(group) as string) ?? "(unknown)"; Debug.Log((object)("GroupName: " + text)); object obj = null; PropertyInfo property = type.GetProperty("AssetBundle", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { obj = property.GetValue(group); } if (obj != null) { Type type2 = obj.GetType(); MethodInfo method = type2.GetMethod("GetAllAssetNames", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { try { if (method.Invoke(obj, null) is string[] array && array.Length != 0) { Debug.Log((object)$"AssetBundle: GetAllAssetNames returned {array.Length} entries:"); string[] array2 = array; foreach (string text2 in array2) { Debug.Log((object)(" - " + text2)); } return; } } catch (Exception ex) { Debug.LogWarning((object)("GetAllAssetNames invocation failed: " + ex)); } } } MethodInfo[] array3 = (from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where string.Equals(m.Name, "LoadAllAssets", StringComparison.OrdinalIgnoreCase) || string.Equals(m.Name, "LoadAll", StringComparison.OrdinalIgnoreCase) select m).ToArray(); MethodInfo[] array4 = array3; foreach (MethodInfo methodInfo in array4) { try { if (methodInfo.ContainsGenericParameters) { Type[] genericTryTypes = GenericTryTypes; foreach (Type type3 in genericTryTypes) { try { MethodInfo methodInfo2 = methodInfo.MakeGenericMethod(type3); object result = methodInfo2.Invoke(group, null); if (TryLogEnumerableResult(result, $"LoadAllAssets<{type3.Name}> via {methodInfo}")) { return; } } catch (Exception ex2) { Debug.Log((object)("LoadAllAssets<" + type3.Name + "> failed: " + ex2.Message)); } } continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 0) { object result2 = methodInfo.Invoke(group, null); if (TryLogEnumerableResult(result2, $"LoadAllAssets() via {methodInfo}")) { return; } } else { if (parameters.Length != 1 || !(parameters[0].ParameterType == typeof(Type))) { continue; } Type[] genericTryTypes2 = GenericTryTypes; foreach (Type type4 in genericTryTypes2) { try { object result3 = methodInfo.Invoke(group, new object[1] { type4 }); if (TryLogEnumerableResult(result3, $"LoadAllAssets({type4.Name}) via {methodInfo}")) { return; } } catch (Exception arg) { Debug.LogWarning((object)$"LoadAllAssets failure: {arg}"); } } continue; } } catch (Exception arg2) { Debug.LogWarning((object)$"LoadAllAssets invocation failed: {arg2}"); } } Debug.Log((object)"Fallback: inspecting public enumerable fields/properties..."); bool flag = false; PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in properties) { if (!typeof(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) || !(propertyInfo.PropertyType != typeof(string))) { continue; } try { object value = propertyInfo.GetValue(group); if (!(value is IEnumerable enumerable)) { continue; } int num = 0; foreach (object item in enumerable) { num++; if (item == null) { Debug.Log((object)$" - property {propertyInfo.Name} item {num} == null"); continue; } string text3 = (item.GetType().GetProperty("name")?.GetValue(item) as string) ?? "(no name)"; Debug.Log((object)$"Property {propertyInfo.Name} item {num}: {text3} ({item.GetType().Name})"); flag = true; } } catch { } } if (!flag) { Debug.Log((object)"AssetBundleGroupDebugger: done (no asset names found by the strategies)."); } else { Debug.Log((object)"AssetBundleGroupDebugger: done (fallback enumerated items)."); } } private static bool TryLogEnumerableResult(object result, string label) { if (result == null) { return false; } if (result is IEnumerable enumerable) { Debug.Log((object)(label + " returned enumerable:")); int num = 0; foreach (object item in enumerable) { num++; if (item == null) { Debug.Log((object)$" - {num}: NULL"); continue; } string arg = (item.GetType().GetProperty("name")?.GetValue(item) as string) ?? "(no name)"; Debug.Log((object)$" - {num}: {arg} ({item.GetType().Name})"); } if (num > 0) { return true; } } else { Debug.Log((object)(label + " returned a " + result.GetType().Name + " (not enumerable)")); } return false; } public static GameObject? ResolvePrefabFromGroup(AssetBundleGroup group, string prefabCandidate) { string prefabCandidate2 = prefabCandidate; if (group == null || string.IsNullOrEmpty(prefabCandidate2)) { return null; } try { try { List<GameObject> list = group.LoadAllAssets<GameObject>(); if (list != null && list.Count > 0) { GameObject val = ((IEnumerable<GameObject>)list).FirstOrDefault((Func<GameObject, bool>)((GameObject a) => (Object)(object)a != (Object)null && string.Equals(((Object)a).name, prefabCandidate2, StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val != (Object)null) { return val; } } } catch { } try { List<AssetBundleInfo> assetBundleInfos = group.GetAssetBundleInfos(); foreach (AssetBundleInfo item in assetBundleInfos) { AssetBundle assetBundleReference = item.AssetBundleReference; if ((Object)(object)assetBundleReference == (Object)null) { continue; } string[] allAssetNames = assetBundleReference.GetAllAssetNames(); foreach (string text in allAssetNames) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); if (string.Equals(fileNameWithoutExtension, prefabCandidate2, StringComparison.OrdinalIgnoreCase)) { GameObject val2 = assetBundleReference.LoadAsset<GameObject>(text); if ((Object)(object)val2 != (Object)null) { return val2; } } } } } catch { } try { List<Object> list2 = group.LoadAllAssets<Object>(); if (list2 != null) { foreach (Object item2 in list2) { if (item2 == (Object)null) { continue; } GameObject val3 = (GameObject)(object)((item2 is GameObject) ? item2 : null); if (val3 != null && string.Equals(((Object)val3).name, prefabCandidate2, StringComparison.OrdinalIgnoreCase)) { return val3; } if (item2.name != null && string.Equals(Path.GetFileNameWithoutExtension(item2.name), prefabCandidate2, StringComparison.OrdinalIgnoreCase)) { GameObject val4 = (GameObject)(object)((item2 is GameObject) ? item2 : null); if (val4 != null) { return val4; } } } } } catch { } } catch (Exception arg) { Debug.LogWarning((object)$"ResolvePrefabFromGroup error: {arg}"); } return null; } private static GameObject? FindMatchingGameObjectInEnumerable(IEnumerable enumerable, string candidate) { if (enumerable == null) { return null; } foreach (object item in enumerable) { if (item == null) { continue; } Type type = item.GetType(); string text = (type.GetProperty("name")?.GetValue(item) as string) ?? null; if (!string.IsNullOrEmpty(text) && (string.Equals(text, candidate, StringComparison.OrdinalIgnoreCase) || string.Equals(Path.GetFileNameWithoutExtension(text), candidate, StringComparison.OrdinalIgnoreCase))) { return (GameObject?)((item is GameObject) ? item : null); } if (item is string text2) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text2); if (string.Equals(fileNameWithoutExtension, candidate, StringComparison.OrdinalIgnoreCase) || text2.IndexOf(candidate, StringComparison.OrdinalIgnoreCase) >= 0) { return null; } } } return null; } } public class PatchedContentDebug : MonoBehaviour { private void Update() { if (Input.GetKeyDown((KeyCode)290)) { DumpPatchedContent(); } } public static void DumpPatchedContent() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("==== PatchedContent Dump ===="); stringBuilder.AppendLine($"LoadedBundleHashes: {PatchedContent.LoadedBundleHashes.Count}"); stringBuilder.AppendLine($"LoadedBundleNames: {PatchedContent.LoadedBundleNames.Count}"); stringBuilder.AppendLine($"AllLevelSceneNames: {PatchedContent.AllLevelSceneNames.Count}"); stringBuilder.AppendLine($"ExtendedMods: {PatchedContent.ExtendedMods.Count}"); foreach (ExtendedMod extendedMod in PatchedContent.ExtendedMods) { stringBuilder.AppendLine(" - Mod: " + extendedMod.ModName + " (Author: " + extendedMod.AuthorName + ")"); if (extendedMod.ExtendedContents == null) { continue; } foreach (ExtendedContent extendedContent in extendedMod.ExtendedContents) { stringBuilder.AppendLine(string.Format(" - Content: {0} (Type: {1}, Tags: {2})", ((Object)extendedContent).name, extendedContent.ContentType, string.Join(',', extendedContent.ContentTags?.ConvertAll((ContentTag t) => t?.contentTagName ?? "null") ?? new List<string>()))); } } stringBuilder.AppendLine("==== End Dump ===="); Debug.Log((object)stringBuilder.ToString()); } } public static class SpawnerHelper { public static Vector3 GetLossyScale(this Transform t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = t.localScale; Transform parent = t.parent; while ((Object)(object)parent != (Object)null) { val = Vector3.Scale(val, parent.localScale); parent = parent.parent; } return val; } public static void SetParentPreserveWorld(Transform child, Transform parent) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) Vector3 position = child.position; Quaternion rotation = child.rotation; Vector3 lossyScale = child.GetLossyScale(); child.SetParent(parent, true); Vector3 val = (((Object)(object)parent != (Object)null) ? parent.GetLossyScale() : Vector3.one); val.x = (Mathf.Approximately(val.x, 0f) ? 1f : val.x); val.y = (Mathf.Approximately(val.y, 0f) ? 1f : val.y); val.z = (Mathf.Approximately(val.z, 0f) ? 1f : val.z); child.localScale = new Vector3(lossyScale.x / val.x, lossyScale.y / val.y, lossyScale.z / val.z); child.position = position; child.rotation = rotation; } internal static void RegisterSegmentContentsSync(GameObject instGO, LevelPack pack, GameObject? campfirePrefab, object mapSegObj, Action<string, object?> TrySetBackingField) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) try { Campfire componentInChildren = instGO.GetComponentInChildren<Campfire>(true); GameObject val = null; Transform val2 = instGO.transform.Find("CampfireAnchor") ?? instGO.transform.Find("campfireAnchor") ?? instGO.transform.Find("Campfire") ?? ((IEnumerable<Transform>)instGO.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf("campfire", StringComparison.OrdinalIgnoreCase) >= 0)); if ((Object)(object)componentInChildren != (Object)null) { val = ((Component)componentInChildren).gameObject; if ((Object)(object)val2 != (Object)null && (Object)(object)val.transform.parent != (Object)(object)val2) { SetParentPreserveWorld(val.transform, val2); } } else if ((Object)(object)campfirePrefab != (Object)null) { val = Object.Instantiate<GameObject>(campfirePrefab); ((Object)val).name = "ModCampfire_" + pack.packName + "_" + (pack.campfirePrefabName ?? "campfire"); Transform parent = val2 ?? instGO.transform; SetParentPreserveWorld(val.transform, parent); if ((Object)(object)val2 != (Object)null) { val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; } } if ((Object)(object)val != (Object)null) { TrySetBackingField("_segmentCampfire", val); } else { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("RegisterSegmentContents: no campfire found/created for pack " + pack.packName + ".")); } } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"RegisterSegmentContents: campfire registration failed for {pack.packName}: {arg}"); } try { Spawner[] componentsInChildren = instGO.GetComponentsInChildren<Spawner>(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { Spawner[] array = componentsInChildren; foreach (Spawner val3 in array) { if (val3.spawnSpots == null || val3.spawnSpots.Count == 0) { List<Transform> list = (from t in ((Component)val3).GetComponentsInChildren<Transform>(true) where ((Object)t).name.IndexOf("spawnspot", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("spawn_point", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("spawn", StringComparison.OrdinalIgnoreCase) >= 0 select (t)).ToList(); if (list.Count > 0) { val3.spawnSpots = list; } } SpawnMapping[] array2 = pack.spawnMappings ?? Array.Empty<SpawnMapping>(); foreach (SpawnMapping mapping2 in array2) { Transform val4 = instGO.transform.Find(mapping2.spawnerMarker) ?? ((IEnumerable<Transform>)instGO.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf(mapping2.spawnerMarker, StringComparison.OrdinalIgnoreCase) >= 0)); if (!((Object)(object)val4 == (Object)null) && PatchedContent.SpawnableRegistry.Registry.TryGetValue(mapping2.spawnableName, out var value) && SpawnerResolveHelper.TryResolvePrefab(value, out GameObject resolvedPrefab) && (Object)(object)resolvedPrefab != (Object)null) { val3.spawnedObjectPrefab = resolvedPrefab; global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("Wired spawner '" + ((Object)val3).name + "' -> prefab '" + ((Object)resolvedPrefab).name + "'")); } } if ((!((Object)(object)val3.spawnedObjectPrefab == (Object)null) && !(((Object)val3.spawnedObjectPrefab).name == "null")) || pack == null) { continue; } SpawnMapping[] array3 = pack.spawnMappings ?? Array.Empty<SpawnMapping>(); foreach (SpawnMapping mapping in array3) { Transform val5 = instGO.transform.Find(mapping.spawnerMarker) ?? ((IEnumerable<Transform>)instGO.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf(mapping.spawnerMarker, StringComparison.OrdinalIgnoreCase) >= 0)); if (!((Object)(object)val5 == (Object)null) && (val5.IsChildOf(((Component)val3).transform) || !((Object)(object)val5 != (Object)(object)((Component)val3).transform)) && PatchedContent.SpawnableRegistry.Registry.TryGetValue(mapping.spawnableName, out var value2)) { GameObject val6 = AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(value2.prefab); if ((Object)(object)val6 != (Object)null) { val3.spawnedObjectPrefab = val6; global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("Wired spawner '" + ((Object)val3).name + "' -> prefab '" + value2.prefab + "'")); break; } } } } return; } List<Transform> list2 = (from t in instGO.GetComponentsInChildren<Transform>(true) where ((Object)t).name.IndexOf("spawner", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("prop_spawner", StringComparison.OrdinalIgnoreCase) >= 0 select t).ToList(); foreach (Transform item in list2) { Spawner val7 = ((Component)item).gameObject.AddComponent<Spawner>(); val7.spawnOnStart = true; List<Transform> spawnSpots = (from t in ((Component)item).GetComponentsInChildren<Transform>(true) where ((Object)t).name.IndexOf("spawnspot", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("spawn_point", StringComparison.OrdinalIgnoreCase) >= 0 select (t)).ToList(); val7.spawnSpots = spawnSpots; } } catch (Exception arg2) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"RegisterSegmentContents: spawner registration failed for {pack.packName}: {arg2}"); } } } public static class SpawnerResolveHelper { public static string? GetPrefabNameFromEntry(object? entry) { if (entry == null) { return null; } Type type = entry.GetType(); string[] array = new string[5] { "prefab", "prefabName", "PrefabName", "prefabPath", "path" }; string[] array2 = array; foreach (string name in array2) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { try { string text = property.GetValue(entry) as string; if (!string.IsNullOrEmpty(text)) { return text; } } catch { } } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null)) { continue; } try { string text2 = field.GetValue(entry) as string; if (!string.IsNullOrEmpty(text2)) { return text2; } } catch { } } try { string text3 = entry.ToString(); if (!string.IsNullOrEmpty(text3)) { return text3; } } catch { } return null; } public static GameObject? ResolvePrefabFromRegistryEntry(object? entry) { string prefabNameFromEntry = GetPrefabNameFromEntry(entry); if (string.IsNullOrEmpty(prefabNameFromEntry)) { return null; } try { return AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(prefabNameFromEntry); } catch (Exception arg) { Debug.LogWarning((object)$"SpawnerResolveHelper.ResolvePrefabFromRegistryEntry: failed resolving '{prefabNameFromEntry}': {arg}"); return null; } } public static bool TryResolvePrefab(object? registryEntry, out GameObject? resolvedPrefab) { resolvedPrefab = null; if (registryEntry == null) { return false; } if (registryEntry is string prefabName) { resolvedPrefab = AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(prefabName); return (Object)(object)resolvedPrefab != (Object)null; } Type type = registryEntry.GetType(); string[] array = new string[6] { "prefab", "prefabName", "Prefab", "PrefabName", "bundlePath", "path" }; string[] array2 = array; foreach (string name in array2) { PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.PropertyType == typeof(string)) { try { string text = property.GetValue(registryEntry) as string; if (!string.IsNullOrEmpty(text)) { resolvedPrefab = AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(text); if ((Object)(object)resolvedPrefab != (Object)null) { return true; } } } catch { } } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field != null) || !(field.FieldType == typeof(string))) { continue; } try { string text2 = field.GetValue(registryEntry) as string; if (!string.IsNullOrEmpty(text2)) { resolvedPrefab = AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(text2); if ((Object)(object)resolvedPrefab != (Object)null) { return true; } } } catch { } } try { string text3 = registryEntry.ToString() ?? ""; string[] array3 = text3.Split(new char[3] { ':', '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length != 0) { string text4 = array3[^1]; if (!string.IsNullOrEmpty(text4)) { resolvedPrefab = AssetBundleGroupDebugger.BundleResolveHelper.ResolvePrefabFromLoadedGroups(text4); if ((Object)(object)resolvedPrefab != (Object)null) { return true; } } } } catch { } return false; } } public static class StringExtensions { public static string ReplaceInvalidFileNameChars(this string s, char replaceWith = '_') { if (string.IsNullOrEmpty(s)) { return s ?? string.Empty; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); char[] array = s.ToCharArray(); for (int i = 0; i < array.Length; i++) { if (Array.IndexOf(invalidFileNameChars, array[i]) >= 0) { array[i] = replaceWith; } } return new string(array); } public static string SanitizeJson(string txt) { if (string.IsNullOrEmpty(txt)) { return txt; } txt = txt.TrimStart('\ufeff', '\u200b', '\u200e', '\u200f', '\0'); int i; for (i = 0; i < txt.Length && char.IsControl(txt[i]) && txt[i] != '\r' && txt[i] != '\n' && txt[i] != '\t'; i++) { } if (i > 0) { txt = txt.Substring(i); } return txt; } public static string ExtractTopLevelArray(string json, string key) { if (string.IsNullOrEmpty(json)) { return string.Empty; } int num = json.IndexOf("\"" + key + "\"", StringComparison.OrdinalIgnoreCase); if (num < 0) { return string.Empty; } int num2 = json.IndexOf('[', num); if (num2 < 0) { return string.Empty; } int num3 = 0; for (int i = num2; i < json.Length; i++) { if (json[i] == '[') { num3++; } else if (json[i] == ']') { num3--; } if (num3 == 0) { return json.Substring(num2, i - num2 + 1); } } return string.Empty; } public static List<string> SplitTopLevelObjects(string arrayText) { List<string> list = new List<string>(); if (string.IsNullOrWhiteSpace(arrayText)) { return list; } int i; for (i = 0; i < arrayText.Length && arrayText[i] != '['; i++) { } if (i >= arrayText.Length) { return list; } i++; while (i < arrayText.Length) { for (; i < arrayText.Length && (char.IsWhiteSpace(arrayText[i]) || arrayText[i] == ','); i++) { } if (i >= arrayText.Length || arrayText[i] != '{') { break; } int num = i; int num2 = 0; for (; i < arrayText.Length; i++) { if (arrayText[i] == '{') { num2++; } else if (arrayText[i] == '}') { num2--; } if (num2 == 0) { i++; break; } } if (num2 != 0) { break; } list.Add(arrayText.Substring(num, i - num)); } return list; } } public static class FogOriginRegistrar { private static FieldInfo _originsField; private static Type _orbFogHandlerType; static FogOriginRegistrar() { _orbFogHandlerType = typeof(OrbFogHandler); _originsField = _orbFogHandlerType.GetField("origins", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } public static void InsertOriginAtIndex(FogSphereOrigin origin, int idx) { if ((Object)(object)origin == (Object)null) { return; } try { OrbFogHandler instance = Singleton<OrbFogHandler>.Instance; if ((Object)(object)instance == (Object)null) { Debug.LogWarning((object)"FogOriginRegistrar: OrbFogHandler.Instance is null; cannot register fog origin now."); return; } if (_originsField == null) { Debug.LogWarning((object)"FogOriginRegistrar: couldn't find 'origins' field on OrbFogHandler via reflection."); return; } FogSphereOrigin[] source = (_originsField.GetValue(instance) as FogSphereOrigin[]) ?? Array.Empty<FogSphereOrigin>(); List<FogSphereOrigin> list = source.ToList(); if (idx < 0 || idx > list.Count) { idx = list.Count; } list.Insert(idx, origin); FogSphereOrigin[] array = list.ToArray(); _originsField.SetValue(instance, array); MethodInfo method = _orbFogHandlerType.GetMethod("InitNewSphere", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { FieldInfo field = _orbFogHandlerType.GetField("currentID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = ((field != null) ? ((int)field.GetValue(instance)) : 0); if (num >= 0 && num < array.Length) { method.Invoke(instance, new object[1] { array[num] }); } } Debug.Log((object)$"FogOriginRegistrar: inserted origin at index {idx}. total origins now = {array.Length}"); } catch (Exception ex) { Debug.LogWarning((object)("FogOriginRegistrar failed: " + ex)); } } } public static class PlaceholderProcessor { public class FogSphereOriginProxy : MonoBehaviour { public float size = 650f; public bool disableFog; public float moveOnHeight; public float moveOnForward; } public class ModLuggageMarker : MonoBehaviour { public string? packName; } private static readonly string[] LuggageTypeNames = new string[6] { "Luggage", "LuggageItem", "LuggageController", "Item", "Pickup", "LuggageBehaviour" }; private static readonly string[] FogOriginTypeNames = new string[1] { "FogSphereOrigin" }; private static readonly string[] CampfireTypeNames = new string[1] { "Campfire" }; public static void ProcessPlaceholdersSync(GameObject instGO, LevelPack pack, object mapSegObj, int insertionIndex) { if ((Object)(object)instGO == (Object)null || pack == null) { return; } try { Placeholder[] array = instGO.GetComponentsInChildren<Placeholder>(true) ?? Array.Empty<Placeholder>(); Placeholder[] array2 = array; foreach (Placeholder placeholder in array2) { try { HandleSinglePlaceholder(((Component)placeholder).gameObject, placeholder, pack, mapSegObj, insertionIndex); } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: failed processing placeholder '{((Object)placeholder).name}': {arg}"); } } Transform[] array3 = (from t in instGO.GetComponentsInChildren<Transform>(true) where ((Object)t).name.IndexOf("fogorigin", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("fog_origin", StringComparison.OrdinalIgnoreCase) >= 0 select t).ToArray(); Transform[] array4 = array3; foreach (Transform val in array4) { try { HandleFogOriginGameObject(((Component)val).gameObject, pack, insertionIndex); } catch (Exception arg2) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: FogOrigin handle failed for {((Object)val).name}: {arg2}"); } } GameObject[] array5 = (from t in instGO.GetComponentsInChildren<Transform>(true) where ((Object)t).name.IndexOf("luggage_", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)t).name.IndexOf("luggage", StringComparison.OrdinalIgnoreCase) >= 0 select ((Component)t).gameObject).ToArray(); GameObject[] array6 = array5; foreach (GameObject val2 in array6) { try { HandleLuggageGameObject(val2, pack); } catch (Exception arg3) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: Luggage handle failed for {((Object)val2).name}: {arg3}"); } } } catch (Exception arg4) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogError((object)$"PlaceholderProcessor: top-level failure: {arg4}"); } } private static void HandleSinglePlaceholder(GameObject placeholderGO, Placeholder ph, LevelPack pack, object mapSegObj, int insertionIndex) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)placeholderGO == (Object)null) { return; } string text = (ph.role ?? "").Trim().ToLowerInvariant(); string text2 = (ph.spawnableName ?? "").Trim(); if (!string.IsNullOrEmpty(text)) { switch (text) { case "fogorigin": case "fog_origin": case "fog": HandleFogOriginGameObject(placeholderGO, pack, insertionIndex, ph); return; } if (text.Contains("luggage") || text.Contains("bag") || text.Contains("suitcase")) { HandleLuggageGameObject(placeholderGO, pack, ph); return; } if (text.Contains("campfire")) { EnsureRuntimeCampfire(placeholderGO, pack); return; } } if (!string.IsNullOrEmpty(text2)) { GameObject val = null; if (PatchedContent.SpawnableRegistry.Registry.TryGetValue(text2, out var value)) { try { if (SpawnerResolveHelper.TryResolvePrefab(value, out GameObject resolvedPrefab) && (Object)(object)resolvedPrefab != (Object)null) { GameObject val2 = Object.Instantiate<GameObject>(val, placeholderGO.transform.position, placeholderGO.transform.rotation, placeholderGO.transform.parent); ((Object)val2).name = "ModSpawn_" + pack.packName + "_" + ((Object)val).name; val2.transform.localScale = placeholderGO.transform.localScale; Object.DestroyImmediate((Object)(object)placeholderGO); if (text2.IndexOf("luggage", StringComparison.OrdinalIgnoreCase) >= 0) { EnsureLuggageBehaviour(val2, pack); } return; } } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: SpawnableResolver invocation failed: {arg}"); } } } if (placeholderGO.transform.childCount > 0) { GameObject val3 = Object.Instantiate<GameObject>(placeholderGO, placeholderGO.transform.parent); ((Object)val3).name = "ModProp_" + pack.packName + "_" + ((Object)placeholderGO).name; if (((Object)placeholderGO).name.IndexOf("luggage", StringComparison.OrdinalIgnoreCase) >= 0) { EnsureLuggageBehaviour(val3, pack); } Object.DestroyImmediate((Object)(object)placeholderGO); } } private static void HandleFogOriginGameObject(GameObject fogGO, LevelPack pack, int insertionIndex, Placeholder ph = null) { //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown if ((Object)(object)fogGO == (Object)null) { return; } Type type = FindTypeInLoadedAssembliesByName(FogOriginTypeNames); if (type == null) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)"PlaceholderProcessor: FogSphereOrigin type not found at runtime (will create plain GameObject and register)."); } object obj = null; if (type != null) { Component component = fogGO.GetComponent(type); if ((Object)(object)component != (Object)null) { obj = component; } else { try { obj = fogGO.AddComponent(type); } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: Failed to AddComponent({type.Name}) on {((Object)fogGO).name}: {arg}"); obj = null; } } } else { FogSphereOriginProxy fogSphereOriginProxy = fogGO.GetComponent<FogSphereOriginProxy>() ?? fogGO.AddComponent<FogSphereOriginProxy>(); obj = fogSphereOriginProxy; } float num = 650f; bool flag = false; float num2 = 0f; float num3 = 0f; try { if ((Object)(object)ph != (Object)null && !string.IsNullOrEmpty(ph.options)) { Dictionary<string, string> dict = ParseOptionsString(ph.options); num = TryParseFloatFromDict(dict, "size", num); flag = TryParseBoolFromDict(dict, "disableFog", flag); num2 = TryParseFloatFromDict(dict, "moveOnHeight", num2); num3 = TryParseFloatFromDict(dict, "moveOnForward", num3); } } catch { } if (obj != null) { TrySetFieldOrProperty(obj, "size", num); TrySetFieldOrProperty(obj, "disableFog", flag); TrySetFieldOrProperty(obj, "moveOnHeight", num2); TrySetFieldOrProperty(obj, "moveOnForward", num3); TrySetFieldOrProperty(obj, "moveOnForward", num3); } try { FogOriginRegistrar.InsertOriginAtIndex((FogSphereOrigin)obj, insertionIndex); global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)$"PlaceholderProcessor: Registered fog origin '{((Object)fogGO).name}' at index {insertionIndex} for pack {pack.packName}"); } catch (Exception arg2) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: failed to register fog origin: {arg2}"); } } private static void HandleLuggageGameObject(GameObject luggageGO, LevelPack pack, Placeholder ph = null) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)luggageGO == (Object)null) { return; } string name = ((Object)luggageGO).name; string registryEntry = name; GameObject val = null; try { if (SpawnerResolveHelper.TryResolvePrefab(registryEntry, out GameObject resolvedPrefab) && (Object)(object)resolvedPrefab != (Object)null) { Transform parent = luggageGO.transform.parent; Vector3 position = luggageGO.transform.position; Quaternion rotation = luggageGO.transform.rotation; Vector3 localScale = luggageGO.transform.localScale; GameObject val2 = Object.Instantiate<GameObject>(val, position, rotation, parent); val2.transform.localScale = localScale; ((Object)val2).name = "ModLuggage_" + pack.packName + "_" + ((Object)val).name; Object.DestroyImmediate((Object)(object)luggageGO); EnsureLuggageBehaviour(val2, pack); return; } } catch { } EnsureLuggageBehaviour(luggageGO, pack); } private static void EnsureRuntimeCampfire(GameObject campfireGO, LevelPack pack) { if ((Object)(object)campfireGO == (Object)null) { return; } Type type = FindTypeInLoadedAssembliesByName(CampfireTypeNames); if (type == null) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("PlaceholderProcessor: Campfire runtime type not found — leaving visual '" + ((Object)campfireGO).name + "' as-is.")); return; } Component component = campfireGO.GetComponent(type); if (!((Object)(object)component == (Object)null)) { return; } try { component = campfireGO.AddComponent(type); TrySetFieldOrProperty(component, "burnsFor", 180f); global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("PlaceholderProcessor: attached runtime Campfire component to '" + ((Object)campfireGO).name + "'")); } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: failed to add Campfire component to {((Object)campfireGO).name}: {arg}"); } } private static void EnsureLuggageBehaviour(GameObject go, LevelPack pack) { if ((Object)(object)go == (Object)null) { return; } Type type = FindTypeInLoadedAssembliesByName(LuggageTypeNames); if (type != null) { try { Component component = go.GetComponent(type); if ((Object)(object)component == (Object)null) { Component target = go.AddComponent(type); TrySetFieldOrProperty(target, "nameOverride", ((Object)go).name); TrySetFieldOrProperty(target, "disableFogFakeMountain", false); } global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("PlaceholderProcessor: attached luggage-like component (" + type.Name + ") to '" + ((Object)go).name + "'")); } catch (Exception arg) { global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogWarning((object)$"PlaceholderProcessor: error attaching luggage type: {arg}"); } } else { ModLuggageMarker modLuggageMarker = go.GetComponent<ModLuggageMarker>() ?? go.AddComponent<ModLuggageMarker>(); modLuggageMarker.packName = pack?.packName ?? "<unknown>"; global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("PlaceholderProcessor: added ModLuggageMarker to '" + ((Object)go).name + "' (no runtime luggage type found).")); } Type type2 = FindTypeInLoadedAssembliesByName("Photon.Pun.PhotonView", "PhotonView"); if (!(type2 != null)) { return; } try { if ((Object)(object)go.GetComponent(type2) == (Object)null) { go.AddComponent(type2); global::PEAKLevelLoader.PEAKLevelLoader.Logger.LogInfo((object)("PlaceholderProcessor: added PhotonView to '" + ((Object)go).name + "' for networking.")); } } catch { } } private static Type? FindTypeInLoadedAssembliesByName(params string[] typeNameCandidates) { foreach (string text in typeNameCandidates) { Type type = FindTypeInLoadedAssembliesByName(text); if (type != null) { return type; } } return null; } private static Type? FindTypeInLoadedAssembliesByName(IEnumerable<string> candidates) { string[] source = candidates.ToArray(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Assembly[] array = assemblies; foreach (Assembly assembly in array) { Type[] types; try { types = assembly.GetTypes(); } catch { continue; } Type[] array2 = types; foreach (Type t in array2) { if (source.Any((string c) => string.Equals(t.Name, c, StringComparison.OrdinalIgnoreCase) || string.Equals(t.FullName, c, StringComparison.OrdinalIgnoreCase))) { return t; } } } return null; } private static void TrySetFieldOrProperty(object target, string name, object val) { if (target == null) { return; } Type type = target.GetType(); FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { try { field.SetValue(target, ConvertToType(val, field.FieldType)); return; } catch { } } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(property != null) || !property.CanWrite) { return; } try { property.SetValue(target, ConvertToType(val, property.PropertyType)); } catch { } } private static object ConvertToType(object val, Type targetType) { if (val == null) { return null; } try { if (targetType.IsAssignableFrom(val.GetType())) { return val; } if (targetType.IsEnum) { if (val is string value) { return Enum.Parse(targetType, value, ignoreCase: true); } return Enum.ToObject(targetType, val); } return Convert.ChangeType(val, targetType); } catch { return val; } } private static Dictionary<string, string> ParseOptionsString(string raw) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(raw)) { return dictionary; } string[] array = raw.Split(new char[3] { '\n', ';', '\r' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { '=' }, 2); if (array3.Length == 2) { dictionary[array3[0].Trim()] = array3[1].Trim(); } } return dictionary; } private static float TryParseFloatFromDict(Dictionary<string, string> dict, string key, float fallback) { if (dict.TryGetValue(key, out string value) && float.TryParse(value, out var result)) { return result; } return fallback; } private static bool TryParseBoolFromDict(Dictionary<string, string> dict, string key, bool fallback) { if (dict.TryGetValue(key, out string value) && bool.TryParse(value, out var result)) { return result; } return fallback; } } namespace PEAKLevelLoader { public static class PEAKBundleManager { public enum ModProcessingStatus { Inactive, Loading, Complete } public static ModProcessingStatus CurrentStatus { get; internal set; } public static bool HasFinalisedFoundContent { get; internal set; } public static event Action? OnFinishedProcessing; internal static void Start() { PEAKLevelLoader.Logger.LogInfo((object)"PEAKBundleManager: Starting!"); TryLoadPEAKBundles(); } private static bool TryLoadPEAKBundles() { //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) PEAKLevelLoader.Logger.LogInfo((object)"PEAKBundleManager: Now scanning entire BepInEx plugins directory for .pll files..."); List<string> list = new List<string>(); try { string pluginPath = Paths.PluginPath; if (Directory.Exists(pluginPath)) { list.Add(pluginPath); } else { PEAKLevelLoader.Logger.LogWarning((object)("PEAKBundleManager: Plugins root not found: " + pluginPath)); } string text = Path.Combine(Path.GetTempPath(), "PEAKLevelLoader_embedded"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { try { PluginInfo value = pluginInfo.Value; if (value == null) { continue; } Assembly assembly = null; if ((Object)(object)value.Instance != (Object)null) { assembly = ((object)value.Instance).GetType().Assembly; goto IL_0381; } if (!string.IsNullOrEmpty(value.Location)) { try { string directoryName = Path.GetDirectoryName(value.Location); if (!string.IsNullOrEmpty(directoryName) && Directory.Exists(directoryName)) { foreach (string item in Directory.EnumerateFiles(directoryName, "*.pll", SearchOption.TopDirectoryOnly)) { if (!list.Contains(directoryName)) { list.Add(directoryName); } } } } catch (Exception arg) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: failed scanning plugin folder for on-disk bundles: {arg}"); } } if (!PEAKLevelLoader.AllowEmbeddedBundles) { ManualLogSource logger = PEAKLevelLoader.Logger; BepInPlugin metadata = value.Metadata; logger.LogDebug((object)("PEAKBundleManager: plugin " + (((metadata != null) ? metadata.GUID : null) ?? value.Location) + " not loaded into domain; skipping manifest resource extraction.")); continue; } try { Type type = Type.GetType("Mono.Cecil.AssemblyDefinition, Mono.Cecil"); if (type == null) { PEAKLevelLoader.Logger.LogInfo((object)"PEAKBundleManager: Mono.Cecil not available. Skipping embedded resource extraction for unloaded plugin."); } else if (!string.IsNullOrEmpty(value.Location) && File.Exists(value.Location)) { try { AssemblyDefinition val = AssemblyDefinition.ReadAssembly(value.Location); Enumerator<Resource> enumerator3 = val.MainModule.Resources.GetEnumerator(); try { while (enumerator3.MoveNext()) { Resource current3 = enumerator3.Current; EmbeddedResource val2 = (EmbeddedResource)(object)((current3 is EmbeddedResource) ? current3 : null); if (val2 == null || !((Resource)val2).Name.EndsWith(".pll", StringComparison.OrdinalIgnoreCase)) { continue; } try { using Stream stream = val2.GetResourceStream(); if (stream != null) { BepInPlugin metadata2 = value.Metadata; string path = (((metadata2 != null) ? metadata2.GUID : null) ?? value.Location?.GetHashCode().ToString() ?? "plugin").ReplaceInvalidFileNameChars(); string text2 = Path.Combine(text, path); if (!Directory.Exists(text2)) { Directory.CreateDirectory(text2); } string path2 = Path.Combine(text2, Path.GetFileName(((Resource)val2).Name)); using (FileStream destination = File.Create(path2)) { stream.CopyTo(destination); } if (!list.Contains(text2)) { list.Add(text2); } } } catch (Exception arg2) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: Failed to extract embedded resource '{current3.Name}' from plugin '{value.Location}': {arg2}"); } } } finally { ((IDisposable)enumerator3).Dispose(); } } catch (Exception arg3) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: Mono.Cecil extraction failed for {value.Location}: {arg3}"); } } } catch (Exception arg4) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: error checking for Mono.Cecil: {arg4}"); } goto IL_0381; IL_0381: if (assembly == null) { continue; } string[] manifestResourceNames = assembly.GetManifestResourceNames(); foreach (string text3 in manifestResourceNames) { if (!text3.EndsWith(".pll", StringComparison.OrdinalIgnoreCase)) { continue; } try { using Stream stream2 = assembly.GetManifestResourceStream(text3); if (stream2 != null) { BepInPlugin metadata3 = value.Metadata; string path3 = (((metadata3 != null) ? metadata3.GUID : null) ?? value.Location?.GetHashCode().ToString() ?? "plugin").ReplaceInvalidFileNameChars(); string text4 = Path.Combine(text, path3); if (!Directory.Exists(text4)) { Directory.CreateDirectory(text4); } string path4 = Path.Combine(text4, Path.GetFileName(text3)); using (FileStream destination2 = File.Create(path4)) { stream2.CopyTo(destination2); } if (!list.Contains(text4)) { list.Add(text4); } } } catch (Exception arg5) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: Failed to extract embedded resource '{text3}' from plugin '{value.Location}': {arg5}"); } } } catch (Exception arg6) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: Failed inspecting plugin for embedded bundles: {arg6}"); } } } catch (Exception arg7) { PEAKLevelLoader.Logger.LogError((object)$"PEAKBundleManager: Exception gathering folders to scan: {arg7}"); } if (list.Count == 0) { PEAKLevelLoader.Logger.LogInfo((object)"PEAKBundleManager: No plugin folders found to scan for .pll files."); return false; } ParameterEvent<AssetBundleGroup> parameterEvent = new ParameterEvent<AssetBundleGroup>(); parameterEvent.AddListener(OnAssetBundleGroupCreated); bool flag = AssetBundleLoader.LoadAllBundlesRequest(null, "*", ".pll", parameterEvent, list); if (flag) { PEAKLevelLoader.Logger.LogInfo((object)$"PEAKBundleManager: Initiated load request — scanning {list.Count} folder(s)."); AssetBundleLoader.OnBundlesFinishedProcessing.AddListener(OnAssetBundleLoadRequestFinished); } else { PEAKLevelLoader.Logger.LogWarning((object)"PEAKBundleManager: LoadAllBundlesRequest returned false (no bundles found)."); } return flag; } private static void OnAssetBundleGroupCreated(AssetBundleGroup group) { try { List<string> sceneNames = group.GetSceneNames(); foreach (string item in sceneNames) { if (!PatchedContent.AllLevelSceneNames.Contains(item)) { PatchedContent.AllLevelSceneNames.Add(item); } } List<TextAsset> list = group.LoadAllAssets<TextAsset>(); TextAsset val = null; foreach (TextAsset item2 in list) { if (!((Object)(object)item2 == (Object)null) && ((Object)item2).name.Equals("mod.json", StringComparison.OrdinalIgnoreCase)) { val = item2; break; } } try { List<ExtendedMod> list2 = new List<ExtendedMod>(); try { List<ExtendedMod> list3 = group.LoadAllAssets<ExtendedMod>(); if (list3 != null && list3.Count > 0) { foreach (ExtendedMod item3 in list3) { if ((Object)(object)item3 != (Object)null) { list2.Add(item3); } } } } catch { } List<ExtendedSegment> list4 = new List<ExtendedSegment>(); try { List<ExtendedSegment> list5 = group.LoadAllAssets<ExtendedSegment>(); if (list5 != null && list5.Count > 0) { foreach (ExtendedSegment item4 in list5) { if ((Object)(object)item4 != (Object)null) { list4.Add(item4); } } } } catch { } if (list2.Count > 0 || list4.Count > 0) { foreach (ExtendedMod item5 in list2) { string key = item5.ModName ?? group.GroupName ?? "mod"; if (!PatchedContent.ModDefinedTags.ContainsKey(key)) { PatchedContent.ModDefinedTags[key] = new List<ContentTag>(); } foreach (ExtendedContent extendedContent in item5.ExtendedContents) { if (extendedContent is ExtendedSegment extendedSegment) { LevelPack levelPack = new LevelPack { index = extendedSegment.index, replace = extendedSegment.replace, isVariant = extendedSegment.isVariant, biome = (extendedSegment.biome ?? string.Empty), bundlePath = group.GroupName, prefabName = (extendedSegment.prefabName ?? string.Empty), campfirePrefabName = (extendedSegment.campfirePrefabName ?? string.Empty), packName = (extendedSegment.packName ?? ((Object)extendedSegment).name ?? Guid.NewGuid().ToString()), id = (extendedSegment.id ?? Guid.NewGuid().ToString()), spawnMappings = (extendedSegment.ResolvedSpawnables?.Select(delegate(KeyValuePair<string, GameObject> kv) { SpawnMapping obj3 = new SpawnMapping { spawnerMarker = kv.Key }; GameObject value = kv.Value; obj3.spawnableName = ((value != null) ? ((Object)value).name : null) ?? ""; return obj3; }).ToArray() ?? Array.Empty<SpawnMapping>()) }; if ((Object)(object)PEAKLevelLoader.Instance != (Object)null) { PEAKLevelLoader.Instance.AddPacks(new LevelPackCollection { packs = new LevelPack[1] { levelPack } }); PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: registered ExtendedSegment " + levelPack.packName + " from group " + group.GroupName)); } } } PatchedContent.ExtendedMods.Add(item5); ContentTagManager.MergeExtendedModTags(item5); } { foreach (ExtendedSegment item6 in list4) { LevelPack levelPack2 = new LevelPack { index = item6.index, replace = item6.replace, isVariant = item6.isVariant, biome = (item6.biome ?? string.Empty), bundlePath = group.GroupName, prefabName = (item6.prefabName ?? string.Empty), campfirePrefabName = (item6.campfirePrefabName ?? string.Empty), packName = (item6.packName ?? ((Object)item6).name ?? Guid.NewGuid().ToString()), id = (item6.id ?? Guid.NewGuid().ToString()) }; if ((Object)(object)PEAKLevelLoader.Instance != (Object)null) { PEAKLevelLoader.Instance.AddPacks(new LevelPackCollection { packs = new LevelPack[1] { levelPack2 } }); } PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: registered ExtendedSegment " + levelPack2.packName + " from group " + group.GroupName)); } return; } } } catch (Exception arg) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: extended asset manifest load attempt failed for {group.GroupName}: {arg}"); } if ((Object)(object)val == (Object)null) { foreach (TextAsset item7 in list) { if (!((Object)(object)item7 == (Object)null) && !string.IsNullOrWhiteSpace(item7.text)) { string text = item7.text?.Trim(); if (!string.IsNullOrEmpty(text) && text.StartsWith("{") && text.Contains("modName")) { val = item7; break; } } } } if ((Object)(object)val != (Object)null) { try { string text2 = StringExtensions.SanitizeJson(val.text); ModJson modJson = JsonUtility.FromJson<ModJson>(text2) ?? new ModJson(); ModJsonSegment[] array = modJson.segments ?? Array.Empty<ModJsonSegment>(); if (array.Length == 0 && text2.IndexOf("\"segments\"", StringComparison.OrdinalIgnoreCase) >= 0) { PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: raw JSON contains 'segments' substring? True - attempting manual extraction for group " + group.GroupName + ".")); string text3 = StringExtensions.ExtractTopLevelArray(text2, "segments"); if (!string.IsNullOrEmpty(text3)) { List<string> list6 = StringExtensions.SplitTopLevelObjects(text3); List<ModJsonSegment> list7 = new List<ModJsonSegment>(); for (int i = 0; i < list6.Count; i++) { try { ModJsonSegment modJsonSegment = JsonUtility.FromJson<ModJsonSegment>(list6[i]); if (modJsonSegment != null) { list7.Add(modJsonSegment); } } catch (Exception arg2) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: manual parse failed for object {i} in group {group.GroupName}: {arg2}"); } } if (list7.Count > 0) { array = (modJson.segments = list7.ToArray()); PEAKLevelLoader.Logger.LogInfo((object)$"PEAKBundleManager: manual fallback parsed segments length = {array.Length} for group {group.GroupName}."); } else { PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: manual fallback found array but parsed 0 segment objects for group " + group.GroupName + ".")); } } else { PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: ExtractTopLevelArray didn't find a 'segments' array for group " + group.GroupName + ".")); } } if (modJson.segments != null && modJson.segments.Length != 0 && !string.IsNullOrEmpty(modJson.modName)) { if (string.IsNullOrWhiteSpace(modJson.version)) { PEAKLevelLoader.Logger.LogError((object)"PEAKBundleManager: The compatiblity version is not defined, please define the version entry...\nAdditionally, the version check will be added later."); } PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: Parsed mod.json from " + group.GroupName + ": " + modJson.modName)); ExtendedMod extendedMod = ExtendedMod.CreateNewMod(modJson.modName, modJson.author ?? "Unknown", modJson.version); Dictionary<string, ContentTag> dictionary = new Dictionary<string, ContentTag>(StringComparer.OrdinalIgnoreCase); if (modJson.contentTags != null) { string[] contentTags = modJson.contentTags; foreach (string text4 in contentTags) { if (!string.IsNullOrEmpty(text4) && !dictionary.ContainsKey(text4)) { dictionary[text4] = ContentTag.Create(text4); } } } if (modJson.spawnables != null) { ModJsonSpawnable[] spawnables = modJson.spawnables; foreach (ModJsonSpawnable modJsonSpawnable in spawnables) { if (!string.IsNullOrEmpty(modJsonSpawnable.name) && !string.IsNullOrEmpty(modJsonSpawnable.prefabName)) { string text5 = ((!string.IsNullOrEmpty(modJsonSpawnable.bundlePath)) ? modJsonSpawnable.bundlePath : (group.GroupName ?? modJson.modName ?? "unknown")); PatchedContent.SpawnableRegistry.Registry[modJsonSpawnable.name] = new PatchedContent.SpawnableEntry(text5, modJsonSpawnable.prefabName); PEAKLevelLoader.Logger.LogInfo((object)("Spawnable registered: '" + modJsonSpawnable.name + "' -> " + text5 + "::" + modJsonSpawnable.prefabName)); } } } array = modJson.segments ?? Array.Empty<ModJsonSegment>(); List<LevelPack> list8 = new List<LevelPack>(); ModJsonSegment[] array2 = array; foreach (ModJsonSegment modJsonSegment2 in array2) { LevelPack levelPack3 = new LevelPack { index = modJsonSegment2.index, replace = modJsonSegment2.replace, isVariant = modJsonSegment2.isVariant, biome = (modJsonSegment2.biome ?? string.Empty), bundlePath = group.GroupName, prefabName = (modJsonSegment2.segmentPrefab ?? string.Empty), campfirePrefabName = (modJsonSegment2.campfirePrefab ?? string.Empty), packName = modJson.modName + "_" + (modJsonSegment2.id ?? modJsonSegment2.index.ToString()), id = (modJsonSegment2.id ?? Guid.NewGuid().ToString()) }; levelPack3.spawnMappings = ((modJsonSegment2.spawnMappings != null) ? modJsonSegment2.spawnMappings.Select((ModJsonSpawnMapping sm) => new SpawnMapping { spawnerMarker = sm.spawnerMarker, spawnableName = sm.spawnableName }).ToArray() : Array.Empty<SpawnMapping>()); list8.Add(levelPack3); ExtendedSegment extendedSegment2 = ScriptableObject.CreateInstance<ExtendedSegment>(); ((Object)extendedSegment2).name = levelPack3.packName; extendedSegment2.index = levelPack3.index; extendedSegment2.replace = levelPack3.replace; extendedSegment2.isVariant = levelPack3.isVariant; extendedSegment2.biome = levelPack3.biome; extendedSegment2.prefabName = levelPack3.prefabName; extendedSegment2.campfirePrefabName = levelPack3.campfirePrefabName; extendedSegment2.packName = levelPack3.packName; extendedSegment2.id = levelPack3.id; extendedSegment2.ContentType = ContentType.Custom; foreach (KeyValuePair<string, ContentTag> item8 in dictionary) { extendedSegment2.ContentTags.Add(item8.Value); } extendedMod.TryRegisterExtendedContent(extendedSegment2); } LevelPackCollection newPacks = new LevelPackCollection { packs = list8.ToArray() }; if ((Object)(object)PEAKLevelLoader.Instance != (Object)null && list8.Count > 0) { PEAKLevelLoader.Instance.AddPacks(newPacks); PEAKLevelLoader.Logger.LogInfo((object)$"PEAKBundleManager: Added {list8.Count} LevelPack(s) to PEAKLevelLoader."); } else { PEAKLevelLoader.Logger.LogInfo((object)("PEAKBundleManager: no level packs to add for group " + group.GroupName + ".")); } string key2 = extendedMod.ModName ?? group.GroupName; if (!PatchedContent.ModDefinedTags.ContainsKey(key2)) { PatchedContent.ModDefinedTags[key2] = new List<ContentTag>(); } foreach (ContentTag value2 in dictionary.Values) { if (!PatchedContent.ModDefinedTags[key2].Contains(value2)) { PatchedContent.ModDefinedTags[key2].Add(value2); } } if (!PatchedContent.ModDefinedTags.ContainsKey(group.GroupName)) { PatchedContent.ModDefinedTags[group.GroupName] = new List<ContentTag>(PatchedContent.ModDefinedTags[key2]); } PatchedContent.ExtendedMods.Add(extendedMod); ContentTagManager.MergeExtendedModTags(extendedMod); ContentTagManager.MergeAllExtendedModTags(); ContentTagManager.PopulateContentTagData(); PatchedContent.SortExtendedMods(); PEAKLevelLoader.Logger.LogInfo((object)$"PEAKBundleManager: Registered runtime ExtendedMod for {modJson.modName} with {array.Length} segments and {dictionary.Count} tags."); } } catch (Exception arg3) { PEAKLevelLoader.Logger.LogWarning((object)$"PEAKBundleManager: failed to parse mod.json in {group.GroupName}: {arg3}"); } } foreach (AssetBundleInfo assetBundleInfo in group.GetAssetBundleInfos()) { string text6 = AssetBundleUtilities.ComputeSHA256(assetBundleInfo.AssetBundleFilePath); if (!string.IsNullOrEmpty(text6) && !PatchedContent.LoadedBundleHashes.Contains(text6)) { PatchedContent.LoadedBundleHashes.Add(text6); PatchedContent.LoadedBundleNames.Add(assetBundleInfo.AssetBundleName); } } } catch (Exception arg4) { PEAKLevelLoader.Logger.LogError((object)$"PEAKBundleManager.OnAssetBundleGroupCreated exception: {arg4}"); } } private static void OnAssetBundleLoadRequestFinished() { AssetBundleLoader.OnBundlesFinishedProcessing.RemoveListener(OnAssetBundleLoadRequestFinished); PEAKLevelLoader.Logger.LogInfo((object)"PEAKBundleManager: Finished processing bundles."); CurrentStatus = ModProcessingStatus.Complete; HasFinalisedFoundContent = true; PEAKBundleManager.OnFinishedProcessing?.Invoke(); } } internal static class PatchHooks { public static void ApplyPatches(Harmony harmony) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown try { Type type = Type.GetType("MapHandler") ?? Type.GetType("MapHandler, Assembly-CSharp"); if (type != null) { MethodInfo method = type.GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { HarmonyMethod val = new HarmonyMethod(typeof(PatchHooks).GetMethod("MapHandler_Awake_Postfix", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)method, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Debug.Log((object)"PatchHooks: patched MapHandler.Awake"); } } Type type2 = Type.GetType("MapBaker") ?? Type.GetType("MapBaker, Assembly-CSharp"); if (type2 != null) { MethodInfo method2 = type2.GetMethod("GetBiomeID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method2 != null) { HarmonyMethod val2 = new HarmonyMethod(typeof(PatchHooks).GetMethod("MapBaker_GetBiomeID_Postfix", BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)method2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Debug.Log((object)"PatchHooks: patched MapBaker.GetBiomeID"); } } } catch (Exception ex) { Debug.LogWarning((object)("PatchHooks.ApplyPatches failed: " + ex)); } } private static void MapHandler_Awake_Postfix(object __instance) { } private static void MapBaker_GetBiomeID_Postfix(object __instance, int levelIndex, ref string __result) { try { if ((Object)(object)PEAKLevelLoader.Instance == (Object)null) { return; } LevelPackCollection packs = PEAKLevelLoader.Instance.GetPacks(); if (packs == null || packs.packs == null) { return; } LevelPack[] packs2 = packs.packs; foreach (LevelPack levelPack in packs2) { if (levelPack != null && levelPack.index == levelIndex) { if (!string.IsNullOrEmpty(levelPack.biome)) { __result = levelPack.biome; } break; } } if (string.IsNullOrEmpty(__result)) { LevelPack[] packs3 = packs.packs; foreach (LevelPack levelPack2 in packs3) { } } } catch (Exception ex) { Debug.LogWarning((object)("MapBaker_GetBiomeID_Postfix error: " + ex)); } } } [BepInPlugin("off_grid.PEAKLevelLoader", "PEAKLevelLoader", "0.4.6")] public class PEAKLevelLoader : BaseUnityPlugin { internal static Harmony Harmony = new Harmony("off_grid.PEAKLevelLoader"); private LevelPackCollection _packs = new LevelPackCollection(); private AssetBundleLoader assetBundleLoader; public ConfigFile config; internal static bool AllowEmbeddedBundles = false; public static PEAKLevelLoader Instance { get; private set; } = null; internal static ManualLogSource Logger { get; private set; } = null; private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Instance = this; InitializeConfig(); Logger.LogWarning((object)"< Config initialized >"); Logger.LogInfo((object)"< PEAKLevelLoader main sector loaded... >"); Harmony.PatchAll(); PatchHooks.ApplyPatches(Harmony); GameObject val = new GameObject("PEAKLevelLoader-AssetBundleLoader"); assetBundleLoader = val.AddComponent<AssetBundleLoader>(); if (Application.isEditor) { Object.DontDestroyOnLoad((Object)(object)val); } else { ((Object)val).hideFlags = (HideFlags)61; } PEAKBundleManager.Start(); ((MonoBehaviour)this).StartCoroutine(WaitForMapHandlerAndApply()); Logger.LogInfo((object)"off_grid.PEAKLevelLoader v0.4.6 has fully loaded!"); } private void InitializeConfig() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "DAa Mods/PEAKLevelLoader"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } string text2 = Path.Combine(text, "config.cfg"); config = new ConfigFile(text2, true); if (config == null) { Logger.LogError((object)"The config file is null and the program cannot continue operations."); return; } string value = config.Bind<string>("Version", "Current Version", "", (ConfigDescription)null).Value; if (value != "0.4.6") { config.Clear(); } DefineConfig(); } private void DefineConfig() { config.Bind<string>("Version", "Current Version", "0.4.6", "Autoupdates the config / lets the mod know what version of config it is."); config.Bind<bool>("PEAKLevelLoader", "EnableCustoms", true, "Will custom segments load."); AllowEmbeddedBundles = config.Bind<bool>("PEAKLevelLoader", "AllowEmbeddedBundles", false, "If true, the loader will extract .pll resources embedded in already-loaded plugin assemblies. Not recommended due to extra memory usage.").Value; } public LevelPackCollection GetPacks() { return _packs ?? new LevelPackCollection(); } public void AddPacks(LevelPackCollection newPacks) { if (newPacks != null && newPacks.packs != null && newPacks.packs.Length != 0) { LevelPack[] first = _packs?.packs ?? Array.Empty<LevelPack>(); LevelPack[] source = first.Concat(newPacks.packs).ToArray(); LevelPack[] packs = (from p in source group p by (!string.IsNullOrEmpty(p.id)) ? p.id : p.packName into g select g.First()).ToArray(); _packs.packs = packs; Logger.LogInfo((object)$"PEAKLevelLoader: Added {newPacks.packs.Length} packs. Total unique packs: {_packs.packs.Length}"); } } private IEnumerator WaitForMapHandlerAndApply() { float timeout = 10f; float start = Time.realtimeSinceStartup; while ((Object)(object)Singleton<MapHandler>.Instance == (Object)null) { if (Time.realtimeSinceStartup - start > timeout) { yield break; } yield return null; } float start2 = Time.realtimeSinceStartup; while (!PEAKBundleManager.HasFinalisedFoundContent) { if (Time.realtimeSinceStartup - start2 > timeout * 3f) { Logger.LogWarning((object)"WaitForMapHandlerAndApply: timed out waiting for PEAKBundleManager to finish."); break; } yield return null; } try { ApplyPacksToMapHandler(Singleton<MapHandler>.Instance); } catch (Exception ex) { Logger.LogError((object)("Error applying packs to MapHandler: " + ex)); } } private IEnumerator EnsureGroupLoadedThenResolve(AssetBundleGroup group, string prefabCandidate, Action<GameObject?> onResolved) { if (group == null) { onResolved(null); yield break; } if (group.LoadedStatus != AssetBundleGroupLoadedStatus.Loaded) { try { group.TryLoadGroup(); } catch { } float start = Time.realtimeSinceStartup; float timeout = 10f; while (group.LoadedStatus != AssetBundleGroupLoadedStatus.Loaded) { if (Time.realtimeSinceStartup - start > timeout) { Logger.LogWarning((object)("EnsureGroupLoadedThenResolve: timed out loading group " + group.GroupName)); break; } yield return null; } } GameObject obj2 = AssetBundleGroupDebugger.ResolvePrefabFromGroup(group, prefabCandidate); onResolved(obj2); } public void ApplyPacksToMapHandler(MapHandler mapHandlerInstance) { ((MonoBehaviour)this).StartCoroutine(ApplyPacksToMapHandlerCoroutine(mapHandlerInstance)); } private IEnumerator ApplyPacksToMapHandlerCoroutine(MapHandler mapHandlerInstance) { if ((Object)(object)mapHandlerInstance == (Object)null || _packs == null || _packs.packs == null || _packs.packs.Length == 0) { yield break; } MapSegment[] source = mapHandlerInstance.segments ?? Array.Empty<MapSegment>(); List<MapSegment> originalList = source.ToList(); int origLen = originalList.Count; List<AssetBundleGroup> list = (assetBundleLoader?.AssetBundleGroups ?? AssetBundleLoader.Instance?.AssetBundleGroups)?.ToList() ?? new List<AssetBundleGroup>(); if (list.Count == 0) { Logger.LogWarning((object)"ApplyPacksToMapHandlerCoroutine: no AssetBundleGroups available."); } LevelPack[] packs = _packs.packs; foreach (LevelPack pack in packs) { GameObject resolvedPrefab = null; yield return ((MonoBehaviour)this).StartCoroutine(FindPrefabAcrossGroups(pack.prefabName, delegate(GameObject? prefab) { resolvedPrefab = prefab; })); if ((Object)(object)resolvedPrefab == (Object)null) { Logger.LogWarning((object)("ApplyPacksToMapHandler: couldn't find prefab '" + pack.prefabName + "' for pack '" + pack.packName + "'.")); yield return null; continue; } GameObject campfirePrefab = null; if (!string.IsNullOrEmpty(pack.campfirePrefabName)) { yield return ((MonoBehaviour)this).StartCoroutine(FindPrefabAcrossGroups(pack.campfirePrefabName, delegate(GameObject? prefab) { campfirePrefab = prefab; })); } GameObject val2; try { Transform globalParent = mapHandlerInstance.globalParent; val2 = Object.Instantiate<GameObject>(resolvedPrefab, globalParent); ((Object)val2).name = "ModSegment_" + pack.packName + "_" + pack.prefabName; } catch (Exception arg) { Logger.LogError((object)$"ApplyPacksToMapHandler: failed to instantiate prefab for pack {pack.packName}: {arg}"); continue; } MapSegment mapSegObj = (MapSegment)Activator.CreateInstance(typeof(MapSegment)); Type mapSegTypeLocal = typeof(MapSegment); object obj = null; if (!string.IsNullOrEmpty(pack.biome)) { try { obj = Enum.Parse(typeof(BiomeType), pack.biome, ignoreCase: true); } catch { obj = null; } } if (obj != null) { TrySetBackingField("_biome", obj); } TrySetBackingField("_segmentParent", val2); TrySetBackingField("_segmentCampfire", null); SpawnerHelper.RegisterSegmentContentsSync(val2, pack, campfirePrefab, mapSegObj, delegate(string name, object? val) { FieldInfo field8 = typeof(MapSegment).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field8 != null) { field8.SetValue(mapSegObj, val); } else { PropertyInfo property2 = typeof(MapSegment).GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null && property2.CanWrite) { property2.SetValue(mapSegObj, val); } } }); int insertionIndex = ((pack.index < origLen) ? pack.index : originalList.Count); PlaceholderProcessor.ProcessPlaceholdersSync(val2, pack, mapSegObj, insertionIndex); try { if ((Object)(object)campfirePrefab != (Object)null) { Transform val3 = val2.transform.Find("CampfireAnchor") ?? val2.transform.Find("campfireAnchor") ?? val2.transform.Find("Campfire") ?? ((IEnumerable<Transform>)val2.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf("campfire", StringComparison.OrdinalIgnoreCase) >= 0)); GameObject val4 = Object.Instantiate<GameObject>(campfirePrefab); ((Object)val4).name = "ModCampfire_" + pack.packName + "_" + pack.campfirePrefabName; Vector3 lossyScale = val4.transform.lossyScale; Transform val5 = (((Object)(object)val3 != (Object)null) ? val3 : val2.transform); Vector3 val6 = (((Object)(object)val5 != (Object)null) ? val5.lossyScale : Vector3.one); val6.x = (Mathf.Approximately(val6.x, 0f) ? 1f : val6.x); val6.y = (Mathf.Approximately(val6.y, 0f) ? 1f : val6.y); val6.z = (Mathf.Approximately(val6.z, 0f) ? 1f : val6.z); val4.transform.SetParent(val5, false); val4.transform.localScale = new Vector3(lossyScale.x / val6.x, lossyScale.y / val6.y, lossyScale.z / val6.z); if ((Object)(object)val3 != (Object)null) { val4.transform.localPosition = Vector3.zero; val4.transform.localRotation = Quaternion.identity; } TrySetBackingField("_segmentCampfire", val4); } Transform val7 = val2.transform.Find("ReconnectSpawnPos") ?? val2.transform.Find("reconnectSpawnPos") ?? ((IEnumerable<Transform>)val2.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf("reconnect", StringComparison.OrdinalIgnoreCase) >= 0)); if ((Object)(object)val7 != (Object)null) { FieldInfo field = typeof(MapSegment).GetField("reconnectSpawnPos", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(mapSegObj, val7); } } Transform val8 = val2.transform.Find("WallNext") ?? ((IEnumerable<Transform>)val2.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf("wallnext", StringComparison.OrdinalIgnoreCase) >= 0)); Transform val9 = val2.transform.Find("WallPrevious") ?? ((IEnumerable<Transform>)val2.GetComponentsInChildren<Transform>()).FirstOrDefault((Func<Transform, bool>)((Transform t) => ((Object)t).name.IndexOf("wallprevious", StringComparison.OrdinalIgnoreCase) >= 0)); if ((Object)(object)val8 != (Object)null) { FieldInfo field2 = typeof(MapSegment).GetField("wallNext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field2 != null) { field2.SetValue(mapSegObj, ((Component)val8).gameObject); } } if ((Object)(object)val9 != (Object)null) { FieldInfo field3 = typeof(MapSegment).GetField("wallPrevious", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field3 != null) { field3.SetValue(mapSegObj, ((Component)val9).gameObject); } } Type typeFromHandle = typeof(MapSegment); FieldInfo field4 = typeFromHandle.GetField("hasVariant", BindingFlags.Instance | BindingFlags.Public); FieldInfo field5 = typeFromHandle.GetField("variantBiome", BindingFlags.Instance | BindingFlags.Public); FieldInfo field6 = typeFromHandle.GetField("isVariant", BindingFlags.Instance | BindingFlags.Public); if (field4 != null) { field4.SetValue(mapSegObj, pack.isVariant); } if (field6 != null) { field6.SetValue(mapSegObj, pack.isVariant); } if (field5 != null && obj != null && pack.isVariant) { field5.SetValue(mapSegObj, obj); } if (pack.index < origLen) { if (pack.replace) { originalList[pack.index] = mapSegObj; } else { originalList.Insert(pack.index + 1, mapSegObj); } } else { originalList.Add(mapSegObj); } string text = ((!string.IsNullOrEmpty(pack.bundlePath)) ? pack.bundlePath : pack.packName); if (!string.IsNullOrEmpty(text) && PatchedContent.ModDefinedTags != null && PatchedContent.ModDefinedTags.TryGetValue(text, out List<ContentTag> value2) && value2 != null && value2.Count > 0) { ModContentTagMarker modContentTagMarker = val2.GetComponent<ModContentTagMarker>() ?? val2.AddComponent<ModContentTagMarker>(); modContentTagMarker.tags = value2.ToArray(); } } catch (Exception arg2) { Logger.LogError((object)$"ApplyPacksToMapHandler error for pack {pack.packName}: {arg2}"); } yield return null; void TrySetBackingField(string fieldName, object? value) { FieldInfo field7 = mapSegTypeLocal.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field7 != null) { try { Type fieldType = field7.FieldType; if (value == null) { field7.SetValue(mapSegObj, null); return; } if (fieldType.IsAssignableFrom(value.GetType())) { field7.SetValue(mapSegObj, value); return; } if (fieldType == typeof(Transform)) { GameObject val10 = (GameObject)((value is GameObject) ? value : null); if (val10 != null) { field7.SetValue(mapSegObj, val10.transform); return; } } if (fieldType == typeof(GameObject)) { Transform val11 = (Transform)((value is Transform) ? value : null); if (val11 != null) { field7.SetValue(mapSegObj, ((Component)val11).gameObject); return; } } Logger.LogWarning((object)("TrySetBackingField: type mismatch for " + fieldName + ".")); } catch (Exception arg3) { Logger.LogWarning((object)$"TrySetBackingField: {arg3}"); } } PropertyInfo property = mapSegTypeLocal.GetProperty(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite) { try { Type propertyType = property.PropertyType; if (value == null) { property.SetValue(mapSegObj, null); } else if (propertyType.IsAssignableFrom(value.GetType())) { property.SetValue(mapSegObj, value); } else { if (propertyType == typeof(Transform)) { GameObject val12 = (GameObject)((value is GameObject) ? value : null); if (val12 != null) { property.SetValue(mapSegObj, val12.transform); return; } } if (propertyType == typeof(GameObject)) { Transform val13 = (Transform)((value is Transform) ? value : null); if (val13 != null) { property.SetValue(mapSegObj, ((Component)val13).gameObject); return; } } Logger.LogWarning((object)("TrySetBackingField(prop): type mismatch for " + fieldName + ".")); } } catch (Exception arg4) { Logger.LogWarning((object)$"TrySetBackingField(prop): {arg4}"); } } } } MapSegment[] array = (mapHandlerInstance.segments = originalList.ToArray()); if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient) { Logger.LogInfo((object)" < Awaiting for sync from non host clients. > "); LevelPack[] packs2 = _packs.packs; PEAKPackSyncPhoton instance = PEAKPackSyncPhoton.Instance; if ((Object)(object)instance != (Object)null) { instance.SendPacksToClients(packs2, waitForAcks: true, delegate(bool success) { if (!success) { Logger.LogWarning((object)"Not all clients ACK'd pack application in time."); } else { Logger.LogInfo((object)"All clients acknowledged pack application."); } }); } else { Logger.LogWarning((object)"PEAKPackSyncPhoton.Instance is null. Ensure it exists in scene and is created in Awake."); } } Logger.LogInfo((object)$"ApplyPacksToMapHandler: finished applying packs, segments length {array.Length}"); } private IEnumerator FindPrefabAcrossGroups(string prefabName, Action<GameObject?> onFound) { GameObject found = null; List<AssetBundleGroup> list = assetBundleLoader?.AssetBundleGroups ?? AssetBundleLoader.Instance?.AssetBundleGroups; if (list == null) { onFound(null); yield break; } foreach (AssetBundleGroup item in list) { if (item == null) { continue; } AssetBundleGroup assetBundleGroup = item; if (assetBundleGroup != null) { yield return ((MonoBehaviour)this).StartCoroutine(EnsureGroupLoadedThenResolve(assetBundleGroup, prefabName, delegate(GameObject? prefab) { found = prefab; })); if ((Object)(object)found != (Object)null) { break; } } } onFound(found); } internal static void TrySoftPatch(string pluginName, Type type) { if (Chainloader.PluginInfos.ContainsKey(pluginName)) { Harmony.CreateClassProcessor(type, true).Patch(); Logger.LogInfo((object)(pluginName + " found, enabling compatability patches.")); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "off_grid.PEAKLevelLoader"; public const string PLUGIN_NAME = "PEAKLevelLoader"; public const string PLUGIN_VERSION = "0.4.6"; } } namespace PEAKLevelLoader.Patches { [HarmonyPatch(typeof(MapHandler))] internal class MapHandlerPatch { [HarmonyPostfix] [HarmonyPatch("Awake")] private static void Postfix_Awake(MapHandler __instance) { try { if ((Object)(object)PEAKLevelLoader.Instance != (Object)null) { PEAKLevelLoader.Instance.ApplyPacksToMapHandler(__instance); try { typeof(MapHandler).GetMethod("DetectBiomes", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(__instance, null); return; } catch (Exception arg) { PEAKLevelLoader.Logger.LogWarning((object)$"DetectBiomes failed after ApplyPacks: {arg}"); return; } } PEAKLevelLoader.Logger.LogWarning((object)"PEAKLevelLoader.Instance is null — can't apply packs yet."); } catch (Exception arg2) { PEAKLevelLoader.Logger.LogErr