Decompiled source of OtherLoaderPatched v1.5.1
patchers\Sirdoggy.OldOtherLoaderDisabler.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using Microsoft.CodeAnalysis; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("Sirdoggy")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Sirdoggy.OldOtherLoaderDisabler")] [assembly: AssemblyTitle("OldOtherLoaderDisabler")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Sirdoggy.OldOtherLoaderDisabler { public static class OldOtherLoaderDisablerPatcher { private const string OtherLoaderDirectoryName = "devyndamonster-OtherLoader"; private const string OtherLoaderDllFullName = "OtherLoader.dll"; private const string OtherLoaderDllFullNameDisabled = "OtherLoader.dll.old"; private const string ManifestFullNameDisabled = "manifest.json.old"; private static readonly ManualLogSource Log = Logger.CreateLogSource("OldOtherLoaderDisabler"); public static IEnumerable<string> TargetDLLs => Enumerable.Empty<string>(); internal static void Initialize() { try { Log.LogMessage((object)"Attempting to disable original OtherLoader. Looking for BepInEx/plugins/devyndamonster-OtherLoader/OtherLoader.dll"); string text = Directory.GetDirectories(Paths.PluginPath, "devyndamonster-OtherLoader", SearchOption.TopDirectoryOnly).FirstOrDefault(); if (text == null) { Log.LogMessage((object)"Original OtherLoader not found in plugins directory, it's likely not installed, aborting..."); return; } string text2 = Path.Combine(text, "OtherLoader.dll"); string text3 = Path.Combine(text, "OtherLoader.dll.old"); if (!File.Exists(text2)) { Log.LogMessage((object)"Did not resolve 'OtherLoader.dll', OtherLoader is likely disabled, aborting..."); return; } if (File.Exists(text3)) { File.Delete(text3); } File.Move(text2, text3); Log.LogMessage((object)"Successfully disabled original OtherLoader!"); } catch (Exception arg) { Log.LogError((object)$"Exception when trying to disable original OtherLoader: {arg}"); } } public static void RestoreOtherLoaderDll() { try { Log.LogMessage((object)"Attempting to restore original OtherLoader dll"); string text = Directory.GetDirectories(Paths.PluginPath, "devyndamonster-OtherLoader", SearchOption.TopDirectoryOnly).FirstOrDefault(); if (text == null) { Log.LogMessage((object)"Original OtherLoader not found in plugins directory, it's likely not installed, aborting..."); return; } if (File.Exists(Path.Combine(text, "manifest.json.old"))) { Log.LogMessage((object)"OtherLoader has been disabled in mod manager, aborting..."); return; } string text2 = Path.Combine(text, "OtherLoader.dll.old"); string text3 = Path.Combine(text, "OtherLoader.dll"); if (!File.Exists(text2)) { Log.LogMessage((object)("Did not resolve 'OtherLoader.dll.old' from path " + text2)); } else if (File.Exists(text3)) { Log.LogWarning((object)"Duplicate dlls exist, this shouldn't happen. Deleting dll.old and exiting..."); File.Delete(text2); } else { File.Move(text2, text3); Log.LogMessage((object)"Successfully restored original OtherLoader dll!"); } } catch (Exception arg) { Log.LogError((object)$"Exception when restoring original OtherLoader dll: {arg}"); } } public static void Patch(AssemblyDefinition _) { } } }
OtherLoader.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.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FistVR; using HarmonyLib; using Microsoft.CodeAnalysis; using OtherLoader.Common; using OtherLoader.Common.FVR; using OtherLoader.ConsoleLogs; using OtherLoader.ItemSpawner; using OtherLoader.ItemSpawner.CustomCategories; using OtherLoader.ItemSpawner.Patches; using OtherLoader.ItemSpawner.SecondaryObjectsLinker; using OtherLoader.ItemSpawner.VanillaCategories; using OtherLoader.Loading; using OtherLoader.Loading.AssetLoaders; using OtherLoader.Loading.AssetLoaders.Implementations; using OtherLoader.Loading.Model; using OtherLoader.PortableItemSpawner; using OtherLoader.QuickbeltPanel; using OtherLoader.UnlockAllItems; using Sirdoggy.OldOtherLoaderDisabler; using Sodalite; using Sodalite.Api; using Sodalite.ModPanel; using Stratum; using Stratum.Extensions; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("OtherLoader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("OtherLoader")] [assembly: AssemblyTitle("OtherLoader")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class ParamCollectionAttribute : Attribute { } [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; } } } namespace OtherLoader { [CreateAssetMenu(menuName = "MeatKit/Otherloader/SpawnerEntry", fileName = "New Spawner Entry")] public class ItemSpawnerEntry : ScriptableObject { [Header("Item IDs")] [Tooltip("ItemID for the main object that will spawn")] public string MainObjectID; [Tooltip("ItemIDs for items that will spawn alongside the main object")] public List<string> SpawnWithIDs = new List<string>(); [Tooltip("ItemIDs for items that appear in the secondary items section")] public List<string> SecondaryObjectIDs = new List<string>(); [Header("[OPTIONAL] Populate ItemIDs using FVRObjects directly")] public FVRObject? MainObjectObj; public List<FVRObject> SpawnWithObjs = new List<FVRObject>(); public List<FVRObject> SecondaryObjs = new List<FVRObject>(); [Header("Entry Path Properties")] [Tooltip("The path for the entry")] public string EntryPath; public PageMode Page; public ESubCategory SubCategory; [Header("Display Properties")] [Tooltip("The icon that will appear in the spawner for this entry")] public Sprite EntryIcon; [Tooltip("The name of the entry")] public string DisplayName; [Tooltip("Decides wether the entry will be visible in the spawner.\n Set to false if you only want the entry visible as a secondary")] public bool IsDisplayedInMainEntry; [Tooltip("A list modding tags to allow for sorting by mod groups in itemspawner")] public List<string> ModTags = new List<string>(); [Tooltip("A list of tutorial block IDs that will appear when this entry is selected")] public List<string> TutorialBlockIDs = new List<string>(); [Header("Misc Properties")] public bool UsesLargeSpawnPad; public bool UsesHugeSpawnPad; public bool IsReward; internal bool IsUncategorized; public static ItemSpawnerEntry CreateEmpty(string path) { ItemSpawnerEntry itemSpawnerEntry = ScriptableObject.CreateInstance<ItemSpawnerEntry>(); itemSpawnerEntry.EntryPath = path; return itemSpawnerEntry; } public void PopulateIDsFromObj() { if ((Object)(object)MainObjectObj != (Object)null) { MainObjectID = MainObjectObj.ItemID; OtherLogger.Log("Assigned MainObjectID '" + MainObjectID + "' from MainObjectObj.ItemID", LogTag.Assets); } foreach (FVRObject spawnWithObj in SpawnWithObjs) { if (!SpawnWithIDs.Contains(spawnWithObj.ItemID)) { SpawnWithIDs.Add(spawnWithObj.ItemID); } } foreach (FVRObject secondaryObj in SecondaryObjs) { if (!SecondaryObjectIDs.Contains(secondaryObj.ItemID)) { SecondaryObjectIDs.Add(secondaryObj.ItemID); } } } public bool IsCategoryEntry() { return string.IsNullOrEmpty(MainObjectID); } internal ESubCategory? GetSpawnerSubcategory() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) string[] array = (from o in EntryPath.Split(new char[1] { '/' }) where Enum.IsDefined(typeof(ESubCategory), o) select o).ToArray(); if (array.Length == 0) { return null; } return ((IEnumerable<string>)array).Select((Func<string, ESubCategory>)((string o) => (ESubCategory)Enum.Parse(typeof(ESubCategory), o))).FirstOrDefault(); } internal EItemCategory? GetSpawnerCategory() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) string[] array = (from o in EntryPath.Split(new char[1] { '/' }) where Enum.IsDefined(typeof(EItemCategory), o) select o).ToArray(); if (array.Length == 0) { return null; } return ((IEnumerable<string>)array).Select((Func<string, EItemCategory>)((string o) => (EItemCategory)Enum.Parse(typeof(EItemCategory), o))).FirstOrDefault(); } } public delegate void StatusUpdate(float progress); internal enum LoadOrderType { LoadFirst, LoadLast, LoadUnordered } internal enum BundleStatus { Waiting, CanLoad, Loading, Loaded, Unloaded } internal class BundleLoadStatus { public readonly string BundleId; public BundleStatus Status; public LoadOrderType LoadOrderType; public BundleLoadStatus(string bundleId, LoadOrderType loadOrderType) { BundleId = bundleId; LoadOrderType = loadOrderType; Status = BundleStatus.Waiting; } } public static class LoaderStatus { private class ModLoadOrderContainer { public List<BundleLoadStatus> loadFirst = new List<BundleLoadStatus>(); public List<BundleLoadStatus> loadUnordered = new List<BundleLoadStatus>(); public List<BundleLoadStatus> loadLast = new List<BundleLoadStatus>(); public Dictionary<string, BundleLoadStatus> bundleLoadStatusDic = new Dictionary<string, BundleLoadStatus>(); public void AddToLoadOrder(string bundleID, LoadOrderType loadOrderType) { BundleLoadStatus bundleLoadStatus = new BundleLoadStatus(bundleID, loadOrderType); if (bundleLoadStatusDic.ContainsKey(bundleID)) { BundleLoadStatus bundleLoadStatus2 = bundleLoadStatusDic[bundleID]; bundleLoadStatusDic.Remove(bundleID); loadFirst.Remove(bundleLoadStatus2); loadUnordered.Remove(bundleLoadStatus2); loadLast.Remove(bundleLoadStatus2); bundleLoadStatus.Status = BundleStatus.Unloaded; bundleLoadStatus.LoadOrderType = bundleLoadStatus2.LoadOrderType; if (bundleLoadStatus2.Status != BundleStatus.Loaded && bundleLoadStatus2.Status != BundleStatus.Unloaded) { OtherLogger.LogError("Tracking a late bundle, but the data bundle isn't already loaded! Data bundle status: " + bundleLoadStatus2.Status); } } else { if (loadOrderType == LoadOrderType.LoadFirst) { if (loadFirst.Count == 0 || loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded)) { bundleLoadStatus.Status = BundleStatus.CanLoad; } if (loadUnordered.Count != 0 || loadLast.Count != 0) { OtherLogger.LogError("Mod is set to load first, but it looks like unordered or load last mods are already loading! BundleID (" + bundleID + ")"); loadUnordered.ForEach(delegate(BundleLoadStatus o) { OtherLogger.LogError("Load Unordered BundleID (" + o.BundleId + ")"); }); loadLast.ForEach(delegate(BundleLoadStatus o) { OtherLogger.LogError("Load Last BundleID (" + o.BundleId + ")"); }); } } if (loadOrderType == LoadOrderType.LoadUnordered) { if (loadFirst.Count == 0 || loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded)) { bundleLoadStatus.Status = BundleStatus.CanLoad; } if (loadLast.Count != 0) { OtherLogger.LogError("Mod is set to load unordered, but it looks like load last mods are already loading! BundleID (" + bundleID + ")"); loadLast.ForEach(delegate(BundleLoadStatus o) { OtherLogger.LogError("Load Last BundleID (" + o.BundleId + ")"); }); } } if (loadOrderType == LoadOrderType.LoadLast && ((loadFirst.Count == 0 && loadUnordered.Count == 0 && loadLast.Count == 0) || (loadFirst.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && loadUnordered.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && loadLast.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded)))) { bundleLoadStatus.Status = BundleStatus.CanLoad; } } bundleLoadStatusDic.Add(bundleID, bundleLoadStatus); switch (loadOrderType) { case LoadOrderType.LoadFirst: loadFirst.Add(bundleLoadStatus); break; case LoadOrderType.LoadLast: loadLast.Add(bundleLoadStatus); break; case LoadOrderType.LoadUnordered: loadUnordered.Add(bundleLoadStatus); break; } } public BundleStatus? TryGetBundleLoadStatus(string bundleID) { return bundleLoadStatusDic.GetValueOrNull(bundleID)?.Status; } public void MarkBundleAsLoaded(string bundleID, bool permanentlyLoaded) { BundleLoadStatus bundleLoadStatus = bundleLoadStatusDic[bundleID]; if (permanentlyLoaded) { bundleLoadStatus.Status = BundleStatus.Loaded; } else { bundleLoadStatus.Status = BundleStatus.Unloaded; } if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadFirst) { BundleLoadStatus bundleLoadStatus2 = loadFirst.FirstOrDefault((BundleLoadStatus o) => o.Status == BundleStatus.Waiting); if (bundleLoadStatus2 != null) { bundleLoadStatus2.Status = BundleStatus.CanLoad; } else if (loadUnordered.Count > 0) { loadUnordered.ForEach(delegate(BundleLoadStatus o) { o.Status = BundleStatus.CanLoad; }); } else if (loadLast.Count > 0) { loadLast[0].Status = BundleStatus.CanLoad; } } else if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadUnordered) { if (loadUnordered.All((BundleLoadStatus o) => o.Status == BundleStatus.Loaded || o.Status == BundleStatus.Unloaded) && loadLast.Count != 0) { loadLast[0].Status = BundleStatus.CanLoad; } } else if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadLast) { BundleLoadStatus bundleLoadStatus3 = loadLast.FirstOrDefault((BundleLoadStatus o) => o.Status == BundleStatus.Waiting); if (bundleLoadStatus3 != null) { bundleLoadStatus3.Status = BundleStatus.CanLoad; } } } public List<BundleLoadStatus> GetBundleDependencies(string bundleID) { List<BundleLoadStatus> list = new List<BundleLoadStatus>(); BundleLoadStatus bundleLoadStatus = bundleLoadStatusDic[bundleID]; if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadFirst) { foreach (BundleLoadStatus item in loadFirst) { if (item.BundleId == bundleID) { break; } if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item.BundleId)) { list.Add(item); } } } else if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadUnordered) { foreach (BundleLoadStatus item2 in loadFirst) { if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item2.BundleId)) { list.Add(item2); } } } else if (bundleLoadStatus.LoadOrderType == LoadOrderType.LoadLast) { foreach (BundleLoadStatus item3 in loadFirst) { if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item3.BundleId)) { list.Add(item3); } } foreach (BundleLoadStatus item4 in loadUnordered) { if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item4.BundleId)) { list.Add(item4); } } foreach (BundleLoadStatus item5 in loadLast) { if (item5.BundleId == bundleID) { break; } if (!AnvilManager.m_bundles.m_lookup.ContainsKey(item5.BundleId)) { list.Add(item5); } } } return list; } } internal static float LastLoadEventTime; private static float? _lastStatus; private static StatusUpdate? _progressUpdatedReplayingListeners; private static readonly Dictionary<string, float> TrackedLoaders = new Dictionary<string, float>(); private static readonly List<string> ActiveLoaders = new List<string>(); private static readonly Dictionary<string, ModLoadOrderContainer> OrderedLoadingLists = new Dictionary<string, ModLoadOrderContainer>(); private static float _loadStartTime; private const float LoadTimeBuffer = 2f; public static event StatusUpdate? ProgressUpdated; public static event StatusUpdate? ProgressUpdatedReplaying { add { _progressUpdatedReplayingListeners = (StatusUpdate)Delegate.Combine(_progressUpdatedReplayingListeners, value); float? lastStatus = _lastStatus; if (lastStatus.HasValue) { value?.Invoke(_lastStatus.Value); } } remove { _progressUpdatedReplayingListeners = (StatusUpdate)Delegate.Remove(_progressUpdatedReplayingListeners, value); } } private static void DoStatusUpdate(float status) { _lastStatus = status; _progressUpdatedReplayingListeners?.Invoke(status); LoaderStatus.ProgressUpdated?.Invoke(status); } public static float GetLoaderProgress() { if (TrackedLoaders.Count == 0) { return 0f; } float num = 0f; foreach (float value in TrackedLoaders.Values) { num += value; } if (Time.realtimeSinceStartup - LastLoadEventTime > 2f) { return num / (float)TrackedLoaders.Count; } return Mathf.Min(num / (float)TrackedLoaders.Count, 0.99f); } internal static IEnumerator LoadTimeCoroutine() { LastLoadEventTime = Time.realtimeSinceStartup; float progress; for (progress = GetLoaderProgress(); progress < 1f; progress = GetLoaderProgress()) { yield return null; DoStatusUpdate(progress); } DoStatusUpdate(progress); OtherLogger.Log($"All items loaded, took {Time.realtimeSinceStartup - _loadStartTime:0.000} seconds!"); } internal static void AddActiveLoader(string bundleID) { if (!ActiveLoaders.Contains(bundleID)) { ActiveLoaders.Add(bundleID); } } internal static void RemoveActiveLoader(string bundleID, bool permanentlyLoaded) { if (ActiveLoaders.Contains(bundleID)) { ActiveLoaders.Remove(bundleID); string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); OrderedLoadingLists[modPathFromUniqueID].MarkBundleAsLoaded(bundleID, permanentlyLoaded); LastLoadEventTime = Time.realtimeSinceStartup; } } internal static void TrackLoader(string bundleID, LoadOrderType loadOrderType) { if (TrackedLoaders.Count == 0) { _loadStartTime = Time.realtimeSinceStartup; OtherLoader.CoroutineStarter.Invoke(LoadTimeCoroutine()); } LastLoadEventTime = Time.realtimeSinceStartup; if (!TrackedLoaders.ContainsKey(bundleID)) { TrackedLoaders.Add(bundleID, 0f); } string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); if (!OrderedLoadingLists.ContainsKey(modPathFromUniqueID)) { OtherLogger.Log("Adding new load order entry for mod", LogTag.BundleLoading); OrderedLoadingLists.Add(modPathFromUniqueID, new ModLoadOrderContainer()); } OrderedLoadingLists[modPathFromUniqueID].AddToLoadOrder(bundleID, loadOrderType); OtherLogger.Log($"Tracking modded bundle ({bundleID}), Load Order ({loadOrderType})", LogTag.BundleLoading); } internal static bool IsBundleAlreadyTracked(string bundleID) { string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); return (OrderedLoadingLists.GetValueOrNull(modPathFromUniqueID)?.TryGetBundleLoadStatus(bundleID)).HasValue; } internal static bool CanOrderedModLoad(string bundleID) { string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); BundleStatus? bundleStatus = (OrderedLoadingLists.GetValueOrNull(modPathFromUniqueID) ?? throw new Exception("Mod was not found in load order! BundleID: " + bundleID)).TryGetBundleLoadStatus(bundleID); if (!bundleStatus.HasValue) { throw new Exception("BundleID was not found in mod load order container: " + bundleID); } if (bundleStatus.GetValueOrDefault() == BundleStatus.Loaded || bundleStatus.GetValueOrDefault() == BundleStatus.Unloaded) { throw new Exception("BundleID is already loaded/unloaded: " + bundleID); } bool flag = bundleStatus.GetValueOrDefault() == BundleStatus.CanLoad; return (PluginConfig.MaxActiveLoaders <= 0 || ActiveLoaders.Count < PluginConfig.MaxActiveLoaders) && flag; } internal static void PrintWaitingBundles(string bundleID) { OtherLogger.Log("Current Active Loaders: " + ActiveLoaders.Count); string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); foreach (BundleLoadStatus item in (from o in OrderedLoadingLists[modPathFromUniqueID].GetBundleDependencies(bundleID) where o.Status != BundleStatus.Loaded && o.Status != BundleStatus.Unloaded select o).ToList()) { OtherLogger.Log("Waiting on bundle: " + item.BundleId + ", Status: " + item.Status); } } internal static void UpdateProgress(string bundleID, float progress) { if (TrackedLoaders.ContainsKey(bundleID)) { TrackedLoaders[bundleID] = progress; } } internal static List<BundleLoadStatus> GetBundleDependencies(string bundleID) { string modPathFromUniqueID = GetModPathFromUniqueID(bundleID); return OrderedLoadingLists[modPathFromUniqueID].GetBundleDependencies(bundleID); } private static string GetModPathFromUniqueID(string bundleID) { return bundleID.Split(new string[1] { " : " }, StringSplitOptions.None)[0].Trim(); } } [BepInPlugin("h3vr.otherloader", "OtherLoaderPatched", "1.5.1")] [BepInDependency("stratum", "1.1.0")] [BepInDependency("nrgill28.Sodalite", "1.4.1")] public class OtherLoader : StratumPlugin { private class DirectLoadMod { public readonly string Path; public readonly string LoadFirst; public readonly string LoadAny; public readonly string LoadLast; public DirectLoadMod(string path, string loadFirst, string loadAny, string loadLast) { Path = path; LoadFirst = loadFirst; LoadAny = loadAny; LoadLast = loadLast; base..ctor(); } } private const string OtherLoaderVersion = "1.5.1"; public static readonly Dictionary<string, ItemSpawnerEntry> SpawnerEntriesByID = new Dictionary<string, ItemSpawnerEntry>(); internal static readonly Dictionary<string, string> ManagedBundles = new Dictionary<string, string>(); internal static CoroutineStarter CoroutineStarter = null; internal static ExceptionCatcher ExceptionCatcher = null; private static readonly List<DirectLoadMod> DirectLoadMods = new List<DirectLoadMod>(); private void Awake() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown CoroutineStarter = new CoroutineStarter(((MonoBehaviour)this).StartCoroutine); ExceptionCatcher = new ExceptionCatcher(((BaseUnityPlugin)this).Logger); OtherLogger.Initialize(((BaseUnityPlugin)this).Logger); PluginConfig.Initialize(((BaseUnityPlugin)this).Info); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(LogLevelColorPatcher), (string)null); }); if (PluginConfig.ItemUnlocker != 0) { ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(RewardUnlocksPatchers), (string)null); }); } ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(PortableSpawnerPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(AnvilRuntimeLoadingPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(QuickbeltPanelPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2InitialPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2SimpleModePatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2SpawningPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2DisplayItemsPatcher), (string)null); }); ExceptionCatcher.Run(delegate { Harmony.CreateAndPatchAll(typeof(ItemSpawnerV2TagsFromHeldPatcher), (string)null); }); if (PluginConfig.AddUnloadButton) { WristMenuAPI.Buttons.Add(new WristMenuButton("Unload Bundles", (ButtonClickEvent)delegate { UnloadAllModdedBundles(); })); } } private void Start() { GM.SetRunningModded(); OldOtherLoaderDisablerPatcher.RestoreOtherLoaderDll(); } public override void OnSetup(IStageContext<Empty> ctx) { ctx.Loaders.Add("icon", (FileSystemInfo _) => default(Empty)); ctx.Loaders.Add("assembly", MainLoader.LoadAssembly); } public override IEnumerator OnRuntime(IStageContext<IEnumerator> ctx) { ctx.Loaders.Add("item_data", MainLoader.BundlePrepareLate); ctx.Loaders.Add("item_first_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrderType.LoadFirst)); ctx.Loaders.Add("item_unordered_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrderType.LoadUnordered)); ctx.Loaders.Add("item_last_late", (FileSystemInfo handle) => MainLoader.BundleRegisterLate(handle, LoadOrderType.LoadLast)); ctx.Loaders.Add("item", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrderType.LoadFirst)); ctx.Loaders.Add("item_unordered", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrderType.LoadUnordered)); ctx.Loaders.Add("item_last", (FileSystemInfo handle) => MainLoader.BundleLoadImmediate(handle, LoadOrderType.LoadLast)); MainLoader.LoadLegacyBundles(); foreach (DirectLoadMod directLoadMod in DirectLoadMods) { MainLoader.BundleLoadDirectFromDirectory(directLoadMod.Path, directLoadMod.LoadFirst.Split(new char[1] { ',' }), directLoadMod.LoadAny.Split(new char[1] { ',' }), directLoadMod.LoadLast.Split(new char[1] { ',' })); } DirectLoadMods.Clear(); LoaderStatus.ProgressUpdated += OnLoaderProgress; yield break; } private static void OnLoaderProgress(float progress) { if (!(progress < 1f)) { LoaderStatus.ProgressUpdated -= OnLoaderProgress; ItemSpawnerIDLinker.LinkQueuedEntries(); ItemManagerDebugger.TryPrintEntries(); SpawnerTilesDatabase.TryCreateTestCategories(); } } public static void RegisterDirectLoad(string path, string guid, string dependancies, string loadFirst, string loadAny, string loadLast) { DirectLoadMods.Add(new DirectLoadMod(path, loadFirst, loadAny, loadLast)); } private void UnloadAllModdedBundles() { foreach (string item in ManagedBundles.Keys.Where((string bundleID) => AnvilManager.m_bundles.m_lookup.ContainsKey(bundleID))) { OtherLogger.Log("Unloading bundle '" + item + "'"); AnvilCallback<AssetBundle> val = (AnvilCallback<AssetBundle>)(object)AnvilManager.m_bundles.m_lookup[item]; AnvilManager.m_bundles.m_loading.Remove((AnvilCallbackBase)(object)val); AnvilManager.m_bundles.m_lookup.Remove(item); val.Result.Unload(false); } } } internal static class PluginAssets { private const string PluginFolderName = "Sirdoggy-OtherLoaderPatched"; private static readonly string AssetsRelativePath = Path.Combine("Sirdoggy-OtherLoaderPatched", "assets"); private static readonly string AssetsFullPath = Path.Combine(Paths.PluginPath, AssetsRelativePath); public static readonly Sprite? UnknownFolder = SpriteMaker.CreateFromImage(Path.Combine(AssetsFullPath, "UnknownFolder.png")); public static readonly Sprite? Shapes = SpriteMaker.CreateFromImage(Path.Combine(AssetsFullPath, "Shapes.png")); public static string CustomCategoriesHeaderLabel => "Modded Categories"; public static string CustomCategoriesButtonLabel(int? count) { return $"MODDED CATEGORIES ({count.GetValueOrDefault()})"; } public static string ModsLoadingProgressLabel(int percentage) { return $"Loading mods | {percentage}%"; } } internal static class PluginConfig { public static bool OptimizeMemory; public static int MaxActiveLoaders; public static ItemUnlockerMode ItemUnlocker; public static ConfigEntry<bool> PreventSelectingModTagsFromHeldObject; public static ConfigEntry<bool> ShowSpawnItemButtonInPortableSpawner; public static ConfigEntry<ItemSpawnerSortGrouping> ItemSpawnerSortGrouping; public static ConfigEntry<ItemSpawnerSortOrder> ItemSpawnerSortOrder; public static ConfigEntry<bool> ColoredLogs; public static ConfigEntry<LogTag> LogTags; public static bool AddUnloadButton; public static bool EnableLogTraces; public static bool ShowDebugItemSpawnerEntries; private static ConfigFile _configFile; private const string ConfigFileName = "OtherLoaderPatched.cfg"; public static void Initialize(PluginInfo pluginInfo) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown _configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "OtherLoaderPatched.cfg"), true); BindFields(); UniversalModPanel.RegisterPluginSettings(pluginInfo, _configFile); } public static void BindFields() { OptimizeMemory = _configFile.Bind<bool>("General", "OptimizeMemory", true, "When true, modded assets will be loaded on-demand instead of kept in memory. Requires game restart.").Value; MaxActiveLoaders = _configFile.Bind<int>("General", "MaxActiveLoaders", 6, "Sets the number of mods that can be loading at once when first launching the game. Values less than 1 will result in all mods being loaded at the same time.").Value; ItemUnlocker = _configFile.Bind<ItemUnlockerMode>("General", "ItemUnlocker", ItemUnlockerMode.Disabled, "Cheat. Unlocks all reward/hidden items, including ones that can only spawn in T&H. Using this won't affect your H3VR save file. Requires game restart.").Value; PreventSelectingModTagsFromHeldObject = _configFile.Bind<bool>("General", "PreventSelectingModTagsFromHeldObject", true, "ModTags will be skipped when using the 'Select Tags From Held Object' button."); ShowSpawnItemButtonInPortableSpawner = _configFile.Bind<bool>("General", "ShowSpawnItemButtonInPortableSpawner", true, "Makes the spawn item button visible in the portable item spawner, letting you spawn objects without having to use the stylus."); ItemSpawnerSortGrouping = _configFile.Bind<ItemSpawnerSortGrouping>("General", "ItemSpawnerSortGrouping", global::OtherLoader.ItemSpawner.VanillaCategories.ItemSpawnerSortGrouping.ShowModdedItemsFirst, "Changes how items are grouped and displayed in the item spawner."); ItemSpawnerSortOrder = _configFile.Bind<ItemSpawnerSortOrder>("General", "ItemSpawnerSortOrder", global::OtherLoader.ItemSpawner.VanillaCategories.ItemSpawnerSortOrder.AlphabeticalByDisplayName, "'Vanilla' orders items alphabetically by their internal ItemIDs. 'AlphabeticalByDisplayName' orders items by their actual visible names. This does not affect how categories are ordered, only items."); ColoredLogs = _configFile.Bind<bool>("Logging", "ColoredLogs", true, "When true, logs will change colors depending on their LogTag."); LogTags = _configFile.Bind<LogTag>("Logging", "LogTags", LogTag.General, "Controls which types of logs should be enabled. Errors and warnings will always be logged, regardless of this setting."); AddUnloadButton = _configFile.Bind<bool>("Debug", "AddUnloadButton", false, "When true, you'll have a wrist menu button that can unload all modded asset bundles for testing purposes. Requires game restart.").Value; EnableLogTraces = _configFile.Bind<bool>("Debug", "EnableLogTraces", false, "Affects performance, only enable when debugging. When true, method call traces will be included in logs. Requires game restart.").Value; ShowDebugItemSpawnerEntries = _configFile.Bind<bool>("Debug", "ShowDebugItemSpawnerEntries", false, "When true, debug spawner entries will be added to the item spawner's custom categories tab. Requires game restart.").Value; } } } namespace OtherLoader.UnlockAllItems { public enum ItemUnlockerMode { Disabled, UnlockOnlyFirearmsAndAmmo, UnlockAllItems } [HarmonyPriority(600)] [HarmonyWrapSafe] internal static class RewardUnlocksPatchers { private static int _activeMethods; [HarmonyPostfix] [HarmonyPatch(typeof(RewardUnlocks), "IsRewardUnlocked", new Type[] { typeof(ItemSpawnerID) })] private static void IsRewardUnlocked_Postfix(ItemSpawnerID ID, ref bool __result) { if (_activeMethods == 0) { return; } if (!__result) { if (PluginConfig.ItemUnlocker == ItemUnlockerMode.UnlockOnlyFirearmsAndAmmo && !ID.IsFirearm() && !ID.IsAmmo()) { OtherLogger.Log("Reward item '" + ID.DisplayName + "' is not firearm or ammo, skipping...", LogTag.ItemUnlocker); return; } OtherLogger.Log("Game checked if '" + ID.DisplayName + "' is unlocked, returning true!", LogTag.ItemUnlocker); if (!ID.ModTags.Contains("GrantedByItemUnlocker")) { ID.ModTags = ID.ModTags.Concat(new <>z__ReadOnlySingleElementList<string>("GrantedByItemUnlocker")).ToList(); } } __result = true; } private static void AddActiveMethod() { Interlocked.Increment(ref _activeMethods); } private static void RemoveActiveMethod() { if (Interlocked.Decrement(ref _activeMethods) < 0) { Interlocked.Exchange(ref _activeMethods, 0); } } [HarmonyPrefix] [HarmonyPatch(typeof(IM), "GenerateItemDBs")] private static void GenerateItemDBs_Prefix() { AddActiveMethod(); } [HarmonyFinalizer] [HarmonyPatch(typeof(IM), "GenerateItemDBs")] private static Exception GenerateItemDBs_Finalizer(Exception __exception) { RemoveActiveMethod(); return __exception; } [HarmonyPrefix] [HarmonyPatch(typeof(ItemSpawnerV2), "RedrawDetailsCanvas")] private static void RedrawDetailsCanvas_Prefix() { AddActiveMethod(); } [HarmonyFinalizer] [HarmonyPatch(typeof(ItemSpawnerV2), "RedrawDetailsCanvas")] private static Exception RedrawDetailsCanvas_Finalizer(Exception __exception) { RemoveActiveMethod(); return __exception; } } } namespace OtherLoader.QuickbeltPanel { internal class QBslotPageController : MonoBehaviour { public const int QbsPerPage = 14; public OptionsPanel_ButtonSet QBslotButtonSet; public GameObject ButtonNextPage; public GameObject ButtonPreviousPage; public int currentPage; public void Start() { SetVisibility(); } public void SetButtons() { ButtonNextPage.SetActive(true); ButtonPreviousPage.SetActive(true); if (currentPage <= 0) { ButtonPreviousPage.SetActive(false); } int num = Mathf.CeilToInt((float)(QBslotButtonSet.ButtonsInSet.Length / 14)); if (currentPage >= num) { ButtonNextPage.SetActive(false); } } public void SetVisibility() { SetButtons(); FVRPointableButton[] buttonsInSet = QBslotButtonSet.ButtonsInSet; for (int i = 0; i < buttonsInSet.Length; i++) { ((Component)buttonsInSet[i]).gameObject.SetActive(false); } int num = currentPage * 14; int num2 = num + 14; for (int j = num; j < num2 && j < QBslotButtonSet.ButtonsInSet.Length; j++) { ((Component)QBslotButtonSet.ButtonsInSet[j]).gameObject.SetActive(true); } } public void GotoPreviousPage() { currentPage--; SetVisibility(); } public void GotoNextPage() { currentPage++; SetVisibility(); } } [HarmonyWrapSafe] internal static class QuickbeltPanelPatcher { [HarmonyPrefix] [HarmonyPatch(typeof(OptionsScreen_Quickbelt), "Awake")] private static bool Awake_Prefix_AddScreens(OptionsScreen_Quickbelt __instance) { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown OptionsScreen_Quickbelt __instance2 = __instance; QBslotPageController pageController = ((Component)__instance2).gameObject.AddComponent<QBslotPageController>(); pageController.QBslotButtonSet = __instance2.OBS_SlotStyle; GameObject gameObject = ((Component)__instance2.OBS_Handedness.ButtonsInSet[0]).gameObject; FVRPointableButton[] buttonsInSet = __instance2.OBS_SlotStyle.ButtonsInSet; for (int i = 0; i < buttonsInSet.Length; i++) { Object.Destroy((Object)(object)((Component)buttonsInSet[i]).gameObject); } __instance2.OBS_SlotStyle.ButtonsInSet = (FVRPointableButton[])(object)new FVRPointableButton[ManagerSingleton<GM>.Instance.QuickbeltConfigurations.Length]; for (int j = 0; j < __instance2.OBS_SlotStyle.ButtonsInSet.Length; j++) { int num = j % 14; int column = num % 4; int row = (int)Mathf.Floor((float)num / 4f); OtherLogger.Log("Adding QB " + ((Object)ManagerSingleton<GM>.Instance.QuickbeltConfigurations[j]).name, LogTag.BundleLoading); GameObject val = Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true); FVRPointableButton component = val.GetComponent<FVRPointableButton>(); __instance2.OBS_SlotStyle.ButtonsInSet[j] = component; string text = ((Object)ManagerSingleton<GM>.Instance.QuickbeltConfigurations[j]).name.Split(new char[1] { '_' }).Last(); Button uiButton = SetQBSlotOptionsPanelButton(val, row, column, text); ((UnityEvent)uiButton.onClick).AddListener((UnityAction)delegate { __instance2.SetSlotStyle(((Component)uiButton).transform.GetSiblingIndex()); }); ((UnityEvent)uiButton.onClick).AddListener((UnityAction)delegate { __instance2.OBS_SlotStyle.SetSelectedButton(((Component)uiButton).transform.GetSiblingIndex()); }); } Button val2 = SetQBSlotOptionsPanelButton(Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true), 3, 2, "Previous Page"); ((UnityEvent)val2.onClick).AddListener((UnityAction)delegate { pageController.GotoPreviousPage(); }); pageController.ButtonPreviousPage = ((Component)val2).gameObject; val2 = SetQBSlotOptionsPanelButton(Object.Instantiate<GameObject>(gameObject, ((Component)__instance2.OBS_SlotStyle).transform, true), 3, 3, "Next Page"); ((UnityEvent)val2.onClick).AddListener((UnityAction)delegate { pageController.GotoNextPage(); }); pageController.ButtonNextPage = ((Component)val2).gameObject; return true; } public static Button SetQBSlotOptionsPanelButton(GameObject button, int row, int column, string text) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) float num = -100 + 125 * column; float num2 = -40 + -45 * row; button.transform.localPosition = new Vector3(num, num2, button.transform.localPosition.z); ((Component)button.gameObject.transform.GetChild(0)).GetComponent<Text>().text = text; Button component = button.GetComponent<Button>(); ((UnityEventBase)component.onClick).RemoveAllListeners(); return component; } [HarmonyPrefix] [HarmonyPatch(typeof(FVRPlayerBody), "ConfigureQuickbelt")] private static bool ConfigureQuickbelt_Prefix_PreventIndexOutOfRange(ref int index) { index = Mathf.Clamp(index, 0, ManagerSingleton<GM>.Instance.QuickbeltConfigurations.Length - 1); return true; } } } namespace OtherLoader.PortableItemSpawner { [HarmonyWrapSafe] [HarmonyPatch(typeof(ItemSpawnerV2))] internal static class PortableSpawnerPatcher { [HarmonyPostfix] [HarmonyPatch("RedrawDetailsCanvas")] private static void RedrawDetailsCanvas_Postfix_EnableSpawnButton(ItemSpawnerV2 __instance) { if (PluginConfig.ShowSpawnItemButtonInPortableSpawner.Value && __instance.IsInPortableMode && !string.IsNullOrEmpty(__instance.m_selectedID)) { GameObject bTN_SpawnSelectedObject = __instance.BTN_SpawnSelectedObject; if (bTN_SpawnSelectedObject != null) { bTN_SpawnSelectedObject.SetActive(true); } } } } } namespace OtherLoader.Loading { [HarmonyWrapSafe] internal static class AnvilRuntimeLoadingPatcher { [HarmonyPrefix] [HarmonyPatch(typeof(AnvilManager), "GetAssetBundleAsyncInternal")] private static bool GetAssetBundleAsyncInternal_Prefix(string bundle, ref AnvilCallback<AssetBundle> __result) { if (OtherLoader.ManagedBundles.TryGetValue(bundle, out string value)) { AnvilCallbackBase val = default(AnvilCallbackBase); if (AnvilManager.m_bundles.TryGetValue(bundle, ref val)) { OtherLogger.Log("Tried to load modded asset bundle, and it's already loaded: " + bundle, LogTag.BundleLoading); __result = val as AnvilCallback<AssetBundle>; return false; } OtherLogger.Log("Tried to load modded asset bundle, and it's not yet loaded: " + bundle, LogTag.BundleLoading); AnvilCallback<AssetBundle> val2 = UnityAssetBundleLoader.LoadAssetsFromBundlePatch(value); List<BundleLoadStatus> bundleDependencies = LoaderStatus.GetBundleDependencies(bundle); if (bundleDependencies.Count > 0) { OtherLogger.Log("Dependencies:", LogTag.BundleLoading); bundleDependencies.ForEach(delegate(BundleLoadStatus o) { OtherLogger.Log(OtherLoader.ManagedBundles[o.BundleId], LogTag.BundleLoading); }); AnvilCallback<AssetBundle> val3 = (val2.m_dependancy = UnityAssetBundleLoader.LoadAssetsFromBundlePatch(OtherLoader.ManagedBundles[bundleDependencies.Last().BundleId])); AnvilManager.m_bundles.Add(bundleDependencies.Last().BundleId, (AnvilCallbackBase)(object)val3); for (int num = bundleDependencies.Count - 2; num >= 0; num--) { val3.m_dependancy = UnityAssetBundleLoader.LoadAssetsFromBundlePatch(OtherLoader.ManagedBundles[bundleDependencies[num].BundleId]); val3 = val3.m_dependancy; AnvilManager.m_bundles.Add(bundleDependencies[num].BundleId, (AnvilCallbackBase)(object)val3); } } __result = val2; AnvilManager.m_bundles.Add(bundle, (AnvilCallbackBase)(object)__result); return false; } return true; } [HarmonyPrefix] [HarmonyPatch(typeof(AnvilAsset), "GetGameObject")] [HarmonyPatch(typeof(AnvilAsset), "GetGameObjectAsync")] private static bool GetGameObject_Prefix_SetBundlePatch(AnvilAsset __instance) { if (string.IsNullOrEmpty(__instance.m_anvilPrefab.Bundle)) { FVRObject val = (FVRObject)(object)((__instance is FVRObject) ? __instance : null); if ((Object)(object)val != (Object)null && IM.OD.TryGetValue(val.ItemID, out var value)) { __instance.m_anvilPrefab.Bundle = ((AnvilAsset)value).m_anvilPrefab.Bundle; } } return true; } } internal static class MainLoader { private static readonly IAssetBundleLoader[] AssetLoaders = new IAssetBundleLoader[13] { new MechanicalAccuracyChartLoader(), new FVRObjectLoader(), new RoundDisplayDataLoader(), new ItemSpawnerCategoryLoader(), new ItemSpawnerIDLoader(), new ItemSpawnerEntryLoader(), new HandlingGrabSetLoader(), new HandlingReleaseSetLoader(), new HandlingSlotSetLoader(), new BulletImpactSetLoader(), new AudioImpactSetLoader(), new TutorialBlockLoader(), new QuickBeltLoader() }; public static Empty LoadAssembly(FileSystemInfo handle) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) OtherLogger.Log("Loading assembly file: $" + handle.FullName, LogTag.BundleLoading); Assembly.LoadFile(handle.FullName); return default(Empty); } public static IEnumerator BundleLoadImmediate(FileSystemInfo handle, LoadOrderType loadOrder) { return LoadBundle(new TL("BundleLoadImmediate", LogTag.BundleLoading), handle, loadOrder, allowUnload: true); } public static IEnumerator BundlePrepareLate(FileSystemInfo handle) { return LoadBundle(new TL("BundlePrepareLate", LogTag.BundleLoading), handle, LoadOrderType.LoadFirst, allowUnload: false); } public static IEnumerator BundleRegisterLate(FileSystemInfo handle, LoadOrderType loadOrder) { TL oldTL = new TL("BundleRegisterLate", LogTag.BundleLoading); FileInfo fileInfo = ExtFileSystemInfo.ConsumeFile(handle); return RegisterLateBundle(oldTL, fileInfo.Name, fileInfo.FullName, loadOrder); } public static void BundleLoadDirectFromDirectory(string directoryNameFull, string[] loadFirst, string[] loadAny, string[] loadLast) { TL oldTL = new TL("BundleLoadDirectFromDirectory", LogTag.BundleLoading); foreach (KeyValuePair<string, LoadOrderType> item in loadFirst.Select((string bundle) => new KeyValuePair<string, LoadOrderType>(bundle, LoadOrderType.LoadFirst)).Concat(loadAny.Select((string bundle) => new KeyValuePair<string, LoadOrderType>(bundle, LoadOrderType.LoadUnordered))).Concat(loadLast.Select((string bundle) => new KeyValuePair<string, LoadOrderType>(bundle, LoadOrderType.LoadLast)))) { if (!string.IsNullOrEmpty(item.Key)) { OtherLoader.CoroutineStarter.Invoke(LoadBundleDirect(oldTL, directoryNameFull, item.Key, item.Value)); } } } public static void LoadLegacyBundles() { string text = Application.dataPath.Replace("/h3vr_Data", "/LegacyVirtualObjects"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } TL newTL = new TL("LoadLegacyBundles", LogTag.BundleLoading); newTL.Log("Loading bundles from legacy directory (" + text + ")"); List<string> list = Directory.GetDirectories(Paths.PluginPath, "LegacyVirtualObjects", SearchOption.AllDirectories).ToList(); list.Add(text); foreach (string item in list) { newTL.Log("Legacy folder found '" + item + "'"); string[] files = Directory.GetFiles(item, "*", SearchOption.AllDirectories); foreach (string text2 in files) { if (!(Path.GetFileName(text2) != Path.GetFileNameWithoutExtension(text2))) { BundleInfo bundleInfo = new BundleInfo(text2); IEnumerator enumerator2 = ExtIEnumerator.TryCatch<Exception>(TrackLoadAssetsFromBundle(newTL, bundleInfo, LoadOrderType.LoadUnordered, allowUnload: true), (Action<Exception>)delegate(Exception exception) { newTL.LogError("Exception when loading legacy bundle '" + bundleInfo.Name + "'\n- " + exception.Message); LoaderStatus.UpdateProgress(bundleInfo.ID, 1f); LoaderStatus.RemoveActiveLoader(bundleInfo.ID, permanentlyLoaded: true); }); OtherLoader.CoroutineStarter.Invoke(enumerator2); } } } } private static IEnumerator LoadBundle(TL oldTL, FileSystemInfo handle, LoadOrderType loadOrder, bool allowUnload) { TL newTL = oldTL.New("LoadBundle"); BundleInfo bundleInfo = new BundleInfo(ExtFileSystemInfo.ConsumeFile(handle)); newTL.Log($"Loading '{bundleInfo.Name}' with: loadOrder '{loadOrder}', allowUnload '{allowUnload}'"); return ExtIEnumerator.TryCatch(TrackLoadAssetsFromBundle(newTL, bundleInfo, loadOrder, allowUnload), (Action<Exception>)delegate(Exception exception) { newTL.LogError("Exception when loading bundle '" + bundleInfo.Name + "'\n- " + exception.Message); LoaderStatus.UpdateProgress(bundleInfo.ID, 1f); LoaderStatus.RemoveActiveLoader(bundleInfo.ID, permanentlyLoaded: true); }); } private static IEnumerator RegisterLateBundle(TL oldTL, string lateBundleName, string lateBundleFullPath, LoadOrderType loadOrder) { TL tL = oldTL.New("RegisterLateBundle"); string text = lateBundleName.Replace("late_", ""); BundleInfo bundleInfo = new BundleInfo(Path.Combine(Path.GetDirectoryName(lateBundleFullPath), text), lateBundleFullPath); OtherLoader.ManagedBundles[bundleInfo.ID] = bundleInfo.ContentFullPath; LoaderStatus.TrackLoader(bundleInfo.ID, loadOrder); AnvilCallbackBase item = default(AnvilCallbackBase); if (AnvilManager.m_bundles.TryGetValue(bundleInfo.ID, ref item)) { AnvilManager.m_bundles.m_lookup.Remove(bundleInfo.ID); AnvilManager.m_bundles.m_loading.Remove(item); tL.Log("Finished registering late bundle '" + lateBundleName + "'\n- This bundle will replace prepared bundle '" + text + "'"); } else { tL.LogError("Failed to register late bundle '" + lateBundleName + "', there is no prepared bundle it can replace.\n- There should have been a prepared bundle '" + text + "'"); } yield return null; } private static IEnumerator LoadBundleDirect(TL oldTL, string directoryNameFull, string bundleName, LoadOrderType loadOrder) { TL newTL = oldTL.New("LoadBundleDirect"); BundleInfo bundleInfo = new BundleInfo(Path.Combine(directoryNameFull, bundleName)); newTL.Log("Starting direct load bundle '" + bundleInfo.Name + "'"); string text = "late_" + bundleName; string text2 = Path.Combine(directoryNameFull, text); IEnumerator onAfterLoadAsync = null; if (File.Exists(text2)) { onAfterLoadAsync = RegisterLateBundle(newTL, text, text2, loadOrder); } return ExtIEnumerator.TryCatch(TrackLoadAssetsFromBundle(newTL, bundleInfo, loadOrder, allowUnload: false, onAfterLoadAsync), (Action<Exception>)delegate(Exception exception) { newTL.LogError("Exception when direct loading bundle '" + bundleInfo.Name + "'\n- " + exception.Message); LoaderStatus.UpdateProgress(bundleInfo.ID, 1f); LoaderStatus.RemoveActiveLoader(bundleInfo.ID, permanentlyLoaded: true); }); } private static IEnumerator TrackLoadAssetsFromBundle(TL oldTL, BundleInfo bundleInfo, LoadOrderType loadOrder, bool allowUnload, IEnumerator? onAfterLoadAsync = null) { TL newTL = oldTL.New("TrackLoadAssetsFromBundle"); if (LoaderStatus.IsBundleAlreadyTracked(bundleInfo.ID)) { newTL.LogWarning("BundleID '" + bundleInfo.Name + "' is already tracked! Returning..."); yield break; } LoaderStatus.TrackLoader(bundleInfo.ID, loadOrder); newTL.Log("Began tracking bundle '" + bundleInfo.Name + "', yielding to track others..."); yield return null; newTL.Log("Waiting until bundle '" + bundleInfo.Name + "' can load..."); yield return WaitUntilBundleCanLoad(newTL, bundleInfo); float loadingTime = Time.realtimeSinceStartup; LoaderStatus.AddActiveLoader(bundleInfo.ID); LoaderStatus.UpdateProgress(bundleInfo.ID, Random.Range(0.1f, 0.3f)); newTL.Log("Beginning async load of bundle '" + bundleInfo.Name + "'"); AnvilCallback<AssetBundle> anvilCallback = UnityAssetBundleLoader.LoadAssetsFromBundlePatch(bundleInfo.ContentFullPath); yield return anvilCallback; if ((Object)(object)anvilCallback?.Result == (Object)null) { OtherLogger.LogFatal("Asset bundle '" + bundleInfo.Name + "' is null! Cannot load assets from mod '" + bundleInfo.PluginName + "'. Most likely a different mod has already loaded a bundle with the same internal name!"); LoaderStatus.UpdateProgress(bundleInfo.ID, 1f); LoaderStatus.RemoveActiveLoader(bundleInfo.ID, permanentlyLoaded: true); } else { yield return RunAssetLoadersOnAssetBundle(newTL, anvilCallback, bundleInfo); FinishBundleLoading(newTL, anvilCallback, bundleInfo, allowUnload, loadingTime); if (onAfterLoadAsync != null) { yield return onAfterLoadAsync; } } } private static IEnumerator WaitUntilBundleCanLoad(TL oldTL, BundleInfo bundleInfo) { TL newTL = oldTL.New("WaitUntilBundleCanLoad"); bool overTime = false; while (!LoaderStatus.CanOrderedModLoad(bundleInfo.ID)) { if (!overTime && Time.realtimeSinceStartup - LoaderStatus.LastLoadEventTime > 30f) { newTL.Log("Bundle '" + bundleInfo.Name + "' has been waiting a long time to load!"); LoaderStatus.PrintWaitingBundles(bundleInfo.ID); overTime = true; } yield return null; } } private static IEnumerator RunAssetLoadersOnAssetBundle(TL oldTL, AnvilCallback<AssetBundle> anvilCallback, BundleInfo bundleInfo) { BundleInfo bundleInfo2 = bundleInfo; TL newTL = oldTL.New("RunAssetLoadersOnAssetBundle"); IAssetBundleLoader[] assetLoaders = AssetLoaders; foreach (IAssetBundleLoader loader in assetLoaders) { yield return ExtIEnumerator.TryCatch(loader.LoadAssetsFromBundle(anvilCallback.Result, bundleInfo2), (Action<Exception>)delegate(Exception e) { newTL.LogError("Exception when loader '" + loader.GetType().Name + "' was loading assets from " + $"bundle '{bundleInfo2.Name}' from mod '{bundleInfo2.PluginName}'! {e}"); }); } } private static void FinishBundleLoading(TL oldTL, AnvilCallback<AssetBundle> anvilCallback, BundleInfo bundleInfo, bool allowUnload, float loadingTime) { TL tL = oldTL.New("FinishBundleLoading"); bool flag = PluginConfig.OptimizeMemory && allowUnload; string text = $"Completed loading bundle '{bundleInfo.Name}' in {Time.realtimeSinceStartup - loadingTime:0.000} seconds!"; string message = (flag ? (text + " Optimizing memory!") : text); tL.Log(message, LogTag.General); if (flag) { anvilCallback.Result.Unload(false); } else { AnvilManager.m_bundles.Add(bundleInfo.ID, (AnvilCallbackBase)(object)anvilCallback); } OtherLoader.ManagedBundles.Add(bundleInfo.ID, bundleInfo.ContentFullPath); LoaderStatus.UpdateProgress(bundleInfo.ID, 1f); LoaderStatus.RemoveActiveLoader(bundleInfo.ID, !flag); } } internal static class UnityAssetBundleLoader { public static AnvilCallback<AssetBundle> LoadAssetsFromBundlePatch(string fullBundlePath) { return new AnvilCallback<AssetBundle>((AsyncOperation)(object)AssetBundle.LoadFromFileAsync(fullBundlePath), (AnvilCallback<AssetBundle>)null); } } } namespace OtherLoader.Loading.Model { internal class BundleInfo { public readonly string Name; public readonly string ContentFullPath; public readonly string PluginName; public readonly string FullDirectoryName; public string ID => FullDirectoryName + "\\ : " + Name; public BundleInfo(FileInfo fileInfo) { Name = fileInfo.Name; FullDirectoryName = fileInfo.DirectoryName; PluginName = RetrievePluginNameFromFullDirectoryName() ?? "UnknownPlugin"; ContentFullPath = fileInfo.FullName; } public BundleInfo(string bundleFullPath, string? bundleContentFullPathOverride = null) { Name = Path.GetFileName(bundleFullPath); FullDirectoryName = Path.GetDirectoryName(bundleFullPath); PluginName = RetrievePluginNameFromFullDirectoryName() ?? "UnknownPlugin"; ContentFullPath = bundleContentFullPathOverride ?? bundleFullPath; } private string? RetrievePluginNameFromFullDirectoryName() { string path = Path.Combine(Paths.BepInExRootPath, "plugins"); string text = Path.GetFullPath(FullDirectoryName).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); string text2 = Path.GetFullPath(path).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); if (!text.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { return null; } string[] array = text.Substring(text2.Length).TrimStart(new char[1] { Path.DirectorySeparatorChar }).Split(new char[1] { Path.DirectorySeparatorChar }); if (array.Length == 0) { return null; } return array[0]; } } } namespace OtherLoader.Loading.AssetLoaders { internal abstract class AssetBundleLoaderBase<T> : IAssetBundleLoader where T : Object { public IEnumerator LoadAssetsFromBundle(AssetBundle assetBundle, BundleInfo bundleInfo) { AssetBundleRequest bundleRequest = assetBundle.LoadAllAssetsAsync<T>(); yield return bundleRequest; Object[] allAssets = bundleRequest.allAssets; foreach (Object val in allAssets) { try { T asset = ((T)(object)((val is T) ? val : null)) ?? throw new InvalidOperationException("CastAsset is null"); LoadAssetFromBundle(asset, bundleInfo); } catch (Exception arg) { OtherLogger.LogError($"Failed to load asset from mod '{bundleInfo.PluginName}'! Exception: {arg}"); } } } protected abstract void LoadAssetFromBundle(T asset, BundleInfo bundleInfo); } internal interface IAssetBundleLoader { IEnumerator LoadAssetsFromBundle(AssetBundle assetBundle, BundleInfo bundleInfo); } } namespace OtherLoader.Loading.AssetLoaders.Implementations { internal class AudioImpactSetLoader : AssetBundleLoaderBase<AudioImpactSet> { protected override void LoadAssetFromBundle(AudioImpactSet asset, BundleInfo bundleInfo) { OtherLogger.Log("Loading new AudioImpactSet: " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<SM>.Instance.AudioImpactSets = ManagerSingleton<SM>.Instance.AudioImpactSets.Concat(new <>z__ReadOnlySingleElementList<AudioImpactSet>(asset)).ToArray(); ManagerSingleton<SM>.Instance.m_impactDic = new Dictionary<ImpactType, Dictionary<MatSoundType, Dictionary<AudioImpactIntensity, AudioEvent>>>(); ManagerSingleton<SM>.Instance.generateImpactDictionary(); } } internal class BulletImpactSetLoader : AssetBundleLoaderBase<AudioBulletImpactSet> { protected override void LoadAssetFromBundle(AudioBulletImpactSet asset, BundleInfo bundleInfo) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) OtherLogger.Log("Loading new bullet impact set entry: " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<SM>.Instance.AudioBulletImpactSets = ManagerSingleton<SM>.Instance.AudioBulletImpactSets.Concat(new <>z__ReadOnlySingleElementList<AudioBulletImpactSet>(asset)).ToArray(); ManagerSingleton<SM>.Instance.m_bulletHitDic.Add(asset.Type, asset); } } internal class FVRObjectLoader : AssetBundleLoaderBase<FVRObject> { protected override void LoadAssetFromBundle(FVRObject fvrObject, BundleInfo bundleInfo) { OtherLogger.Log("Loading FVRObject with ID '" + fvrObject.ItemID + "'", LogTag.Assets); if (IM.OD.ContainsKey(fvrObject.ItemID)) { OtherLogger.LogError("The ItemID '" + fvrObject.ItemID + "' of FVRObject is already used! Item will not be loaded!"); return; } ((AnvilAsset)fvrObject).m_anvilPrefab.Bundle = bundleInfo.ID; LoadIntoObjectDatabase(fvrObject); fvrObject.IsModContent = true; OtherLogger.Log("Loaded FVRObject with ID '" + fvrObject.ItemID + "'", LogTag.Assets); } private void LoadIntoObjectDatabase(FVRObject fvrObject) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) FVRObject fvrObject2 = fvrObject; IM.OD.Add(fvrObject2.ItemID, fvrObject2); ManagerSingleton<IM>.Instance.odicTagCategory.GetOrCreateDefault(fvrObject2.Category).Add(fvrObject2); ManagerSingleton<IM>.Instance.odicTagFirearmEra.GetOrCreateDefault(fvrObject2.TagEra).Add(fvrObject2); ManagerSingleton<IM>.Instance.odicTagFirearmSize.GetOrCreateDefault(fvrObject2.TagFirearmSize).Add(fvrObject2); ManagerSingleton<IM>.Instance.odicTagFirearmAction.GetOrCreateDefault(fvrObject2.TagFirearmAction).Add(fvrObject2); ManagerSingleton<IM>.Instance.odicTagAttachmentMount.GetOrCreateDefault(fvrObject2.TagAttachmentMount).Add(fvrObject2); ManagerSingleton<IM>.Instance.odicTagAttachmentFeature.GetOrCreateDefault(fvrObject2.TagAttachmentFeature).Add(fvrObject2); fvrObject2.TagFirearmFeedOption.ForEach(delegate(OTagFirearmFeedOption o) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManagerSingleton<IM>.Instance.odicTagFirearmFeedOption.GetOrCreateDefault(o).Add(fvrObject2); }); fvrObject2.TagFirearmFiringModes.ForEach(delegate(OTagFirearmFiringMode o) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManagerSingleton<IM>.Instance.odicTagFirearmFiringMode.GetOrCreateDefault(o).Add(fvrObject2); }); fvrObject2.TagFirearmMounts.ForEach(delegate(OTagFirearmMount o) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ManagerSingleton<IM>.Instance.odicTagFirearmMount.GetOrCreateDefault(o).Add(fvrObject2); }); } } internal class HandlingGrabSetLoader : AssetBundleLoaderBase<HandlingGrabSet> { protected override void LoadAssetFromBundle(HandlingGrabSet asset, BundleInfo bundleInfo) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) OtherLogger.Log("Loading new handling grab set entry: " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<SM>.Instance.m_handlingGrabDic.Add(asset.Type, asset); } } internal class HandlingReleaseSetLoader : AssetBundleLoaderBase<HandlingReleaseSet> { protected override void LoadAssetFromBundle(HandlingReleaseSet asset, BundleInfo bundleInfo) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) OtherLogger.Log("Loading new handling release set entry: " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<SM>.Instance.m_handlingReleaseDic.Add(asset.Type, asset); } } internal class HandlingSlotSetLoader : AssetBundleLoaderBase<HandlingReleaseIntoSlotSet> { protected override void LoadAssetFromBundle(HandlingReleaseIntoSlotSet asset, BundleInfo bundleInfo) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) OtherLogger.Log("Loading new handling QB slot set entry: " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<SM>.Instance.m_handlingReleaseIntoSlotDic.Add(asset.Type, asset); } } internal class ItemSpawnerCategoryLoader : AssetBundleLoaderBase<ItemSpawnerCategoryDefinitions> { protected override void LoadAssetFromBundle(ItemSpawnerCategoryDefinitions categoryDefinitions, BundleInfo bundleInfo) { new TL("LoadAssetFromBundle", LogTag.Assets).Log("Loading legacy ItemSpawnerCategoryDefinitions from plugin '" + bundleInfo.PluginName + "'"); SpawnerTilesDatabase.RegisterLegacyCategories(categoryDefinitions); } } internal class ItemSpawnerEntryLoader : AssetBundleLoaderBase<ItemSpawnerEntry> { protected override void LoadAssetFromBundle(ItemSpawnerEntry entry, BundleInfo bundleInfo) { TL tL = new TL("LoadAssetFromBundle", LogTag.Assets); bool isDisplayedInMainEntry = entry.IsDisplayedInMainEntry; tL.Log("Loading ItemSpawnerEntry from plugin '" + bundleInfo.PluginName + "'\n- MainObjectID '" + (entry.MainObjectID ?? "null") + "'\n- MainObjectObj.ItemID '" + (entry.MainObjectObj?.ItemID ?? "null") + "'\n- EntryPath '" + (entry.EntryPath ?? "null") + "'\n- DisplayName '" + (entry.DisplayName ?? "null") + "'"); entry.PopulateIDsFromObj(); bool flag = entry.IsCategoryEntry(); tL.Log($"Is a category entry: {flag}"); if ((Object)(object)entry.MainObjectObj == (Object)null && !flag) { FVRObject valueOrNull = IM.OD.GetValueOrNull(entry.MainObjectID); if ((Object)(object)valueOrNull == (Object)null) { tL.LogWarning("ItemSpawnerEntry is not a custom category, but has no specified FVRObject! Attempted to resolve MainObjectID '" + entry.MainObjectID + "', but there is no FVRObject with such ID! Attempting to load this entry regardless..."); } entry.MainObjectObj = valueOrNull; } if (!flag) { ItemSpawnerID itemSpawnerID = SpawnerEntryToSpawnerIDConverter.Convert(tL, entry); ItemSpawnerIDRegisterer.Register(tL, itemSpawnerID, registerInTilesDatabase: false, unifyItemIDs: false, blockDuplicateIDs: false, bundleInfo.PluginName); OtherLoader.SpawnerEntriesByID[entry.MainObjectID] = entry; } if (isDisplayedInMainEntry) { SpawnerTilesDatabase.TryRegister(entry); } else if (flag) { OtherLogger.LogWarning("CategoryEntry has IsDisplayedInMainEntry set to false, it will not be displayed!"); } } } internal class ItemSpawnerIDLoader : AssetBundleLoaderBase<ItemSpawnerID> { protected override void LoadAssetFromBundle(ItemSpawnerID itemSpawnerID, BundleInfo bundleInfo) { TL tL = new TL("LoadAssetFromBundle", LogTag.Assets); tL.Log("Loading ItemSpawnerID from plugin '" + bundleInfo.PluginName + "'\n- ItemID '" + (itemSpawnerID.ItemID ?? "null") + "'\n- MainObject.ItemID '" + (itemSpawnerID.MainObject?.ItemID ?? "null") + "'\n- DisplayName '" + (itemSpawnerID.DisplayName ?? "null") + "'"); if (itemSpawnerID.SecondObject?.ItemID != null) { ItemSpawnerIDLinker.QueueEntryToLink(new EntryToLink(itemSpawnerID, new List<string>(1) { itemSpawnerID.SecondObject.ItemID }, new List<string>())); } bool flag; switch (bundleInfo.PluginName) { case "Meat_banono-Meats_ASh12": case "Meat_banono-Meats_ModulSIG": case "Phoenix-NikiFoxsCSGOBenelliNova": case "Potatoes-Potatoes_SMGs": case "Potatoes-Potatoes_Rifles": case "Potatoes-Potatoes_NonRepeaters": case "Potatoes-Potatoes_Pistols": flag = true; break; default: flag = false; break; } bool num = flag; bool flag2 = itemSpawnerID.ItemID?.All(char.IsWhiteSpace) ?? false; bool unifyItemIDs = num || flag2; bool blockDuplicateIDs = bundleInfo.PluginName == "Andrew_FTW-FTW_Arms_Edged_Weapons_Pack"; ItemSpawnerIDRegisterer.Register(tL, itemSpawnerID, registerInTilesDatabase: true, unifyItemIDs, blockDuplicateIDs, bundleInfo.PluginName); } } internal class MechanicalAccuracyChartLoader : AssetBundleLoaderBase<FVRFireArmMechanicalAccuracyChart> { protected override void LoadAssetFromBundle(FVRFireArmMechanicalAccuracyChart asset, BundleInfo bundleInfo) { foreach (MechanicalAccuracyEntry entry in asset.Entries) { LoadMechanicalAccuracyEntry(entry); } } private void LoadMechanicalAccuracyEntry(MechanicalAccuracyEntry entry) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (AM.SMechanicalAccuracyDic.ContainsKey(entry.Class)) { OtherLogger.LogError("Duplicate mechanical accuracy class found, will not use one of them! Make sure you're using unique mechanical accuracy classes!"); return; } AM.SMechanicalAccuracyDic.Add(entry.Class, entry); OtherLogger.Log("Loaded new mechanical accuracy entry: " + ((object)(FVRFireArmMechanicalAccuracyClass)(ref entry.Class)).ToString(), LogTag.Assets); } } internal class QuickBeltLoader : AssetBundleLoaderBase<GameObject> { protected override void LoadAssetFromBundle(GameObject asset, BundleInfo bundleInfo) { if (IsPrefabAQuickBelt(asset)) { OtherLogger.Log("Adding QuickBelt " + ((Object)asset).name, LogTag.Assets); ManagerSingleton<GM>.Instance.QuickbeltConfigurations = ManagerSingleton<GM>.Instance.QuickbeltConfigurations.Concat(new <>z__ReadOnlySingleElementList<GameObject>(asset)).ToArray(); } } private static bool IsPrefabAQuickBelt(GameObject prefab) { string[] array = ((Object)prefab).name.Split(new char[1] { '_' }); if (array.Length > 1) { return array[^2] == "QuickBelt"; } return false; } } internal class RoundDisplayDataLoader : AssetBundleLoaderBase<FVRFireArmRoundDisplayData> { protected override void LoadAssetFromBundle(FVRFireArmRoundDisplayData asset, BundleInfo bundleInfo) { AddRoundTypeIfNotExist(asset); AddRoundClassIfNotExist(asset); AddRoundDisplayData(asset); OtherLogger.Log("Loaded ammo type: " + ((object)(FireArmRoundType)(ref asset.Type)).ToString(), LogTag.Assets); } private void AddRoundTypeIfNotExist(FVRFireArmRoundDisplayData displayData) { //IL_0006: 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) AM.STypeDic.GetOrCreateDefault(displayData.Type); AM.STypeList.AddIfUnique(displayData.Type); } private void AddRoundClassIfNotExist(FVRFireArmRoundDisplayData displayData) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_006e: Unknown result type (might be due to invalid IL or missing references) AM.STypeClassLists.GetOrCreateDefault(displayData.Type); DisplayDataClass[] classes = displayData.Classes; foreach (DisplayDataClass val in classes) { OtherLogger.Log("Loading ammo class: " + ((object)(FireArmRoundClass)(ref val.Class)).ToString(), LogTag.Assets); AM.STypeDic[displayData.Type][val.Class] = val; AM.STypeClassLists[displayData.Type].AddIfUnique(val.Class); } } private void AddRoundDisplayData(FVRFireArmRoundDisplayData displayData) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!AM.SRoundDisplayDataDic.ContainsKey(displayData.Type)) { AM.SRoundDisplayDataDic[displayData.Type] = displayData; return; } List<DisplayDataClass> list = AM.SRoundDisplayDataDic[displayData.Type].Classes.ToList(); list.AddRange(displayData.Classes); AM.SRoundDisplayDataDic[displayData.Type].Classes = list.ToArray(); } } internal class TutorialBlockLoader : AssetBundleLoaderBase<TutorialBlock> { protected override void LoadAssetFromBundle(TutorialBlock tutorialBlock, BundleInfo bundleInfo) { if (string.IsNullOrEmpty(tutorialBlock.MediaRef.MediaPath.Path)) { LinkVideoToTutorialBlockByID(tutorialBlock, bundleInfo); } IM.TutorialBlockDic[tutorialBlock.ID] = tutorialBlock; OtherLogger.Log("Loaded tutorial block with media path: " + tutorialBlock.MediaRef.MediaPath.Path, LogTag.Assets); } private void LinkVideoToTutorialBlockByID(TutorialBlock tutorialBlock, BundleInfo bundleInfo) { string text = Path.Combine(bundleInfo.FullDirectoryName, tutorialBlock.ID + ".mp4"); if (!File.Exists(text)) { throw new FileNotFoundException("Tutorial block had no assigned path. Attempted to find MP4 file by its ID, but failed: " + text); } tutorialBlock.MediaRef.MediaPath.Path = text; } } } namespace OtherLoader.ItemSpawner { internal static class ItemSpawnerIDRegisterer { public static void Register(TL oldTL, ItemSpawnerID itemSpawnerID, bool registerInTilesDatabase, bool unifyItemIDs, bool blockDuplicateIDs, string pluginName) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) TL tL = oldTL.New("Register", LogTag.Assets); EnsureMainObjectIsNotNull(tL, itemSpawnerID); itemSpawnerID.FromMod = pluginName; if (unifyItemIDs && itemSpawnerID.MainObject?.ItemID != null) { itemSpawnerID.ItemID = itemSpawnerID.MainObject.ItemID; itemSpawnerID.MainObject.SpawnedFromId = itemSpawnerID.MainObject.ItemID; tL.Log("Unified spawner IDs"); } if (itemSpawnerID.ItemID == null) { tL.LogError("ItemSpawnerID.ItemID is null, can't register ItemSpawnerID!"); return; } tL.Log("Registering new ItemSpawnerID\n- DisplayName '" + itemSpawnerID.DisplayName + "'\n- ItemID '" + itemSpawnerID.ItemID + "'\n- MainObject.ItemID '" + (itemSpawnerID.MainObject?.ItemID ?? "null") + "'" + $"\n- Category '{itemSpawnerID.Category}'" + $"\n- SubCategory '{itemSpawnerID.SubCategory}'" + $"\n- IsDisplayedInMainEntry '{itemSpawnerID.IsDisplayedInMainEntry}'" + $"\n- SecondObject '{itemSpawnerID.SecondObject}'" + "\n- Secondaries: " + (itemSpawnerID.Secondaries?.JoinToString() ?? "null") + "\n- SecondariesByStringID: " + (itemSpawnerID.Secondaries_ByStringID?.JoinToString() ?? "null")); if (IM.HasSpawnedID(itemSpawnerID.ItemID)) { if (blockDuplicateIDs) { tL.LogWarning("Warning! Duplicates are specifically disabled for this mod! Skipping ItemSpawnerID with ID '" + itemSpawnerID.ItemID + "' because a spawner entry with the same ID is already registered!"); return; } tL.LogWarning("Warning! Registering ItemSpawnerID with ID '" + itemSpawnerID.ItemID + "' even though a spawner entry with the same ID is already registered!"); if (itemSpawnerID.IsDisplayedInMainEntry) { ManagerSingleton<IM>.Instance.SpawnerIDDic[itemSpawnerID.ItemID] = itemSpawnerID; } } else { ManagerSingleton<IM>.Instance.SpawnerIDDic[itemSpawnerID.ItemID] = itemSpawnerID; } ItemSpawnerIDTagger.RegisterSpawnerIDIntoTagSystem(itemSpawnerID); IM.CD.GetValueOrNull(itemSpawnerID.Category)?.Add(itemSpawnerID); IM.SCD.GetValueOrNull(itemSpawnerID.SubCategory)?.Add(itemSpawnerID); if (itemSpawnerID.IsDisplayedInMainEntry) { RegisteredItemSpawnerIDsDatabase.RegisteredVisibleIDs.Add(itemSpawnerID.ItemID); if (!registerInTilesDatabase) { return; } if (Enum.IsDefined(typeof(EItemCategory), itemSpawnerID.Category)) { if (!Enum.IsDefined(typeof(ESubCategory), itemSpawnerID.SubCategory)) { ItemSpawnerEntry itemSpawnerEntry = ItemSpawnerEntry.CreateEmpty($"{itemSpawnerID.SubCategory}/" + itemSpawnerID.ItemID); itemSpawnerEntry.DisplayName = itemSpawnerID.DisplayName; itemSpawnerEntry.MainObjectID = itemSpawnerID.ItemID; itemSpawnerEntry.EntryIcon = itemSpawnerID.Sprite; SpawnerTilesDatabase.TryRegister(itemSpawnerEntry); } } else { ItemSpawnerEntry itemSpawnerEntry2 = ItemSpawnerEntry.CreateEmpty($"{itemSpawnerID.Category}/" + $"{itemSpawnerID.SubCategory}/" + itemSpawnerID.ItemID); itemSpawnerEntry2.DisplayName = itemSpawnerID.DisplayName; itemSpawnerEntry2.MainObjectID = itemSpawnerID.ItemID; itemSpawnerEntry2.EntryIcon = itemSpawnerID.Sprite; SpawnerTilesDatabase.TryRegister(itemSpawnerEntry2); } } else { RegisteredItemSpawnerIDsDatabase.RegisteredHiddenIDs.Add(itemSpawnerID.ItemID); } } private static void EnsureMainObjectIsNotNull(TL oldTL, ItemSpawnerID spawnerId) { TL tL = oldTL.New("EnsureMainObjectIsNotNull"); if (!((Object)(object)spawnerId.MainObject != (Object)null)) { spawnerId.MainObject = spawnerId.Secondaries.Select((ItemSpawnerID obj) => obj.MainObject).FirstOrDefault((Func<FVRObject, bool>)((FVRObject obj) => (Object)(object)obj != (Object)null)); if ((Object)(object)spawnerId.MainObject == (Object)null) { throw new NullReferenceException("ItemSpawnerID.MainObject is null, and there are no secondary objects to use as the main object"); } spawnerId.ItemID = spawnerId.MainObject.ItemID; tL.Log("Assigned ItemID '" + spawnerId.ItemID + "' from secondary object"); } } } internal static class ItemSpawnerIDTagger { public static void RegisterSpawnerIDIntoTagSystem(ItemSpawnerID spawnerID) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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: Invalid comparison between Unknown and I4 //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Invalid comparison between Unknown and I4 //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) TL tL = new TL("RegisterSpawnerIDIntoTagSystem", LogTag.ItemSpawnerTagging); tL.Log("Attempting to tag '" + spawnerID.ItemID + "'"); PageMode spawnerPageForSpawnerId = GetSpawnerPageForSpawnerId(spawnerID); tL.Log($"Assigning item to spawner page '{spawnerPageForSpawnerId}'"); RegisterModTags(spawnerID, spawnerPageForSpawnerId); RegisterCategoryTags(spawnerID, spawnerPageForSpawnerId); if ((int)spawnerPageForSpawnerId == 1) { RegisterFirearmIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId); } else if ((int)spawnerPageForSpawnerId == 3) { RegisterAttachmentIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId); } else if ((int)spawnerPageForSpawnerId == 2) { RegisterAmmoIntoMetaTagSystem(spawnerID, spawnerPageForSpawnerId); } } private static PageMode GetSpawnerPageForSpawnerId(ItemSpawnerID spawnerId) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (ShouldItemBeTaggedAsToolsToys(spawnerId)) { return (PageMode)5; } if (ShouldItemBeTaggedAsMelee(spawnerId)) { return (PageMode)4; } if (ShouldItemBeTaggedAsAmmo(spawnerId)) { return (PageMode)2; } if ((int)ItemSubCategoryMapper.InferCategoryFrom(spawnerId.SubCategory).GetValueOrDefault() == 4) { return (PageMode)3; } if (spawnerId.IsFirearm()) { return (PageMode)1; } if ((int)spawnerId.MainObject.Category == 5) { return (PageMode)3; } return (PageMode)1; } private static void RegisterCategoryTags(ItemSpawnerID spawnerId, PageMode page) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) IM.AddMetaTag(((object)(EItemCategory)(ref spawnerId.Category)).ToString(), (TagType)2, spawnerId.ItemID, page); if ((int)spawnerId.SubCategory != 0) { IM.AddMetaTag(((object)(ESubCategory)(ref spawnerId.SubCategory)).ToString(), (TagType)3, spawnerId.ItemID, page); } } private static void RegisterModTags(ItemSpawnerID spawnerId, PageMode page) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) foreach (string modTag in spawnerId.ModTags) { IM.AddMetaTag(modTag, (TagType)50, spawnerId.ItemID, page); } IM.AddMetaTag("OtherLoader", (TagType)50, spawnerId.ItemID, page); } private static void RegisterFirearmIntoMetaTagSystem(ItemSpawnerID itemSpawnerID, PageMode page) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) ItemSpawnerID itemSpawnerID2 = itemSpawnerID; FVRObject mainObject = itemSpawnerID2.MainObject; IM.AddMetaTag(((object)(OTagSet)(ref mainObject.TagSet)).ToString(), (TagType)4, itemSpawnerID2.ItemID, page); if ((int)mainObject.TagEra != 0) { IM.AddMetaTag(((object)(OTagEra)(ref mainObject.TagEra)).ToString(), (TagType)6, itemSpawnerID2.ItemID, page); } if ((int)mainObject.TagFirearmSize != 0) { IM.AddMetaTag(((object)(OTagFirearmSize)(ref mainObject.TagFirearmSize)).ToString(), (TagType)5, itemSpawnerID2.ItemID, page); } if ((int)mainObject.TagFirearmAction != 0) { IM.AddMetaTag(((object)(OTagFirearmAction)(ref mainObject.TagFirearmAction)).ToString(), (TagType)7, itemSpawnerID2.ItemID, page); } if ((int)mainObject.TagFirearmRoundPower != 0) { IM.AddMetaTag(((object)(OTagFirearmRoundPower)(ref mainObject.TagFirearmRoundPower)).ToString(), (TagType)8, itemSpawnerID2.ItemID, page); } if ((int)mainObject.TagFirearmCountryOfOrigin != 0) { IM.AddMetaTag(((object)(OTagFirearmCountryOfOrigin)(ref mainObject.TagFirearmCountryOfOrigin)).ToString(), (TagType)10, itemSpawnerID2.ItemID, page); } if (mainObject.TagFirearmFirstYear != 0) { IM.AddMetaTag(mainObject.TagFirearmFirstYear.ToString(), (TagType)11, itemSpawnerID2.ItemID, page); } if ((int)mainObject.MagazineType != 0) { IM.AddMetaTag(((object)(FireArmMagazineType)(ref mainObject.MagazineType)).ToString(), (TagType)14, itemSpawnerID2.ItemID, page); } if (mainObject.UsesRoundTypeFlag) { IM.AddMetaTag(((object)(FireArmRoundType)(ref mainObject.RoundType)).ToString(), (TagType)9, itemSpawnerID2.ItemID, page); } mainObject.TagFirearmFiringModes.ForEach(delegate(OTagFirearmFiringMode tag) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((int)tag != 0) { IM.AddMetaTag(((object)(OTagFirearmFiringMode)(ref tag)).ToString(), (TagType)12, itemSpawnerID2.ItemID, page); } }); mainObject.TagFirearmFeedOption.ForEach(delegate(OTagFirearmFeedOption tag) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((int)tag != 0) { IM.AddMetaTag(((object)(OTagFirearmFeedOption)(ref tag)).ToString(), (TagType)13, itemSpawnerID2.ItemID, page); } }); mainObject.TagFirearmMounts.ForEach(delegate(OTagFirearmMount tag) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((int)tag != 0) { IM.AddMetaTag(((object)(OTagFirearmMount)(ref tag)).ToString(), (TagType)15, itemSpawnerID2.ItemID, page); } }); } private static void RegisterAttachmentIntoMetaTagSystem(ItemSpawnerID itemSpawnerID, PageMode page) { //IL_001f: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) FVRObject mainObject = itemSpawnerID.MainObject; IM.AddMetaTag(((object)(OTagSet)(ref mainObject.TagSet)).ToString(), (TagType)4, itemSpawnerID.ItemID, page); if ((int)mainObject.TagEra != 0) { IM.AddMetaTag(((object)(OTagEra)(ref mainObject.TagEra)).ToString(), (TagType)6, itemSpawnerID.ItemID, page); } if ((int)mainObject.TagAttachmentFeature != 0) { IM.AddMetaTag(((object)(OTagAttachmentFeature)(ref mainObject.TagAttachmentFeature)).ToString(), (TagType)16, itemSpawnerID.ItemID, page); } if ((int)mainObject.TagAttachmentMount != 0) { IM.AddMetaTag(((object)(OTagFirearmMount)(ref mainObject.TagAttachmentMount)).ToString(), (TagType)15, itemSpawnerID.ItemID, page); } } private static void RegisterAmmoIntoMetaTagSystem(ItemSpawnerID itemSpawnerID, PageMode page) { //IL_001f: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) FVRObject mainObject = itemSpawnerID.MainObject; IM.AddMetaTag(((object)(OTagSet)(ref mainObject.TagSet)).ToString(), (TagType)4, itemSpawnerID.ItemID, page); if ((int)mainObject.TagEra != 0) { IM.AddMetaTag(((object)(OTagEra)(ref mainObject.TagEra)).ToString(), (TagType)6, itemSpawnerID.ItemID, page); } if ((int)mainObject.MagazineType != 0) { IM.AddMetaTag(((object)(FireArmMagazineType)(ref mainObject.MagazineType)).ToString(), (TagType)14, itemSpawnerID.ItemID, page); } if (mainObject.UsesRoundTypeFlag) { IM.AddMetaTag(((object)(FireArmRoundType)(ref mainObject.RoundType)).ToString(), (TagType)9, itemSpawnerID.ItemID, page); } } private static bool ShouldItemBeTaggedAsToolsToys(ItemSpawnerID spawnerId) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_003b: 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_004e: Invalid comparison between Unknown and I4 if ((int)spawnerId.MainObject.Category != 20 && (int)spawnerId.MainObject.Category != 7 && (int)spawnerId.SubCategory != 15 && (int)spawnerId.SubCategory != 61 && (int)spawnerId.Category != 6) { return (int)ItemSubCategoryMapper.InferCategoryFrom(spawnerId.SubCategory).GetValueOrDefault() == 6; } return true; } private static bool ShouldItemBeTaggedAsMelee(ItemSpawnerID spawnerId) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 if ((int)spawnerId.MainObject.Category != 10 && (int)spawnerId.Category != 5 && (int)spawnerId.SubCategory != 46) { return (int)ItemSubCategoryMapper.InferCategoryFrom(spawnerId.SubCategory).GetValueOrDefault() == 5; } return true; } private static bool ShouldItemBeTaggedAsAmmo(ItemSpawnerID spawnerId) { //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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: 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: Invalid comparison between Unknown and I4 EItemCategory category = spawnerId.Category; if (category - 7 <= 1 || category - 10 <= 1) { return true; } return false; } } internal static class RegisteredItemSpawnerIDsDatabase { public static readonly HashSet<string> RegisteredVisibleIDs = new HashSet<string>(); public static readonly HashSet<string> RegisteredHiddenIDs = new HashSet<string>(); public static readonly HashSet<string> RegisteredInCustomCategoryIDs = new HashSet<string>(); } internal static class SpawnerEntryToSpawnerIDConverter { public static ItemSpawnerID Convert(TL oldTL, ItemSpawnerEntry entry) { TL newTL = oldTL.New("Convert"); ItemSpawnerID val = ScriptableObject.CreateInstance<ItemSpawnerID>(); AssignCategoriesForSpawnerID(newTL, val, entry); val.DisplayName = entry.DisplayName; val.IsDisplayedInMainEntry = entry.IsDisplayedInMainEntry; val.ItemID = entry.MainObjectID; val.ModTags = entry.ModTags; val.MainObject = entry.MainObjectObj; ItemSpawnerIDLinker.QueueEntryToLink(new EntryToLink(val, entry.SpawnWithIDs, entry.SecondaryObjectIDs)); FVRObject val2 = ItemSpawnerIDLinker.ResolveObjectIDsToFVRObjects(entry.SpawnWithIDs).FirstOrDefault(); if ((Object)(object)val2 != (Object)null) { val.SecondObject = val2; } val.Secondaries_ByStringID = ItemSpawnerIDLinker.ResolveObjectIDsToSpawnerIDs(entry.SecondaryObjectIDs).ToList(); val.Secondaries = (ItemSpawnerID[])(object)new ItemSpawnerID[0]; val.Sprite = entry.EntryIcon; val.UsesLargeSpawnPad = entry.UsesLargeSpawnPad; val.UsesHugeSpawnPad = entry.UsesHugeSpawnPad; val.IsReward = entry.IsReward; val.TutorialBlocks = entry.TutorialBlockIDs; return val; } private static void AssignCategoriesForSpawnerID(TL newTL, ItemSpawnerID itemSpawnerID, ItemSpawnerEntry entry) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) PageMode? vanillaSpawnerPage = entry.GetVanillaSpawnerPage(); EItemCategory? vanillaSpawnerCategory = entry.GetVanillaSpawnerCategory(); ESubCategory? vanillaSpawnerSubCategory = entry.GetVanillaSpawnerSubCategory(); if (vanillaSpawnerCategory.HasValue) { itemSpawnerID.Category = vanillaSpawnerCategory.Value; itemSpawnerID.SubCategory = (ESubCategory)0; newTL.Log("Updated item categories:" + $"\n- Category '{itemSpawnerID.Category}' read from EntryPath" + $"\n- SubCategory '{itemSpawnerID.SubCategory}'"); } else if (vanillaSpawnerSubCategory.HasValue) { EItemCategory? val = ItemSubCategoryMapper.InferCategoryFrom(vanillaSpawnerSubCategory.Value); if (!val.HasValue) { itemSpawnerID.Category = (EItemCategory)0; itemSpawnerID.SubCategory = vanillaSpawnerSubCategory.Value; newTL.Log("Updated item categories:" + $"\n- Category '{itemSpawnerID.Category}' (failed to infer from SubCategory)" + $"\n- SubCategory '{itemSpawnerID.SubCategory}' read from EntryPath"); return; } PageMode? val2 = ItemSubCategoryMapper.InferPageFrom(val.Value); if (val2.HasValue && vanillaSpawnerPage.HasValue && vanillaSpawnerPage != val2) { entry.IsUncategorized = true; itemSpawnerID.Category = (EItemCategory)621113382; itemSpawnerID.SubCategory = (ESubCategory)0; newTL.Log("Updated item categories:" + $"\n- Category '{621113382}' (Miscellaneous category)" + $"\n- SubCategory '{itemSpawnerID.SubCategory}'"); } else { itemSpawnerID.Category = val.Value; itemSpawnerID.SubCategory = vanillaSpawnerSubCategory.Value; newTL.Log("Updated item categories:" + $"\n- Category '{itemSpawnerID.Category}' inferred from SubCategory" + $"\n- SubCategory '{itemSpawnerID.SubCategory}' read from EntryPath"); } } else { itemSpawnerID.Category = (EItemCategory)CreateCustomEItemCategoryInt(newTL, entry); itemSpawnerID.SubCategory = (ESubCategory)0; newTL.Log("Updated item categories:" + $"\n- Category '{itemSpawnerID.Category}' (custom category)" + $"\n- SubCategory '{itemSpawnerID.SubCategory}'"); } } private static int CreateCustomEItemCategoryInt(TL oldTL, ItemSpawnerEntry entry) { if (string.IsNullOrEmpty(entry.EntryPath)) { return 0; } TL tL = oldTL.New("CreateCustomEItemCategoryInt"); string[] array = entry.EntryPath.Split(new char[1] { '/' }); IEnumerable<string> values; if (!entry.IsCategoryEntry()) { values = array.Take(array.Length - 1); } else { IEnumerable<string> enumerable = array; values = enumerable; } string text = values.JoinToString("/"); int num = Hasher.HashStringToInt(text); tL.Log($"Hashed '{text}' to custom EItemCategory integer: {num}"); return num; } private static PageMode? GetVanillaSpawnerPage(this ItemSpawnerEntry entry) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) string[] array = entry.EntryPath.Split(new char[1] { '/' }); if (array.Length < 1) { return null; } string value = array[0]; if (Enum.IsDefined(typeof(PageMode), value)) { return (PageMode)Enum.Parse(typeof(PageMode), value); } return null; } private static EItemCategory? GetVanillaSpawnerCategory(this ItemSpawnerEntry entry) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) string[] array = entry.EntryPath.Split(new char[1] { '/' }); if (array.Length < 2) { return null; } string value = array[1]; if (Enum.IsDefined(typeof(EItemCategory), value)) { return (EItemCategory)Enum.Parse(typeof(EItemCategory), value); } return null; } private static ESubCategory? GetVanillaSpawnerSubCategory(this ItemSpawnerEntry entry) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) string[] array = entry.EntryPath.Split(new char[1] { '/' }); if (array.Length < 2) { return null; } string value = array[1]; if (Enum.IsDefined(typeof(ESubCategory), value)) { return (ESubCategory)Enum.Parse(typeof(ESubCategory), value); } return null; } } } namespace OtherLoader.ItemSpawner.VanillaCategories { internal enum ItemSpawnerSortGrouping { ShowModdedItemsFirst, ShowModdedItemsLast, NoGrouping } internal enum ItemSpawnerSortOrder { Vanilla, AlphabeticalByDisplayName } internal static class ItemSpawnerV2DisplayItemsPatcher { [HarmonyTranspiler] [HarmonyPatch(typeof(ItemSpawnerV2), "RedrawSimpleCanvas")] private static IEnumerable<CodeInstruction> RedrawSimpleCanvas_Transpiler_ApplyCustomSorting(IEnumerable<CodeInstruction> instructions) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) List<CodeInstruction> list = instructions.ToList(); try { return new CodeMatcher((IEnumerable<CodeInstruction>)list, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Callvirt && code.operand == AccessTools.Method(typeof(List<string>), "Sort", (Type[])null, (Type[])null))).SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnerIDSorter), "FilterAndSortItemsSimpleMode", (Type[])null, (Type[])null)).InstructionEnumeration(); } catch (Exception arg) { OtherLogger.LogError($"Exception in RedrawSimpleCanvas transpiler: {arg}"); return list; } } [HarmonyTranspiler] [HarmonyPatch(typeof(ItemSpawnerV2), "RedrawListCanvas")] private static IEnumerable<CodeInstruction> RedrawListCanvas_Transpiler_ApplyCustomSorting(IEnumerable<CodeInstruction> instructions) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) List<CodeInstruction> list = instructions.ToList(); try { return new CodeMatcher((IEnumerable<CodeInstruction>)list, (ILGenerator)null).SearchForward((Func<CodeInstruction, bool>)((CodeInstruction code) => code.opcode == OpCodes.Callvirt && code.operand == AccessTools.Method(typeof(List<string>), "Sort", (Type[])null, (Type[])null))).SetAndAdvance(OpCodes.Call, (object)AccessTools.Method(typeof(SpawnerIDSorter), "FilterAndSortItemsTagMode", (Type[])null, (Type[])null)).InstructionEnumeration(); } catch (Exception arg) { OtherLogger.LogError($"Exception in RedrawListCanvas transpiler: {arg}"); return list; } } } internal static class SpawnerIDSorter { public static void FilterAndSortItemsSimpleMode(List<string> workingItemSpawnerIDs) { FilterAndSortItems(workingItemSpawnerIDs, includeHiddenIDs: false); } public static void FilterAndSortItemsTagMode(List<string> workingItemSpawnerIDs) { FilterAndSortItems(workingItemSpawnerIDs, includeHiddenIDs: true); } private static void FilterAndSortItems(List<string> workingItemSpawnerIDs, bool includeHiddenIDs) { List<string> list = workingItemSpawnerIDs.ToList(); workingItemSpawnerIDs.Clear(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); foreach (string item in list) { if (RegisteredItemSpawnerIDsDatabase.RegisteredInCustomCategoryIDs.Contains(item)) { if (includeHiddenIDs) { list3.Add(item); } } else if (RegisteredItemSpawnerIDsDatabase.RegisteredVisibleIDs.Contains(item)) { list3.Add(item); } else if (RegisteredItemSpawnerIDsDatabase.RegisteredHiddenIDs.Contains(item)) { if (includeHiddenIDs) { list3.Add(item); } } else { list2.Add(item); } } OtherLogger.Log($"Sorting tiles: {list2.Count} vanilla, {list3.Count} modded. " + $"Showing hidden: {includeHiddenIDs}", LogTag.ItemSpawnerPatches); switch (PluginConfig.ItemSpawnerSortGrouping.Value) { default: SortListCustom(list2); SortListCustom(list3); workingItemSpawnerIDs.AddRange(list3); workingItemSpawnerIDs.AddRange(list2); break; case ItemSpawnerSortGrouping.ShowModdedItemsLast: SortListCustom(list2); SortListCustom(list3); workingItemSpawnerIDs.AddRange(list2); workingItemSpawnerIDs.AddRange(list3); break; case ItemSpawnerSortGrouping.NoGrouping: workingItemSpawnerIDs.AddRange(list2); workingItemSpawnerIDs.AddRange(list3); SortListCustom(workingItemSpawnerIDs); break; } } private static void SortListCustom(List<string> list) { ItemSpawnerSortOrder value = PluginConfig.ItemSpawnerSortOrder.Value; if (value == ItemSpawnerSortOrder.Vanilla || value != ItemSpawnerSortOrder.AlphabeticalByDisplayN