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 PEAKLevelLoader v0.4.6
off_grid.PEAKLevelLoader.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.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