using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Localizer; using ModifAmorphic.Outward.Config.Extensions; using ModifAmorphic.Outward.Config.Models; using ModifAmorphic.Outward.Events; using ModifAmorphic.Outward.Extensions; using ModifAmorphic.Outward.GameObjectResources; using ModifAmorphic.Outward.Internal; using ModifAmorphic.Outward.Localization; using ModifAmorphic.Outward.Logging; using ModifAmorphic.Outward.Models; using ModifAmorphic.Outward.Modules.CharacterMods; using ModifAmorphic.Outward.Modules.Crafting; using ModifAmorphic.Outward.Modules.Crafting.CompatibleIngredients; using ModifAmorphic.Outward.Modules.Crafting.Models; using ModifAmorphic.Outward.Modules.Crafting.Patches; using ModifAmorphic.Outward.Modules.Crafting.Services; using ModifAmorphic.Outward.Modules.Items; using ModifAmorphic.Outward.Modules.Items.Models; using ModifAmorphic.Outward.Modules.Items.Patches; using ModifAmorphic.Outward.Modules.Localization; using ModifAmorphic.Outward.Modules.Merchants; using ModifAmorphic.Outward.Modules.QuickSlots; using ModifAmorphic.Outward.Modules.QuickSlots.KeyBindings; using ModifAmorphic.Outward.Modules.QuickSlots.KeyBindings.Services; using ModifAmorphic.Outward.Patches; using Rewired; using SideLoader; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("ModifAmorphic.Outward")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0748ee4c3e5cabdf3003c1bbf7caa92a7535e9c1")] [assembly: AssemblyProduct("ModifAmorphic.Outward")] [assembly: AssemblyTitle("ModifAmorphic.Outward.Shared.v0_0_0_9")] [assembly: AssemblyVersion("1.0.0.0")] namespace ModifAmorphic.Outward { internal static class DefaultLoggerInfo { public const string ModId = "modifamorphic.outward.shared"; public const string ModName = "ModifAmorphic"; public const LogLevel DebugLogLevel = LogLevel.Trace; } public static class ItemTags { private static Tag _equipmentTag; private static Tag _weaponTag; private static Tag _bowTag; private static Tag _pistolTag; private static Tag _chakramTag; private static Tag _helmetTag; private static Tag _armorTag; private static Tag _bootsTag; private static Tag _dagueTag; private static Tag _trinketTag; private static Tag _lanternTag; private static Tag _lexiconTag; private static Tag _backpackTag; private static Tag _enchantIngredientsTag; public static Tag EquipmentTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _equipmentTag)).IsSet) { _equipmentTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("13")); } return _equipmentTag; } } public static Tag WeaponTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _weaponTag)).IsSet) { _weaponTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("1")); } return _weaponTag; } } public static Tag BowTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _bowTag)).IsSet) { _bowTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("8")); } return _bowTag; } } public static Tag PistolTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _pistolTag)).IsSet) { _pistolTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("21")); } return _pistolTag; } } public static Tag ChakramTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _chakramTag)).IsSet) { _chakramTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("160")); } return _chakramTag; } } public static Tag HelmetTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _helmetTag)).IsSet) { _helmetTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("14")); } return _helmetTag; } } public static Tag ArmorTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _armorTag)).IsSet) { _armorTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("15")); } return _armorTag; } } public static Tag BootsTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _bootsTag)).IsSet) { _bootsTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("16")); } return _bootsTag; } } public static Tag DagueTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _dagueTag)).IsSet) { _dagueTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("22")); } return _dagueTag; } } public static Tag TrinketTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _trinketTag)).IsSet) { _trinketTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("17")); } return _trinketTag; } } public static Tag LanternTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _lanternTag)).IsSet) { _lanternTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("37")); } return _lanternTag; } } public static Tag LexiconTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _lexiconTag)).IsSet) { _lexiconTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("161")); } return _lexiconTag; } } public static Tag BackpackTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _backpackTag)).IsSet) { _backpackTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("68")); } return _backpackTag; } } public static Tag EnchantIngredientsTag { get { //IL_002b: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!((Tag)(ref _enchantIngredientsTag)).IsSet) { _enchantIngredientsTag = TagSourceManager.Instance.GetTag(UID.op_Implicit("54")); } return _enchantIngredientsTag; } } } public class ServicesProvider { private readonly ConcurrentDictionary _serviceFactories = new ConcurrentDictionary(); private readonly NullLogger nullLogger = new NullLogger(); public BaseUnityPlugin UnityPlugin => GetService(); private IModifLogger Logger { get { IModifLogger result; if (!TryGetLogger(out var logger)) { IModifLogger modifLogger = nullLogger; result = modifLogger; } else { result = logger; } return result; } } public ServicesProvider(BaseUnityPlugin unityPlugin) { AddSingleton(unityPlugin); } public ServicesProvider AddSingleton(T serviceInstance) { _serviceFactories.TryAdd(typeof(T), (Func)(() => serviceInstance)); return this; } public ServicesProvider AddFactory(Func serviceFactory) { _serviceFactories.TryAdd(typeof(T), serviceFactory); return this; } public Func GetServiceFactory() { Logger.LogTrace("ServicesProvider::GetServiceFactory: Type: " + typeof(T).Name); return (Func)_serviceFactories[typeof(T)]; } public T GetService() { Logger.LogTrace("ServicesProvider::GetService: Type: " + typeof(T).Name); return (T)_serviceFactories[typeof(T)].DynamicInvoke(); } public object GetService(Type type) { Logger.LogTrace("ServicesProvider::GetService: Type: " + type.Name); return _serviceFactories[type].DynamicInvoke(); } public List GetServices() { Logger.LogTrace("ServicesProvider::GetServices: Type: " + typeof(T).Name); return (from kvp in _serviceFactories where typeof(T).IsAssignableFrom(kvp.Key) select (T)kvp.Value.DynamicInvoke()).ToList(); } public List> GetServiceFactories() { Logger.LogTrace("ServicesProvider::GetServiceFactories: Type: " + typeof(T).Name); return (from kvp in _serviceFactories where typeof(T).IsAssignableFrom(kvp.Key) select (Func)kvp.Value).ToList(); } public bool TryGetService(out T service) { Logger.LogTrace("ServicesProvider::TryGetService: Type: " + typeof(T).Name); service = default(T); if (!_serviceFactories.TryGetValue(typeof(T), out var value)) { return false; } service = (T)value.DynamicInvoke(); return !EqualityComparer.Default.Equals(service, default(T)); } private bool TryGetLogger(out IModifLogger logger) { logger = null; if (!_serviceFactories.TryGetValue(typeof(IModifLogger), out var value)) { return false; } logger = (IModifLogger)value.DynamicInvoke(); return logger != null; } } } namespace ModifAmorphic.Outward.Patches { [HarmonyPatch(typeof(LocalizationManager))] public static class LocalizationManagerPatches { public delegate void RegisterItemLocalizations(ref Dictionary itemLocalizations); [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static event Action AwakeAfter; public static event Action LoadAfter; public static event RegisterItemLocalizations LoadItemLocalizationAfter; [HarmonyPatch("Awake")] [HarmonyPostfix] private static void AwakePostfix(LocalizationManager __instance) { try { Logger.LogTrace(string.Format("{0}::{1}(): Invoked. Invoking {2}({3}). AwakeAfter null: {4}", "LocalizationManagerPatches", "AwakePostfix", "AwakePostfix", "LocalizationManager", LocalizationManagerPatches.AwakeAfter == null)); LocalizationManagerPatches.AwakeAfter?.Invoke(__instance); } catch (Exception ex) { Logger.LogException("LocalizationManagerPatches::AwakePostfix(): Exception Invoking AwakePostfix(LocalizationManager).", ex); } } [HarmonyPatch("Load")] [HarmonyPostfix] private static void LoadPostfix(LocalizationManager __instance) { try { Logger.LogTrace("LocalizationManagerPatches::LoadPostfix(): Invoked. Invoking LoadAfter(LocalizationManager)."); LocalizationManagerPatches.LoadAfter?.Invoke(__instance); } catch (Exception ex) { Logger.LogException("LocalizationManagerPatches::LoadPostfix(): Exception Invoking LoadAfter(LocalizationManager).", ex); } } [HarmonyPatch("LoadItemLocalization")] [HarmonyPostfix] private static void LoadItemLocalizationPostfix(ref Dictionary ___m_itemLocalization) { try { Logger.LogTrace("LocalizationManagerPatches::LoadItemLocalizationPostfix(): Invoked. Invoking LoadItemLocalizationPostfix(Dictionary)"); LocalizationManagerPatches.LoadItemLocalizationAfter?.Invoke(ref ___m_itemLocalization); } catch (Exception ex) { Logger.LogException("LocalizationManagerPatches::LoadItemLocalizationPostfix(): Exception Invoking LoadItemLocalizationPostfix(Dictionary).", ex); } } } } namespace ModifAmorphic.Outward.Modules { internal interface IModifModule { HashSet PatchDependencies { get; } HashSet DepsWithMultiLogger { get; } HashSet EventSubscriptions { get; } } internal abstract class ModifModule { public IModifLogger Logger { get; } public ModifModule(IModifLogger modifLogger) { Logger = modifLogger; } } public static class ModifModules { private static ModuleService _lazyService; private static ModuleService ModuleService { get { if (_lazyService == null) { _lazyService = new ModuleService(); } return _lazyService; } } public static QuickSlotExtender GetQuickSlotExtenderModule(string modId) { return ModuleService.GetModule(modId, () => new QuickSlotExtender(new QsMenuExtender(() => LoggerFactory.GetLogger(modId)), () => LoggerFactory.GetLogger(modId))); } public static CharacterInstances GetCharacterInstancesModule(string modId) { return ModuleService.GetModule(modId, () => new CharacterInstances(() => LoggerFactory.GetLogger(modId))); } public static PreFabricator GetPreFabricatorModule(string modId) { ItemPrefabService itemPrefabService = new ItemPrefabService(modId, new ModifGoService(() => LoggerFactory.GetLogger(modId)), () => ResourcesPrefabManager.Instance, () => LoggerFactory.GetLogger(modId)); return ModuleService.GetModule(modId, () => new PreFabricator(modId, itemPrefabService, () => LoggerFactory.GetLogger(modId))); } public static ItemVisualizer GetItemVisualizerModule(string modId) { IconService iconService = new IconService(modId, new ModifGoService(() => LoggerFactory.GetLogger(modId)), () => LoggerFactory.GetLogger(modId)); return ModuleService.GetModule(modId, () => new ItemVisualizer(() => ResourcesPrefabManager.Instance, () => ItemManager.Instance, iconService, () => LoggerFactory.GetLogger(modId))); } public static MerchantModule GetMerchantModule(string modId) { return ModuleService.GetModule(modId, () => new MerchantModule(() => LoggerFactory.GetLogger(modId))); } public static CustomCraftingModule GetCustomCraftingModule(string modId) { CraftingMenuUIService craftingMenuUIService = new CraftingMenuUIService(() => LoggerFactory.GetLogger(modId)); CraftingMenuEvents craftingMenuEvents = new CraftingMenuEvents(); return ModuleService.GetModule(modId, () => new CustomCraftingModule(new CraftingMenuUIService(() => LoggerFactory.GetLogger(modId)), new RecipeDisplayService(() => LoggerFactory.GetLogger(modId)), new CustomRecipeService(() => RecipeManager.Instance, () => LoggerFactory.GetLogger(modId)), new CustomCraftingService(craftingMenuEvents, () => LoggerFactory.GetLogger(modId)), craftingMenuEvents, () => LoggerFactory.GetLogger(modId))); } public static LocalizationModule GetLocalizationModule(string modId) { return ModuleService.GetModule(modId, () => new LocalizationModule(() => LoggerFactory.GetLogger(modId))); } } internal class ModuleService { private Harmony _patcher = null; private readonly ConcurrentDictionary _patchedTypes = new ConcurrentDictionary(); private readonly ConcurrentDictionary _subscriberTypes = new ConcurrentDictionary(); private readonly ConcurrentDictionary> _instances = new ConcurrentDictionary>(); internal T GetModule(string modId, Func factory) where T : class, IModifModule { ConcurrentDictionary orAdd = _instances.GetOrAdd(modId, new ConcurrentDictionary()); return orAdd.GetOrAdd(typeof(T), (Type x) => CreateModule(modId, factory)) as T; } private IModifModule CreateModule(string modId, Func factory) where T : class, IModifModule { T module = factory(); LoggerEvents.LoggerCreated += delegate((string ModId, IModifLogger Logger) args) { if (args.ModId == modId) { ConfigureMultiLoggersForDependencies(modId, module, () => LoggerFactory.GetLogger(modId)); } }; ConfigureMultiLoggersForDependencies(modId, module, () => LoggerFactory.GetLogger(modId)); ApplyPatches(module); ConfigureSubscriptions(module, () => LoggerFactory.GetLogger(modId)); return module; } internal IModifModule ConfigureSubscriptions(IModifModule module, Func getLogger) { foreach (Type eventSubscription in module.EventSubscriptions) { if (!_subscriberTypes.ContainsKey(eventSubscription)) { _subscriberTypes.TryAdd(eventSubscription, 0); EventSubscriberService.RegisterClassSubscriptions(eventSubscription, getLogger()); } } return module; } private void ConfigureMultiLoggersForDependencies(string modId, IModifModule module, Func loggerFactory) { foreach (Type item in module.DepsWithMultiLogger) { PatchLoggerRegisterService.AddOrUpdatePatchLogger(item, modId, loggerFactory); } } private IModifModule ApplyPatches(IModifModule module) { foreach (Type patchDependency in module.PatchDependencies) { if (!_patchedTypes.ContainsKey(patchDependency)) { _patchedTypes.TryAdd(patchDependency, 0); GetModPatcher().PatchAll(patchDependency); if (patchDependency == typeof(LocalizationManagerPatches)) { LocalizationService.Init(); } } } return module; } private Harmony GetModPatcher() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_001d: Expected O, but got Unknown Harmony obj = _patcher; if (obj == null) { Harmony val = new Harmony("modifamorphic.outward"); Harmony val2 = val; _patcher = val; obj = val2; } return obj; } } } namespace ModifAmorphic.Outward.Modules.QuickSlots { public class QuickSlotExtender : IModifModule { private readonly Func _loggerFactory; private readonly QsMenuExtender _qsMenuExtender; private IModifLogger Logger => _loggerFactory(); public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterQuickSlotManagerPatches)); hashSet.Add(typeof(KeyboardQuickSlotPanelPatches)); hashSet.Add(typeof(LocalCharacterControlPatches)); hashSet.Add(typeof(QsLocalizationManagerPatches)); return hashSet; } } public HashSet EventSubscriptions { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterQuickSlotManagerPatches)); hashSet.Add(typeof(KeyboardQuickSlotPanelPatches)); hashSet.Add(typeof(LocalCharacterControlPatches)); hashSet.Add(typeof(QsLocalizationManagerPatches)); return hashSet; } } public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterQuickSlotManagerPatches)); hashSet.Add(typeof(KeyboardQuickSlotPanelPatches)); hashSet.Add(typeof(LocalCharacterControlPatches)); hashSet.Add(typeof(QsLocalizationManagerPatches)); return hashSet; } } [MethodImpl(MethodImplOptions.NoInlining)] internal QuickSlotExtender(QsMenuExtender qsMenuExtender, Func loggerFactory) { _loggerFactory = loggerFactory; _qsMenuExtender = qsMenuExtender; } public void ExtendQuickSlots(int extendAmount, string menuDescriptionFormat) { List list = _qsMenuExtender.ExtendQuickSlots(extendAmount, menuDescriptionFormat); CharacterQuickSlotManagerPatches.Configure(list.Count); KeyboardQuickSlotPanelPatches.Configure(list.Count, list.First().QuickSlotId); LocalCharacterControlPatches.Configure(list); QsLocalizationManagerPatches.Configure(list); } } } namespace ModifAmorphic.Outward.Modules.QuickSlots.KeyBindings { internal class ExtendedQuickSlot { public int QuickSlotId { get; set; } public string ActionName { get; set; } public string ActionKey { get; set; } public string ActionDescription { get; set; } } internal class MoreQuickslotsLocalizationListener : ILocalizeListener { private readonly Dictionary qsLocalizations; private readonly IModifLogger logger; public MoreQuickslotsLocalizationListener(Dictionary qsLocalizations, IModifLogger logger) { this.logger = logger; this.qsLocalizations = qsLocalizations; } public void Localize() { logger.LogInfo(string.Format("{0} Adding {1} new localizations for quickslots.", "MoreQuickslotsLocalizationListener", qsLocalizations.Count)); Dictionary generalLocalizations = LocalizationManager.Instance.GetGeneralLocalizations(); StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair qsLocalization in qsLocalizations) { if (!generalLocalizations.ContainsKey(qsLocalization.Key)) { generalLocalizations.Add(qsLocalization.Key, qsLocalization.Value); stringBuilder.AppendLine("\tname: " + qsLocalization.Key + ", desc: " + qsLocalization.Value); } } logger.LogDebug(string.Format("{0} Localizations Added:\n{1}.", "MoreQuickslotsLocalizationListener", stringBuilder)); LocalizationManager.Instance.SetGeneralLocalizations(generalLocalizations); } } [HarmonyPatch(typeof(CharacterQuickSlotManager), "Awake")] internal static class CharacterQuickSlotManagerPatches { private static int _quickslotsToAdd; private static bool _isAwakened = false; [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static void Configure(int qsToAdd) { if (_isAwakened) { throw new InvalidOperationException("CharacterQuickSlotManagerPatches.Configure cannot be called after the CharacterQuickSlotManager's Awake method has been called."); } _quickslotsToAdd = qsToAdd; } [HarmonyPrefix] public static void OnAwake_AddQuickSlots(CharacterQuickSlotManager __instance) { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown _isAwakened = true; if (_quickslotsToAdd < 1) { return; } try { Transform val = ((Component)__instance).transform.Find("QuickSlots"); int num = val.childCount + 1; Logger.LogDebug($"Adding {_quickslotsToAdd} extra quickslots to the CharacterQuickSlotManager QuickSlots transform. Starting with Id {num}."); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("\n\t//////*************quickslotTransform Start*************//////"); for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i); QuickSlot component = ((Component)child).gameObject.GetComponent(); stringBuilder.AppendLine($"\tIndex: {i}; GameObject Name: {((Object)((Component)child).gameObject).name}; QuickSlot Name: {((Object)component).name}"); } stringBuilder.AppendLine("\t//////*************quickslotTransform End*************//////"); Logger.LogTrace(stringBuilder.ToString()); for (int j = 0; j < _quickslotsToAdd; j++) { GameObject val2 = new GameObject($"ExtraQuickSlot_{j}"); Logger.LogDebug(string.Format("{0}(): created new GameObject(ExtraQuickSlot_{1}). gameObject.name: '{2}'", "OnAwake_AddQuickSlots", j, ((Object)val2).name)); QuickSlot val3 = val2.AddComponent(); ((Object)val3).name = (num + j).ToString(); val2.transform.SetParent(val); } val.SetParent(((Component)__instance).transform); Transform val4 = ((Component)__instance).transform.Find("QuickSlots"); stringBuilder = new StringBuilder(); stringBuilder.AppendLine("\n\t//////*************quickslotTransformAfterSetParent after quickslotTransform.SetParent(self.transform) Start*************//////"); if ((Object)(object)val4 != (Object)null) { for (int k = 0; k < val4.childCount; k++) { Transform child2 = val4.GetChild(k); object obj; if (child2 == null) { obj = null; } else { GameObject gameObject = ((Component)child2).gameObject; obj = ((gameObject != null) ? gameObject.GetComponent() : null); } QuickSlot val5 = (QuickSlot)obj; StringBuilder stringBuilder2 = stringBuilder; object[] obj2 = new object[4] { k, (child2 != null) ? ((Object)child2).name : null, null, null }; object obj3; if (child2 == null) { obj3 = null; } else { GameObject gameObject2 = ((Component)child2).gameObject; obj3 = ((gameObject2 != null) ? ((Object)gameObject2).name : null); } obj2[2] = obj3; obj2[3] = ((val5 != null) ? ((Object)val5).name : null); stringBuilder2.AppendLine(string.Format("\tIndex: {0}; Child Name: {1}; GameObject Name: {2}; QuickSlot Name: {3}", obj2)); } } else { stringBuilder.AppendLine("\tquickslotTransformAfterSetParent null. No GameObjects."); } stringBuilder.AppendLine("\t//////*************quickslotTransformAfterSetParent after quickslotTransform.SetParent(self.transform) End*************//////"); Logger.LogDebug(stringBuilder.ToString()); Logger.LogDebug("OnAwake_AddQuickSlots(): complete."); } catch (Exception ex) { Logger.LogException("OnAwake_AddQuickSlots() error.", ex); throw; } } } [HarmonyPatch(typeof(KeyboardQuickSlotPanel), "InitializeQuickSlotDisplays")] internal static class KeyboardQuickSlotPanelPatches { private static int _quickslotsToAdd; private static int _quickslotStartId; private static bool _isInitialized = false; [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static void Configure(int qsToAdd, int qsStartId) { if (_isInitialized) { throw new InvalidOperationException("KeyboardQuickSlotPanelPatches.Configure cannot be called after the KeyboardQuickSlotPanel's InitializeQuickSlotDisplays method has been called."); } _quickslotsToAdd = qsToAdd; _quickslotStartId = qsStartId; } [HarmonyPrefix] public static void OnInitializeQuickSlotDisplays_AddExtraSlots(KeyboardQuickSlotPanel __instance) { _isInitialized = true; if (_quickslotsToAdd < 1) { return; } try { int num = __instance.DisplayOrder.Length; int num2 = __instance.DisplayOrder.Length + _quickslotsToAdd; int quickslotStartId = _quickslotStartId; Array.Resize(ref __instance.DisplayOrder, num2); Logger.LogTrace(string.Format("{0}(): exStartIndex={1}; exEndIndex={2}; Starting Quickslot Id={3})", "OnInitializeQuickSlotDisplays_AddExtraSlots", num, num2, quickslotStartId)); for (int i = num; i < num2; i++) { __instance.DisplayOrder[i] = (QuickSlotIDs)(quickslotStartId++); } } catch (Exception ex) { Logger.LogException("OnInitializeQuickSlotDisplays_AddExtraSlots() error.", ex); throw; } } } [HarmonyPatch] internal static class LocalCharacterControlPatches { private static Dictionary _playerInputManager = new Dictionary(); private static IEnumerable _exQuickSlots = new List(); [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static void Configure(IEnumerable exQuickSlots) { _exQuickSlots = exQuickSlots; } [HarmonyPatch(typeof(ControlsInput), "Setup")] [HarmonyPostfix] public static void OnControlsInputSetup_SetPlayerInputManager() { _playerInputManager = ((ControlsInput)null).GetPlayerInputManager(); IList actionCategories = ReInput.mapping.ActionCategories; string text = string.Empty; foreach (InputCategory item in actionCategories) { text += $"Category ID: {item.id}, Name: {item.name}, DescriptiveName: {item.descriptiveName}\n"; IEnumerable enumerable = ReInput.mapping.ActionsInCategory(item.id); foreach (InputAction item2 in enumerable) { text += $"\tAction Id: {item2.id}, Name: {item2.name}, DescriptiveName: {item2.descriptiveName}\n"; } } Logger.LogTrace(text); } [HarmonyPatch(typeof(LocalCharacterControl), "UpdateQuickSlots")] [HarmonyPostfix] public static void OnUpdateQuickSlots_CheckForButtonPresses(LocalCharacterControl __instance) { if (_exQuickSlots.Count() < 1) { return; } if ((Object)(object)((CharacterControl)__instance).Character == (Object)null || (Object)(object)((CharacterControl)__instance).Character.QuickSlotMngr == (Object)null) { Logger?.LogTrace("LocalCharacterControl.UpdateQuickSlots - Character or Character.QuickSlotMng was null."); return; } try { int playerID = ((CharacterControl)__instance).Character.OwnerPlayerSys.PlayerID; if (AnyQuickSlotInstantButtonsDown(playerID)) { Logger?.LogTrace("LocalCharacterControl.UpdateQuickSlots - Built in quickslot button was pressed. Exiting."); return; } int firstExQuickSlotInstantDown = GetFirstExQuickSlotInstantDown(playerID); if (firstExQuickSlotInstantDown > 0) { Logger?.LogTrace($"Triggering Ex Quickslot #{firstExQuickSlotInstantDown}"); ((CharacterControl)__instance).Character.QuickSlotMngr.QuickSlotInput(firstExQuickSlotInstantDown - 1); } } catch (Exception ex) { Logger?.LogException("Exception in LocalCharacterControlPatches.OnUpdateQuickSlots_CheckForButtonPresses().", ex); throw; } } public static bool AnyQuickSlotInstantButtonsDown(int _playerID) { return ControlsInput.QuickSlotInstant1(_playerID) || ControlsInput.QuickSlotInstant2(_playerID) || ControlsInput.QuickSlotInstant3(_playerID) || (ControlsInput.QuickSlotInstant4(_playerID) | ControlsInput.QuickSlotInstant5(_playerID)) || ControlsInput.QuickSlotInstant6(_playerID) || ControlsInput.QuickSlotInstant7(_playerID) || ControlsInput.QuickSlotInstant8(_playerID); } public static int GetFirstExQuickSlotInstantDown(int playerID) { foreach (ExtendedQuickSlot exQuickSlot in _exQuickSlots) { if (QuickSlotInstantN(playerID, exQuickSlot.ActionName)) { return exQuickSlot.QuickSlotId; } } return -1; } public static bool QuickSlotInstantN(int playerId, string actionName) { return _playerInputManager[playerId].GetButtonDown(actionName); } } [HarmonyPatch(typeof(LocalizationManager), "Awake")] internal static class QsLocalizationManagerPatches { private static readonly List _customLocalizationListeners = new List(); [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static void Configure(IEnumerable extendedQuickSlots) { Dictionary qsLocalizations = extendedQuickSlots.ToDictionary((ExtendedQuickSlot x) => x.ActionKey, (ExtendedQuickSlot x) => x.ActionDescription); MoreQuickslotsLocalizationListener item = new MoreQuickslotsLocalizationListener(qsLocalizations, Logger); _customLocalizationListeners.Add((ILocalizeListener)(object)item); } [HarmonyPostfix] public static void AddCustomLocalizations(LocalizationManager __instance) { foreach (ILocalizeListener customLocalizationListener in _customLocalizationListeners) { __instance.RegisterLocalizeElement(customLocalizationListener); } } } } namespace ModifAmorphic.Outward.Modules.QuickSlots.KeyBindings.Services { internal class QsMenuExtender { private readonly Func _loggerFactory; private const string ActionNamePrefix = "QS_Instant"; private const string ActionKeyPrefix = "InputAction_"; private const string MenuSlotNoKey = "{ExtraSlotNumber}"; private const string MenuDescriptionDefaultFormat = "Ex Quick Slot {ExtraSlotNumber}"; private IModifLogger Logger => _loggerFactory(); public QsMenuExtender(Func loggerFactory) { _loggerFactory = loggerFactory; } public List ExtendQuickSlots(Queue menuDescriptions) { try { int count = menuDescriptions.Count; int num = 0; List list = new List(); int num2 = Enum.GetValues(typeof(QuickSlotIDs)).Cast().Max() + 1; while (menuDescriptions.Count > 0) { int num3 = num + num2; int num4 = num + 1; string text = "QS_Instant" + num3; string text2 = menuDescriptions.Dequeue(); if (string.IsNullOrEmpty(text2?.Trim())) { Logger.LogWarning(string.Format("{0}(): Empty menu description found in queue {1}. Defaulting menu message text for extra slot {2}.", "ExtendQuickSlots", "menuDescriptions", num4)); text2 = "Ex Quick Slot {ExtraSlotNumber}".Replace("{ExtraSlotNumber}", num4.ToString()); } list.Add(new ExtendedQuickSlot { QuickSlotId = num3, ActionName = text, ActionKey = "InputAction_" + text, ActionDescription = text2 }); CustomKeybindings.AddAction(text, (KeybindingsCategory)2, (ControlType)2, (InputType)1); Logger.LogDebug($"Adding quickslot - id: {num3}; actionName: '{text}'; description: {text2}"); num++; } Logger.LogTrace($"RaiseSlotsChanged Event. StartId = {num2}, QuickSlotsToAdd = {list.Count}"); return list; } catch (Exception ex) { Logger.LogException("Exception in QuickSlotExtender.ExtendQuickSlots(Queue menuDescriptions). Extend failed.", ex); throw; } } public List ExtendQuickSlots(int extendAmount, string menuDescriptionFormat) { Queue queue = new Queue(); Logger.LogDebug($"Extending quickslots by {extendAmount}."); try { string text = menuDescriptionFormat; if (extendAmount < 1) { throw new ArgumentOutOfRangeException("extendAmount", string.Format("Value of {0} must be greater than 0. Value was {1}.", "extendAmount", extendAmount)); } if (string.IsNullOrEmpty(menuDescriptionFormat?.Trim()) || !menuDescriptionFormat.Contains("{ExtraSlotNumber}")) { Logger.LogWarning("ExtendQuickSlots(): '{ExtraSlotNumber}' replacer not found in menuDescriptionFormat parameter. Using default menu formatting."); text = "Ex Quick Slot {ExtraSlotNumber}"; } for (int i = 0; i < extendAmount; i++) { queue.Enqueue(text.Replace("{ExtraSlotNumber}", (i + 1).ToString())); } } catch (Exception ex) { Logger.LogException("Exception in QuickSlotExtender.ExtendQuickSlots(int extendAmount, string menuDescriptionFormat). Extend failed.", ex); throw; } return ExtendQuickSlots(queue); } } } namespace ModifAmorphic.Outward.Modules.Merchants { public class MerchantModule : IModifModule { private readonly Func _loggerFactory; private readonly ConcurrentDictionary> _customDropTables = new ConcurrentDictionary>(); private IModifLogger Logger => _loggerFactory(); public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(MerchantPatches)); return hashSet; } } public HashSet EventSubscriptions { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(MerchantPatches)); return hashSet; } } public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(MerchantPatches)); return hashSet; } } [MethodImpl(MethodImplOptions.NoInlining)] internal MerchantModule(Func loggerFactory) { _loggerFactory = loggerFactory; MerchantPatches.InitDropTableGameObjectAfter += AppendCustomDrops; } private void AppendCustomDrops((Merchant Merchant, Transform MerchantInventoryTablePrefab, Dropable DropableInventory) args) { Logger.LogDebug("MerchantModule::AppendCustomDrops: Looking for custom drop tables for shop '" + args.Merchant.ShopName + "'\n\tScene: " + AreaManager.Instance.CurrentArea.SceneName + "\n\tPath: " + ((Component)args.Merchant).gameObject.GetPath()); if (!_customDropTables.TryGetValue(AreaManager.Instance.CurrentArea.SceneName, out var value) || !value.TryGetValue(((Component)args.Merchant).gameObject.GetPath(), out var value2)) { return; } foreach (GuaranteedDropTable guaranteedDrop in value2.GuaranteedDrops) { GuaranteedDrop val = ((Component)args.DropableInventory).gameObject.AddComponent(); ((ItemDropper)val).ItemGenatorName = guaranteedDrop.ItemGenatorName; val.SetItemDrops(guaranteedDrop.CustomGuaranteedDrops.ToItemDrops()); Logger.LogDebug("MerchantModule::AppendCustomDrops:" + $" Added {guaranteedDrop.CustomGuaranteedDrops.Count} guaranteed custom drops to merchant shop '{args.Merchant.ShopName}'."); } } public void AddGuaranteedDrops(string sceneName, string merchantPath, IEnumerable guaranteedDrops, string itemGenName, string gameObjectName = "InventoryTable") { ConcurrentDictionary orAdd = _customDropTables.GetOrAdd(sceneName, new ConcurrentDictionary()); CustomDropTables orAdd2 = orAdd.GetOrAdd(merchantPath, new CustomDropTables()); orAdd2.GuaranteedDrops.Add(new GuaranteedDropTable { CustomGuaranteedDrops = guaranteedDrops.ToList(), ItemGenatorName = itemGenName, GameObjectName = gameObjectName }); } } [HarmonyPatch(typeof(Merchant))] internal static class MerchantPatches { [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static event Action<(Merchant Merchant, Transform MerchantInventoryTablePrefab, Dropable DropableInventory)> InitDropTableGameObjectAfter; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void InitDropTableGameObjectPostfix(Merchant __instance, ref Transform ___m_merchantInventoryTablePrefab, ref Dropable ___m_dropableInventory) { try { Logger.LogTrace("MerchantPatches::InitDropTableGameObjectPostfix: Raising event InitDropTableGameObjectAfter."); MerchantPatches.InitDropTableGameObjectAfter?.Invoke((__instance, ___m_merchantInventoryTablePrefab, ___m_dropableInventory)); } catch (Exception ex) { Logger.LogException("MerchantPatches::InitDropTableGameObjectPostfix: Excepting triggering event InitDropTableGameObjectAfter.", ex); } } } } namespace ModifAmorphic.Outward.Modules.Localization { public class LocalizationModule : IModifModule { private readonly string _modId; private readonly Func _loggerFactory; private IModifLogger Logger => _loggerFactory(); public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); return hashSet; } } public HashSet EventSubscriptions { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); return hashSet; } } public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); hashSet.Add(typeof(LocalizationService)); return hashSet; } } [MethodImpl(MethodImplOptions.NoInlining)] internal LocalizationModule(Func loggerFactory) { _loggerFactory = loggerFactory; } public void RegisterLocalization(string key, string localization) { LocalizationService.RegisterLocalization(key, localization); } public static void RegisterLocalizations(IDictionary localizations) { LocalizationService.RegisterLocalizations(localizations); } } } namespace ModifAmorphic.Outward.Modules.Items { internal class IconService { private readonly string _modId; private readonly Func _loggerFactory; private readonly ModifGoService _modifGoService; private readonly GameObject _iconsGo; private IModifLogger Logger => _loggerFactory(); private Transform Icons => _iconsGo.transform; internal IconService(string modId, ModifGoService modifGoService, Func loggerFactory) { _modId = modId; _loggerFactory = loggerFactory; _modifGoService = modifGoService; _iconsGo = ((Component)UnityEngineExtensions.GetOrAddComponent(modifGoService.GetModResources(modId, activable: false))).gameObject; } public GameObject GetOrAddIcon(ItemDisplay itemDisplay, string iconName, string iconFilePath, bool activate = false) { string iconGameObjectName = GetIconGameObjectName(iconName); Transform obj = ((Component)itemDisplay).transform.Find(iconGameObjectName); GameObject val = ((obj != null) ? ((Component)obj).gameObject : null); if (Object.op_Implicit((Object)(object)val)) { if (activate && !val.activeSelf) { val.SetActive(true); } return val; } GameObject orAddBaseIcon = GetOrAddBaseIcon(itemDisplay, iconName, iconFilePath); GameObject val2 = Object.Instantiate(orAddBaseIcon, ((Component)itemDisplay).transform); Image component = orAddBaseIcon.GetComponent(); Image component2 = val2.GetComponent(); Logger.LogDebug(string.Format("{0}::{1}(): Setting new image's sprite to existing {2} sprite reference from base icon.", "IconService", "GetOrAddIcon", component.sprite)); component2.sprite = component.sprite; ((Object)component2).name = ((Object)component).name; val2.DeCloneNames(recursive: true); if (!val2.gameObject.activeSelf && activate) { val2.gameObject.SetActive(true); } return val2; } public bool TryDeactivateIcon(ItemDisplay itemDisplay, string iconName) { string iconGameObjectName = GetIconGameObjectName(iconName); Transform obj = ((Component)itemDisplay).transform.Find(iconGameObjectName); GameObject val = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val == (Object)null || !val.activeSelf) { Logger.LogTrace("IconService::TryDeactivateIcon(): No existing icon GameObject '" + iconGameObjectName + "' found attached, or existing icon's GameObject " + (((val != null) ? ((Object)val).name : null) ?? " ") + "was already deactivated. No action taken."); return false; } val.SetActive(false); Logger.LogDebug("IconService::TryDeactivateIcon(): Deactivated existing icon's GameObject " + ((Object)val).name + "."); return true; } private string GetIconGameObjectName(string iconName) { string text = ((iconName.Length == 1) ? iconName.ToUpper() : (iconName.Substring(0, 1).ToUpper() + iconName.Substring(1))); if (text.StartsWith("Img")) { text = ((iconName.Length == 3) ? "" : ((text.Length > 3) ? (text.Substring(3, 1).ToUpper() + text.Substring(4)) : text.Substring(3, 1).ToUpper())); } Logger.LogTrace("IconService::GetIconGameObjectName(): img" + text + "."); return "img" + text; } private GameObject GetOrAddBaseIcon(ItemDisplay itemDisplay, string baseIconName, string iconPath) { string iconGameObjectName = GetIconGameObjectName(baseIconName); string spriteName = "icon_" + baseIconName + "Item"; string textureName = "tex_men_" + baseIconName + "Item_v_icn"; Transform obj = Icons.Find(iconGameObjectName); GameObject val = ((obj != null) ? ((Component)obj).gameObject : null); Logger.LogDebug(string.Format("{0}::{1}(): Tried to get base game object for icon {2}. Got {3}.", "IconService", "GetOrAddBaseIcon", iconGameObjectName, val)); if (Object.op_Implicit((Object)(object)val)) { return val; } if (!File.Exists(iconPath)) { throw new FileNotFoundException("Sprite for icon " + baseIconName + " could not be loaded.", iconPath); } GameObject gameObject = ((Component)((Component)itemDisplay).transform.Find("imgEnchanted")).gameObject; Logger.LogDebug(string.Format("{0}::{1}(): Cloned enchanting icon gameobject {2}.", "IconService", "GetOrAddBaseIcon", gameObject)); val = Object.Instantiate(gameObject, Icons); Image component = val.GetComponent(); Logger.LogDebug("IconService::GetOrAddBaseIcon(): Destroying existing image " + ((Object)component).name + "."); Object.DestroyImmediate((Object)(object)component); ((Object)val).name = iconGameObjectName; Image val2 = val.AddComponent(); ((Object)val2).name = iconGameObjectName; val2.LoadSpriteIcon(iconPath, spriteName, textureName); return val; } } internal class ItemPrefabService { private readonly string _modId; private readonly Func _loggerFactory; private readonly ModifGoService _modifGoService; private readonly ModifItemPrefabs _modifItemPrefabs; private readonly Func _prefabManagerFactory; private readonly Dictionary _itemLocalizations = new Dictionary(); private Dictionary _itemPrefabs; private IModifLogger Logger => _loggerFactory(); public ModifItemPrefabs ModifItemPrefabs => _modifItemPrefabs; private ResourcesPrefabManager PrefabManager => _prefabManagerFactory(); internal ItemPrefabService(string modId, ModifGoService modifGoService, Func prefabManagerFactory, Func loggerFactory) { _modId = modId; _loggerFactory = loggerFactory; _modifGoService = modifGoService; _modifItemPrefabs = modifGoService.GetModItemPrefabs(modId); _prefabManagerFactory = prefabManagerFactory; LocalizationManagerPatches.LoadItemLocalizationAfter += RegisterItemLocalizations; ItemPatches.GetItemIconBefore += SetCustomItemIcon; ResourcesPrefabManagerPatches.TryGetItemPrefabActions.Add(delegate(int itemID, out Item item) { if (_modifItemPrefabs.Prefabs.ContainsKey(itemID)) { item = _modifItemPrefabs.Prefabs[itemID]; return true; } item = null; return false; }); } private void SetCustomItemIcon(Item item) { if (item.TryGetCustomIcon(out var icon)) { item.SetItemIcon(icon); } } public T CreatePrefab(int baseItemID, int newItemID, string name, string description, bool addToResoucesPrefabManager, bool setFields) where T : Item { T basePrefab = (T)(object)PrefabManager.GetItemPrefab(baseItemID); return CreatePrefab(basePrefab, newItemID, name, description, addToResoucesPrefabManager, setFields); } public T CreatePrefab(T basePrefab, int newItemID, string name, string description, bool addToResoucesPrefabManager, bool setFields) where T : Item { //IL_01f5: 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_0236: Expected O, but got Unknown //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Expected O, but got Unknown if (string.IsNullOrEmpty(description)) { description = ((Item)basePrefab).Description; } bool activeSelf = ((Component)(object)basePrefab).gameObject.activeSelf; ((Component)(object)basePrefab).gameObject.SetActive(false); T val = (T)(object)((Component)(object)Object.Instantiate(basePrefab, ((Component)_modifItemPrefabs).transform, false)).GetComponent(); UnityEngineExtensions.ResetLocal(((Component)(object)val).transform, true); ((Component)(object)basePrefab).gameObject.SetActive(activeSelf); if (setFields) { basePrefab.CopyFieldsTo(val); ((Item)(object)val).SetPrivateField("m_loadedVisual", null); if ((Object)(object)((Item)basePrefab).Stats != (Object)null) { ItemStats value = Object.Instantiate(((Item)basePrefab).Stats, ((Component)(object)val).transform); ((Item)(object)val).SetPrivateField("m_stats", value); } if (((Item)basePrefab).DisplayedInfos != null) { DisplayedInfos[] array = (DisplayedInfos[])(object)new DisplayedInfos[((Item)basePrefab).DisplayedInfos.Length]; Array.Copy(((Item)basePrefab).DisplayedInfos, array, array.Length); ((Item)(object)val).SetPrivateField("m_displayedInfos", array); ((Item)(object)val).SetPrivateField("m_displayedInfoInitialzed", value: false); } object obj = basePrefab; Equipment val2 = (Equipment)((obj is Equipment) ? obj : null); if (val2 != null) { object obj2 = val; Equipment val3 = (Equipment)((obj2 is Equipment) ? obj2 : null); if (val3 != null) { ProcessEquipmentFields(val2, val3); } } object obj3 = val; Weapon val4 = (Weapon)((obj3 is Weapon) ? obj3 : null); if (val4 != null) { ProcessWeaponFields(val4); } object obj4 = basePrefab; Armor val5 = (Armor)((obj4 is Armor) ? obj4 : null); if (val5 != null) { object obj5 = val; Armor val6 = (Armor)((obj5 is Armor) ? obj5 : null); if (val6 != null) { ProcessArmorFields(val5, val6); } } } ((Item)val).SetDLC(((Item)basePrefab).DLCID); ((Item)val).ItemID = newItemID; ((Item)val).IsPrefab = true; ((Item)(object)val).SetNames(name).SetDescription(description); ItemLocalization value2 = new ItemLocalization(name, description); _itemLocalizations.AddOrUpdate(((Item)val).ItemID, new ItemLocalization(name, description)); Dictionary privateField = LocalizationManager.Instance.GetPrivateField>("m_itemLocalization"); privateField.AddOrUpdate(((Item)val).ItemID, value2); if (addToResoucesPrefabManager) { GetItemPrefabs().AddOrUpdate(((Item)val).ItemIDString, (Item)(object)val); } else { _modifItemPrefabs.Add((Item)(object)val); } return val; } private void ProcessWeaponFields(Weapon weapon) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown weapon.SetPrivateField("m_enchantmentDamageBonus", new DamageList()); weapon.SetPrivateField("m_baseDamage", null); weapon.SetPrivateField("m_activeBaseDamage", null); weapon.SetPrivateField>("m_alreadyHitChars", new List()); weapon.SetPrivateField("m_lastDealtDamages", new DamageList()); weapon.SetPrivateField>("m_imbueStack", new DictionaryExt()); weapon.SetPrivateField>("tmpattackTags", new List()); weapon.SetPrivateField("baseDamage", null); } private void ProcessArmorFields(Armor sourceArmor, Armor targetArmor) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_0065: Expected O, but got Unknown ArmorBaseData privateField = sourceArmor.GetPrivateField("m_baseData"); if (privateField != null) { ArmorBaseData value = new ArmorBaseData { Class = privateField.Class, ColdProtection = privateField.ColdProtection, DamageReduction = privateField.DamageReduction?.ToList(), DamageResistance = privateField.DamageResistance?.ToList() }; targetArmor.SetPrivateField("m_baseData", value); } } private void ProcessEquipmentFields(Equipment source, Equipment target) { target.AssociatedEquipment = null; target.SetPrivateField>("m_activeEnchantments", source.GetPrivateField>("m_activeEnchantments")?.ToList()); target.SetPrivateField>("m_appliedAffectStats", source.GetPrivateField>("m_appliedAffectStats")?.ToList()); target.SetPrivateField>("m_enchantmentIDs", source.GetPrivateField>("m_enchantmentIDs")?.ToList()); target.SetPrivateField("m_summonedEquipment", null); } public Dictionary GetItemPrefabs() { if (_itemPrefabs == null) { FieldInfo field = typeof(ResourcesPrefabManager).GetField("ITEM_PREFABS", BindingFlags.Static | BindingFlags.NonPublic); _itemPrefabs = field.GetValue(null) as Dictionary; } return _itemPrefabs; } private void RegisterItemLocalizations(ref Dictionary targetLocalizations) { foreach (KeyValuePair itemLocalization in _itemLocalizations) { targetLocalizations.AddOrUpdate(itemLocalization.Key, itemLocalization.Value); } } } public class ItemVisualizer : IModifModule { private readonly Func _loggerFactory; private readonly Func _prefabManagerFactory; private readonly Func _itemManagerFactory; private readonly IconService _iconService; private readonly ConcurrentDictionary _itemVisuals = new ConcurrentDictionary(); private readonly ConcurrentDictionary> _itemsIcons = new ConcurrentDictionary>(); private readonly HashSet _displayIcons = new HashSet(); private IModifLogger Logger => _loggerFactory(); private ResourcesPrefabManager PrefabManager => _prefabManagerFactory(); private ItemManager ItemManager => _itemManagerFactory(); public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(ItemManagerPatches)); hashSet.Add(typeof(ItemDisplayPatches)); return hashSet; } } public HashSet EventSubscriptions => new HashSet(); public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(ItemManagerPatches)); hashSet.Add(typeof(ItemDisplayPatches)); return hashSet; } } [MethodImpl(MethodImplOptions.NoInlining)] internal ItemVisualizer(Func prefabManagerFactory, Func itemManagerFactory, IconService iconService, Func loggerFactory) { _loggerFactory = loggerFactory; _prefabManagerFactory = prefabManagerFactory; _itemManagerFactory = itemManagerFactory; _iconService = iconService; ItemManagerPatches.GetVisualsByItemAfter += SetVisualsByItem; ItemManagerPatches.GetSpecialVisualsByItemAfter += SetSpecialVisualsByItem; ItemDisplayPatches.RefreshEnchantedIconAfter += ToggleCustomIcons; } public void RegisterItemVisual(int visualItemID, string targetItemUID) { Logger.LogDebug(string.Format("{0}::{1}(): Registering target UID '{2}' to use ItemID {3} visuals.", "ItemVisualizer", "RegisterItemVisual", targetItemUID, visualItemID)); _itemVisuals.TryAdd(targetItemUID, visualItemID); } public void UnregisterItemVisual(string targetItemUID) { Logger.LogDebug("ItemVisualizer::RegisterItemVisual(): Unregistering target UID '" + targetItemUID + "'."); _itemVisuals.TryRemove(targetItemUID, out var _); } public bool IsItemVisualRegistered(string itemUID) { return _itemVisuals.ContainsKey(itemUID); } public void RegisterAdditionalIcon(string itemUID, string iconName, string iconPath) { Logger.LogDebug("ItemVisualizer::RegisterItemVisual(): Registering new Icon " + iconName + " to Item UID '" + itemUID + "'. Icon file path: " + iconPath + "."); ConcurrentDictionary orAdd = _itemsIcons.GetOrAdd(itemUID, new ConcurrentDictionary()); orAdd.TryAdd(iconName, iconPath); if (!_displayIcons.Contains(iconName)) { _displayIcons.Add(iconName); } } public void UnregisterAdditionalIcon(string itemUID, string iconName) { Logger.LogDebug("ItemVisualizer::RegisterItemVisual(): Unregistering Icon " + iconName + " from Item UID '" + itemUID + "'."); if (_itemsIcons.TryGetValue(itemUID, out var value)) { value.TryRemove(iconName, out var _); if (value.Count == 0) { _itemsIcons.TryRemove(itemUID, out var _); } } } public bool IsAdditionalIconRegistered(string itemUID, string iconName) { ConcurrentDictionary value; return _itemsIcons.TryGetValue(itemUID, out value) && value.ContainsKey(iconName); } private void SetVisualsByItem(Item item, ref ItemVisual visual) { if (TryGetVisualsByItem(item, out var visual2)) { visual = visual2; } } private bool TryGetVisualsByItem(Item item, out ItemVisual visual) { visual = null; if (!_itemVisuals.TryGetValue(item.UID, out var value)) { Logger.LogTrace(string.Format("{0}::{1}(): No custom ItemVisual mapping found for {2} - {3} ({4}).", "ItemVisualizer", "TryGetVisualsByItem", item.ItemID, item.DisplayName, item.UID)); return false; } item.SetPrivateField("m_loadedVisual", null); visual = ItemManager.GetVisuals(value); IModifLogger logger = Logger; string text = string.Format("{0}::{1}(): ItemVisual mapping found for {2} - {3} ({4}). Replaced ", "ItemVisualizer", "TryGetVisualsByItem", item.ItemID, item.DisplayName, item.UID); object arg = value; ItemVisual obj = visual; logger.LogDebug(text + $"visuals with ItemID {arg}'s ItemVisual - {((obj != null) ? ((Object)obj).name : null)}"); Item itemPrefab = PrefabManager.GetItemPrefab(value); ToggleModelOnEnchant component = ((Component)itemPrefab).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((Component)item).GetComponent() == (Object)null) { ToggleModelOnEnchant val = ((Component)item).gameObject.AddComponent(); val.ModelName = component.ModelName; ((Object)val).name = ((Object)item).name; ((Component)val).gameObject.SetActive(true); } ConfigureVisualToggles(item, value); return (Object)(object)visual != (Object)null; } private void SetSpecialVisualsByItem(Item item, ref ItemVisual visual) { if (TryGetSpecialVisualsByItem(item, out var visual2)) { visual = visual2; } } private bool TryGetSpecialVisualsByItem(Item item, out ItemVisual visual) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) visual = null; if (!_itemVisuals.TryGetValue(item.UID, out var value)) { Logger.LogTrace(string.Format("{0}::{1}(): No custom ItemVisual mapping found for {2} - {3} ({4}).", "ItemVisualizer", "SetSpecialVisualsByItem", item.ItemID, item.DisplayName, item.UID)); return false; } item.SetPrivateField("m_loadedVisual", null); Item itemPrefab = PrefabManager.GetItemPrefab(value); if (itemPrefab.HasSpecialVisualPrefab) { Item val = PrefabManager.GenerateItem(value.ToString()); val.SetHolderUID(UID.op_Implicit(Global.GenerateUID())); if ((Object)(object)((EffectSynchronizer)item).OwnerCharacter != (Object)null) { val.SetPrivateField("m_ownerCharacter", ((EffectSynchronizer)item).OwnerCharacter); } Logger.LogDebug(string.Format("{0}::{1}(): HasSpecialVisualPrefab --> Generated temporary Item and set it's owner to {2} to retrieve ItemVisual. ", "ItemVisualizer", "SetSpecialVisualsByItem", ((EffectSynchronizer)val).OwnerCharacter) + $" Generated Item: {val.ItemID} - {val.DisplayName} ({val.UID})"); visual = ItemManager.GetSpecialVisuals(val); Object.Destroy((Object)(object)((Component)val).gameObject); IModifLogger logger = Logger; string text = string.Format("{0}::{1}(): HasSpecialVisualPrefab --> ItemVisual mapping found for {2} - {3} ({4}). Replaced ", "ItemVisualizer", "SetSpecialVisualsByItem", item.ItemID, item.DisplayName, item.UID); object arg = value; ItemVisual obj = visual; logger.LogDebug(text + $"visuals with ItemID {arg}'s ItemVisual - {((obj != null) ? ((Object)obj).name : null)}"); } else { visual = ItemManager.GetVisuals(value); IModifLogger logger2 = Logger; string text2 = string.Format("{0}::{1}(): ItemVisual mapping found for {2} - {3} ({4}). Replaced ", "ItemVisualizer", "SetSpecialVisualsByItem", item.ItemID, item.DisplayName, item.UID); object arg2 = value; ItemVisual obj2 = visual; logger2.LogDebug(text2 + $"visuals with ItemID {arg2}'s ItemVisual - {((obj2 != null) ? ((Object)obj2).name : null)}"); } if ((Object)(object)visual != (Object)null) { visual.SetLinkedItem(item); } ConfigureVisualToggles(item, value); return (Object)(object)visual != (Object)null; } private void ConfigureVisualToggles(Item item, int visualItemID) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) Item itemPrefab = PrefabManager.GetItemPrefab(visualItemID); ToggleModelOnEnchant component = ((Component)itemPrefab).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)((Component)item).GetComponent() == (Object)null) { ToggleModelOnEnchant val = ((Component)item).gameObject.AddComponent(); val.ModelName = component.ModelName; ((Object)val).name = ((Object)item).name; ((Component)val).gameObject.SetActive(true); } SwapColor component2 = ((Component)itemPrefab).GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)((Component)item).GetComponent() == (Object)null) { SwapColor val2 = ((Component)item).gameObject.AddComponent(); val2.DefaultColor = component2.DefaultColor; val2.Palette = component2.Palette; ((Object)val2).name = ((Object)item).name; ((Component)val2).gameObject.SetActive(true); } } private void ToggleCustomIcons(ItemDisplay itemDisplay, Item item) { HashSet hashSet = new HashSet(); Logger.LogTrace(string.Format("{0}::{1}(): Setting custom icons for Item {2} - {3} ({4}) current ItemDisplay {5}.", "ItemVisualizer", "ToggleCustomIcons", item?.ItemID, (item != null) ? item.DisplayName : null, (item != null) ? item.UID : null, ((Object)itemDisplay).name)); if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(item.UID) && _itemsIcons.TryGetValue(item.UID, out var value)) { foreach (KeyValuePair item2 in value) { _iconService.GetOrAddIcon(itemDisplay, item2.Key, item2.Value, activate: true); hashSet.Add(item2.Key); Logger.LogDebug("ItemVisualizer::ToggleCustomIcons(): Added icon " + item2.Key + " to ItemDisplay " + ((Object)itemDisplay).name + "."); } } foreach (string displayIcon in _displayIcons) { if (!hashSet.Contains(displayIcon) && _iconService.TryDeactivateIcon(itemDisplay, displayIcon)) { Logger.LogTrace("ItemVisualizer::ToggleCustomIcons(): Deactivated icon " + displayIcon + " for ItemDisplay " + ((Object)itemDisplay).name + "."); } } } private bool TryUnregisterItemVisual(Item containedItem, out (string UID, int VisualItemID) visualMap) { if (_itemVisuals.TryRemove(containedItem.UID, out var value)) { visualMap = (containedItem.UID, value); containedItem.SetPrivateField("m_loadedVisual", null); Logger.LogDebug(string.Format("{0}::{1}(): Unregistered target UID '{2}' from ItemID {3} visuals.\n", "ItemVisualizer", "RegisterItemVisual", containedItem.UID, value) + $"\tm_loadedVisual: {containedItem.GetLoadedVisual()}"); Logger.LogDebug("ItemVisualizer::RegisterItemVisual(): Visuals: \n" + $"\tLoadedVisual: {containedItem.LoadedVisual}" + $"\tCurrentVisual: {containedItem.CurrentVisual}"); return true; } visualMap = default((string, int)); return false; } private bool PositionVisualsOverride(VisualSlot visualSlot, ref Item item) { if (string.IsNullOrEmpty(item.UID) || (!_itemVisuals.TryGetValue(item.UID, out var value) && !item.DisplayName.Contains("Virgin"))) { return false; } Logger.LogDebug(string.Format("{0}::{1}(): Starting PositionVisuals processing for {2} - {3} ({4}) and ", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID) + $"visualItemID {value}."); VisualSlotWrapper visualSlotWrapper = VisualSlotWrapper.Wrap(visualSlot); if (!Application.isPlaying) { visualSlotWrapper.m_currentItem = item; Logger.LogDebug(string.Format("{0}::{1}(): Application.isPlaying == false. m_currentItem set to item {2} - {3} ({4}).", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID)); } else { Logger.LogDebug(string.Format("{0}::{1}(): Application.isPlaying == true for item: {2} - {3} ({4}).", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID)); if ((Object)(object)visualSlotWrapper.m_editorCurrentVisuals != (Object)null) { visualSlotWrapper.m_currentVisual = visualSlotWrapper.m_editorCurrentVisuals; Logger.LogDebug(string.Format("{0}::{1}(): m_editorCurrentVisuals != null. Set m_currentVisual to m_editorCurrentVisuals {2} for item: {3} - {4} ({5}).", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_editorCurrentVisuals, item.ItemID, item.DisplayName, item.UID)); } if ((Object)(object)item == (Object)(object)visualSlotWrapper.m_currentItem) { if (!item.HasSpecialVisualPrefab) { Logger.LogDebug(string.Format("{0}::{1}(): !item.HasSpecialVisualPrefab. Calling item.LinkVisuals({2}, false). item: {3} - {4} ({5}).", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentVisual, item.ItemID, item.DisplayName, item.UID)); item.LinkVisuals(visualSlotWrapper.m_currentVisual, false); } Logger.LogDebug(string.Format("{0}::{1}(): item == m_currentItem. Calling PositionVisuals() for item: {2} - {3} ({4}).", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID)); visualSlotWrapper.PositionVisuals(); return true; } if ((Object)(object)visualSlotWrapper.m_currentItem != (Object)null) { Logger.LogDebug(string.Format("{0}::{1}(): vs.m_currentItem != null. m_currentItem is [{2} - {3} ({4})]. Calling PutBackVisuals(). item: {5} - {6} ({7}).", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentItem.ItemID, visualSlotWrapper.m_currentItem.DisplayName, visualSlotWrapper.m_currentItem.UID, item.ItemID, item.DisplayName, item.UID)); visualSlot.PutBackVisuals(); } IModifLogger logger = Logger; object[] obj = new object[8] { "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentItem?.ItemID, null, null, null, null, null }; Item currentItem = visualSlotWrapper.m_currentItem; obj[3] = ((currentItem != null) ? currentItem.DisplayName : null); Item currentItem2 = visualSlotWrapper.m_currentItem; obj[4] = ((currentItem2 != null) ? currentItem2.UID : null); obj[5] = item.ItemID; obj[6] = item.DisplayName; obj[7] = item.UID; logger.LogDebug(string.Format("{0}::{1}(): m_currentItem [{2} - {3} ({4})] being set to param item [{5} - {6} ({7})].", obj)); visualSlotWrapper.m_currentItem = item; } if ((Object)(object)visualSlotWrapper.m_currentVisual == (Object)null) { Logger.LogDebug(string.Format("{0}::{1}(): m_currentVisual == null. item: [{2} - {3} ({4})].", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID)); if (!item.HasSpecialVisualPrefab) { Logger.LogDebug(string.Format("{0}::{1}(): !item.HasSpecialVisualPrefab (No Special). m_currentVisual [{2}] set to item.LoadedVisual [{3}]. ", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentVisual, item.LoadedVisual) + $"m_editorCurrentVisuals [{visualSlotWrapper.m_editorCurrentVisuals}] set to m_currentVisual [{visualSlotWrapper.m_currentVisual}]. " + $"item: [{item.ItemID} - {item.DisplayName} ({item.UID})]."); visualSlotWrapper.m_currentVisual = item.LoadedVisual; visualSlotWrapper.m_editorCurrentVisuals = visualSlotWrapper.m_currentVisual; } else { Logger.LogDebug(string.Format("{0}::{1}(): item.HasSpecialVisualPrefab == true. m_currentVisual [{2}]. m_editorCurrentVisuals [{3}]. ", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentVisual, visualSlotWrapper.m_editorCurrentVisuals) + $"item: [{item.ItemID} - {item.DisplayName} ({item.UID})]."); visualSlotWrapper.m_currentVisual = ItemManager.GetSpecialVisuals(item); visualSlotWrapper.m_editorCurrentVisuals = visualSlotWrapper.m_currentVisual; Logger.LogDebug(string.Format("{0}::{1}(): ItemManager.GetSpecialVisuals({2} - {3} ({4})). m_currentVisual now [{5}] and m_editorCurrentVisuals [{6}].", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID, visualSlotWrapper.m_currentVisual, visualSlotWrapper.m_currentVisual)); if (Object.op_Implicit((Object)(object)visualSlotWrapper.m_currentVisual)) { Logger.LogDebug(string.Format("{0}::{1}(): m_currentVisual.Show(). m_currentVisual [{2}]. item: [{3} - {4} ({5})].", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_currentVisual, item.ItemID, item.DisplayName, item.UID)); visualSlotWrapper.m_currentVisual.Show(); } if (item is Equipment) { Logger.LogDebug(string.Format("{0}::{1}(): item is Equipment. IsEnchanted == {2}. Calling (item as Equipment).SetSpecialVisuals({3}) item: [{4} - {5} ({6})].", "ItemVisualizer", "PositionVisualsOverride", item.IsEnchanted, visualSlotWrapper.m_currentVisual, item.ItemID, item.DisplayName, item.UID)); Item obj2 = item; ((Equipment)((obj2 is Equipment) ? obj2 : null)).SetSpecialVisuals(visualSlotWrapper.m_currentVisual); } } } if (Application.isPlaying) { Logger.LogDebug(string.Format("{0}::{1}(): Application.isPlaying == true. Setting m_editorCurrentVisuals [{2}] to m_currentVisual [{3}].item: [{4} - {5} ({6})].", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_editorCurrentVisuals, visualSlotWrapper.m_currentVisual, item.ItemID, item.DisplayName, item.UID)); visualSlotWrapper.m_editorCurrentVisuals = visualSlotWrapper.m_currentVisual; } else if ((Object)(object)visualSlotWrapper.m_currentItem != (Object)null) { Logger.LogDebug(string.Format("{0}::{1}(): m_currentItem != null. Setting m_editorCurrentVisuals [{2}] to m_currentVisual [{3}]. item: [{4} - {5} ({6})].", "ItemVisualizer", "PositionVisualsOverride", visualSlotWrapper.m_editorCurrentVisuals, visualSlotWrapper.m_currentVisual, item.ItemID, item.DisplayName, item.UID)); visualSlotWrapper.m_editorCurrentVisuals = visualSlotWrapper.m_currentVisual; } Logger.LogDebug(string.Format("{0}::{1}(): Calling PositionVisuals() then returning true. item: [{2} - {3} ({4})].", "ItemVisualizer", "PositionVisualsOverride", item.ItemID, item.DisplayName, item.UID)); visualSlotWrapper.PositionVisuals(); return true; } } public class PreFabricator : IModifModule { private readonly string _modId; private readonly Func _loggerFactory; private readonly ItemPrefabService _itemPrefabService; private IModifLogger Logger => _loggerFactory(); public ModifItemPrefabs ModifItemPrefabs => _itemPrefabService.ModifItemPrefabs; public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); hashSet.Add(typeof(ItemPatches)); hashSet.Add(typeof(ResourcesPrefabManagerPatches)); return hashSet; } } public HashSet EventSubscriptions { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); hashSet.Add(typeof(ItemPatches)); hashSet.Add(typeof(ResourcesPrefabManagerPatches)); return hashSet; } } public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(LocalizationManagerPatches)); hashSet.Add(typeof(ItemPatches)); hashSet.Add(typeof(ResourcesPrefabManagerPatches)); return hashSet; } } internal PreFabricator(string modId, ItemPrefabService itemPrefabService, Func loggerFactory) { _modId = modId; _loggerFactory = loggerFactory; _itemPrefabService = itemPrefabService; } public T CreatePrefab(int baseItemID, int newItemID, string name, string description, bool addToResourcesPrefabManager, bool setFields = false) where T : Item { return _itemPrefabService.CreatePrefab(baseItemID, newItemID, name, description, addToResourcesPrefabManager, setFields); } public T CreatePrefab(T basePrefab, int newItemID, string name, string description, bool addToResourcesPrefabManager, bool setFields = false) where T : Item { return _itemPrefabService.CreatePrefab(basePrefab, newItemID, name, description, addToResourcesPrefabManager, setFields); } public T GetPrefab(int itemID) where T : Item { if (ModifItemPrefabs.Prefabs.TryGetValue(itemID, out var value)) { T val = (T)(object)((value is T) ? value : null); if (val != null) { return val; } } return default(T); } public bool TryGetPrefab(int itemID, out T prefab) where T : Item { prefab = GetPrefab(itemID); return (Object)(object)prefab != (Object)null; } public void RemovePrefab(int itemID) { ModifItemPrefabs.Remove(itemID); } } } namespace ModifAmorphic.Outward.Modules.Items.Patches { [HarmonyPatch(typeof(ItemDisplay))] internal static class ItemDisplayPatches { [CompilerGenerated] [DebuggerBrowsable(DebuggerBrowsableState.Never)] private static Action m_RefreshEnchantedIconAfter; [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static event Action RefreshEnchantedIconAfter { [CompilerGenerated] add { Action val = ItemDisplayPatches.m_RefreshEnchantedIconAfter; Action val2; do { val2 = val; Action value2 = (Action)(object)Delegate.Combine((Delegate?)(object)val2, (Delegate?)(object)value); val = Interlocked.CompareExchange(ref ItemDisplayPatches.m_RefreshEnchantedIconAfter, value2, val2); } while (val != val2); } [CompilerGenerated] remove { Action val = ItemDisplayPatches.m_RefreshEnchantedIconAfter; Action val2; do { val2 = val; Action value2 = (Action)(object)Delegate.Remove((Delegate?)(object)val2, (Delegate?)(object)value); val = Interlocked.CompareExchange(ref ItemDisplayPatches.m_RefreshEnchantedIconAfter, value2, val2); } while (val != val2); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] public static void RefreshEnchantedIconPostfix(ItemDisplay __instance, Item ___m_refItem) { try { Logger.LogTrace(string.Format("{0}::{1}(): Invoked for ItemDisplay {2} and Item {3} - {4} ({5}). Invoking {6}().", "ItemDisplayPatches", "RefreshEnchantedIconPostfix", ((Object)__instance).name, ___m_refItem?.ItemID, (___m_refItem != null) ? ___m_refItem.DisplayName : null, (___m_refItem != null) ? ___m_refItem.UID : null, "RefreshEnchantedIconAfter")); ItemDisplayPatches.RefreshEnchantedIconAfter?.Invoke(__instance, ___m_refItem); } catch (Exception ex) { Logger.LogException("ItemDisplayPatches::RefreshEnchantedIconPostfix(): Exception Invoking RefreshEnchantedIconAfter().", ex); } } } [HarmonyPatch(typeof(ItemManager))] public static class ItemManagerPatches { public delegate void GetVisualsByItem(Item input, ref ItemVisual itemVisual); [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static event GetVisualsByItem GetSpecialVisualsByItemAfter; public static event GetVisualsByItem GetVisualsByItemAfter; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] [HarmonyPatch(new Type[] { typeof(Item) })] public static void GetSpecialVisualsPostfix(ref Item _item, ref ItemVisual __result) { try { if (!((Object)(object)_item == (Object)null) && !string.IsNullOrEmpty(_item.UID)) { Logger.LogTrace(string.Format("{0}::{1}(): Invoked on Item {2} - {3} ({4}). Invoking {5}().", "ItemManagerPatches", "GetSpecialVisualsPostfix", _item.ItemID, _item.DisplayName, _item.UID, "GetSpecialVisualsByItemAfter")); ItemManagerPatches.GetSpecialVisualsByItemAfter?.Invoke(_item, ref __result); } } catch (Exception ex) { Logger.LogException("ItemManagerPatches::GetSpecialVisualsPostfix(): Exception Invoking GetSpecialVisualsByItemAfter().", ex); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] [HarmonyPatch(new Type[] { typeof(Item) })] private static void GetVisualsByItemPostfix(ref Item _item, ref ItemVisual __result) { try { if (!((Object)(object)_item == (Object)null) && !string.IsNullOrEmpty(_item.UID)) { Logger.LogTrace(string.Format("{0}::{1}(): Invoked on Item {2} - {3} ({4}). Invoking {5}()", "ItemManagerPatches", "GetVisualsByItemPostfix", _item.ItemID, _item.DisplayName, _item.UID, "GetVisualsByItemPostfix")); ItemManagerPatches.GetVisualsByItemAfter?.Invoke(_item, ref __result); } } catch (Exception ex) { Logger.LogException("ItemManagerPatches::GetVisualsByItemPostfix(): Exception Invoking GetVisualsByItemPostfix().", ex); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] [HarmonyPatch(new Type[] { typeof(int), typeof(ItemVisual) })] public static void PutBackVisualItemIDFix(ref int _itemID, ref ItemVisual _visuals) { try { if (!((Object)(object)_visuals == (Object)null)) { int itemIDFromName = _visuals.GetItemIDFromName(); Logger.LogTrace(string.Format("{0}::{1}(): Invoked for ItemID {2} and visual ItemVisual: {3}. GetItemIDFromName(): {4}.", "ItemManagerPatches", "PutBackVisualItemIDFix", _itemID, _visuals, itemIDFromName)); if (itemIDFromName != _itemID) { _itemID = itemIDFromName; Logger.LogTrace(string.Format("{0}::{1}(): ItemID set to {2}.", "ItemManagerPatches", "PutBackVisualItemIDFix", _itemID)); } } } catch (Exception ex) { Logger.LogException(string.Format("{0}::{1}(): Exception Fixing ItemID for _itemID {2}, _visuals {3}.", "ItemManagerPatches", "PutBackVisualItemIDFix", _itemID, _visuals), ex); } } } [HarmonyPatch(typeof(Item))] public static class ItemPatches { [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); public static event Action GetItemIconBefore; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPrefix] private static void ItemIconPrefix(Item __instance) { try { ItemPatches.GetItemIconBefore?.Invoke(__instance); } catch (Exception ex) { Logger.LogException("ItemPatches::ItemIconPrefix(): Exception Invoking GetItemIconBefore().", ex); } } } [HarmonyPatch(typeof(ResourcesPrefabManager))] internal static class ResourcesPrefabManagerPatches { public delegate bool TryGetItemPrefabDelegate(int itemID, out Item itemPrefab); public static List TryGetItemPrefabActions = new List(); [MultiLogger] private static IModifLogger Logger { get; set; } = new NullLogger(); [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] [HarmonyPatch(new Type[] { typeof(int) })] private static void GetItemPrefabByInt(int _itemID, ref Item __result) { try { if (!((Object)(object)__result != (Object)null)) { Logger.LogTrace("ResourcesPrefabManagerPatches::GetItemPrefabByInt: Invoking TryGetItemPrefabActions"); GetItemPrefab(_itemID, ref __result); } } catch (Exception ex) { Logger.LogException("ResourcesPrefabManagerPatches::GetItemPrefabByInt: Exception Invoking TryGetItemPrefabActions.", ex); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] [HarmonyPatch(new Type[] { typeof(string) })] private static void GetItemPrefabByString(string _itemIDString, ref Item __result) { try { if (!((Object)(object)__result != (Object)null) && int.TryParse(_itemIDString, out var result)) { Logger.LogTrace("ResourcesPrefabManagerPatches::GetItemPrefabByString: Invoking TryGetItemPrefabActions"); GetItemPrefab(result, ref __result); } } catch (Exception ex) { Logger.LogException("ResourcesPrefabManagerPatches::GetItemPrefabByString: Exception Invoking TryGetItemPrefabActions.", ex); } } private static void GetItemPrefab(int itemID, ref Item item) { for (int i = 0; i < TryGetItemPrefabActions.Count; i++) { if (TryGetItemPrefabActions[0](itemID, out var itemPrefab)) { item = itemPrefab; break; } } } } } namespace ModifAmorphic.Outward.Modules.Items.Models { internal class VisualSlotWrapper { private readonly VisualSlot _visualSlot; public Item m_currentItem { get { return _visualSlot.GetPrivateField("m_currentItem"); } set { _visualSlot.SetPrivateField("m_currentItem", value); } } public ItemVisual m_editorCurrentVisuals { get { return _visualSlot.GetPrivateField("m_editorCurrentVisuals"); } set { _visualSlot.SetPrivateField("m_editorCurrentVisuals", value); } } public ItemVisual m_currentVisual { get { return _visualSlot.GetPrivateField("m_currentVisual"); } set { _visualSlot.SetPrivateField("m_currentVisual", value); } } public Action PositionVisuals => delegate { _visualSlot.InvokePrivateMethod("PositionVisuals", Array.Empty()); }; private VisualSlotWrapper(VisualSlot visualSlot) { _visualSlot = visualSlot; } public static VisualSlotWrapper Wrap(VisualSlot visualSlot) { return new VisualSlotWrapper(visualSlot); } } } namespace ModifAmorphic.Outward.Modules.Crafting { public class CustomCraftingModule : IModifModule { private readonly Func _loggerFactory; private readonly CraftingMenuUIService _menuUiService; private readonly RecipeDisplayService _recipeDisplayService; private readonly CustomRecipeService _customRecipeService; private readonly CustomCraftingService _craftingService; private readonly List _registeredMenus = new List(); private readonly ConcurrentDictionary> _characterMenus = new ConcurrentDictionary>(); private readonly ConcurrentDictionary _craftingMenus = new ConcurrentDictionary(); private readonly ConcurrentDictionary> _customRecipes = new ConcurrentDictionary>(); private readonly ConcurrentDictionary _craftingStationTypes = new ConcurrentDictionary(); public readonly CraftingMenuEvents CraftingMenuEvents; private IModifLogger Logger => _loggerFactory(); internal RecipeDisplayService RecipeDisplayService => _recipeDisplayService; internal CustomRecipeService CustomRecipeService => _customRecipeService; internal CustomCraftingService CustomCraftingService => _craftingService; public HashSet PatchDependencies { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterUIPatches)); hashSet.Add(typeof(CraftingMenuPatches)); hashSet.Add(typeof(CompatibleIngredientPatches)); hashSet.Add(typeof(LocalizationManagerPatches)); return hashSet; } } public HashSet EventSubscriptions { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterUIPatches)); hashSet.Add(typeof(CraftingMenuPatches)); hashSet.Add(typeof(LocalizationManagerPatches)); return hashSet; } } public HashSet DepsWithMultiLogger { get { HashSet hashSet = new HashSet(); hashSet.Add(typeof(CharacterUIPatches)); hashSet.Add(typeof(CraftingMenuPatches)); hashSet.Add(typeof(CompatibleIngredientPatches)); hashSet.Add(typeof(LocalizationManagerPatches)); return hashSet; } } internal CustomCraftingModule(CraftingMenuUIService menuUIService, RecipeDisplayService recipeDisplayService, CustomRecipeService customRecipeService, CustomCraftingService craftingService, CraftingMenuEvents craftingMenuEvents, Func loggerFactory) { _menuUiService = menuUIService; _recipeDisplayService = recipeDisplayService; _customRecipeService = customRecipeService; _craftingService = craftingService; CraftingMenuEvents = craftingMenuEvents; _loggerFactory = loggerFactory; CharacterUIPatches.AwakeBefore += CharacterUIPatches_AwakeBefore; CharacterUIPatches.RegisterMenuAfter += CharacterUIPatches_RegisterMenuAfter; CraftingMenuPatches.AwakeInitAfter += CraftingMenuPatches_AwakeInitAfter; recipeDisplayService.MenuHiding += delegate(CustomCraftingMenu menu) { CraftingMenuEvents.InvokeMenuHiding(menu); }; } private void CraftingMenuPatches_AwakeInitAfter(CraftingMenu craftingMenu) { if (!(craftingMenu is CustomCraftingMenu)) { AddCustomCraftingMenus(craftingMenu); } } private void CharacterUIPatches_AwakeBefore(CharacterUI characterUI) { AddCraftingTabAndFooter(characterUI); } private void CharacterUIPatches_RegisterMenuAfter(CharacterUI characterUI, CustomCraftingMenu craftingMenu) { Type type = ((object)craftingMenu).GetType(); int rewiredID = characterUI.RewiredID; if (_craftingMenus.TryGetValue(type, out var value)) { MenuTab[] privateField = characterUI.GetPrivateField("m_menuTabs"); CraftingMenuMetadata meta = value.Clone(); meta.MenuType = type; meta.MenuPanel = craftingMenu; meta.MenuDisplay = ((Component)craftingMenu).gameObject; meta.MenuTab = ((Component)privateField.First((MenuTab t) => t.TabName == meta.TabName).Tab).gameObject; meta.MenuFooter = _menuUiService.GetFooter(characterUI, meta.FooterName); List orAdd = _characterMenus.GetOrAdd(rewiredID, new List()); orAdd.Add(meta); CraftingMenuEvents?.InvokeMenuLoading(craftingMenu); } } public CraftingType RegisterCraftingMenu(string menuDisplayName, MenuIcons menuIcons = null) where T : CustomCraftingMenu { //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if (_craftingMenus.ContainsKey(typeof(T))) { throw new ArgumentException(string.Format("{0} of type {1} already exists. ", "CustomCraftingMenu", typeof(T)) + "Only one instance of a type derived from CustomCraftingMenu can be added.", "T"); } menuIcons?.TrySetIconNames(menuDisplayName); _craftingMenus.TryAdd(typeof(T), new CraftingMenuMetadata { MenuType = typeof(T), TabButtonName = "btn" + typeof(T).Name, TabName = "PlayerMenu_Tab_" + typeof(T).Name, TabDisplayName = menuDisplayName, MenuName = typeof(T).Name, MenuIcons = menuIcons, FooterName = typeof(T).Name + "Footer" }); _registeredMenus.Add(_craftingMenus[typeof(T)]); _craftingStationTypes.TryAdd(typeof(T), (CraftingType)_menuUiService.AddIngredientTag()); TryAddRecipes(); return _craftingStationTypes[typeof(T)]; } public void RegisterRecipe(Recipe recipe) where T : CustomCraftingMenu { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) ValidateRecipe(recipe); Logger.LogTrace("CustomCraftingModule:RegisterRecipe:: Recipe " + ((Object)recipe).name + " is valid. Registering recipe."); Dictionary orAdd = _customRecipes.GetOrAdd(typeof(T), new Dictionary()); UID uID = recipe.UID; if (orAdd.ContainsKey(((object)(UID)(ref uID)).ToString())) { throw new ArgumentException($"A Recipe with UID '{recipe.UID}' is already registered for crafting station type {typeof(T).Name}.", "recipe"); } uID = recipe.UID; orAdd.Add(((object)(UID)(ref uID)).ToString(), new RecipeMetadata { CraftingStationType = typeof(T), Recipe = recipe }); TryAddRecipes(); } public List GetRegisteredRecipes() { Dictionary value; return _customRecipes.TryGetValue(typeof(T), out value) ? value.Values.Select((RecipeMetadata r) => r.Recipe).ToList() : new List(); } public void RegisterCustomCrafter(ICustomCrafter crafter) where T : CustomCraftingMenu { _craftingService.AddOrUpdateCrafter(crafter); } public void RegisterMenuIngredientFilters(MenuIngredientFilters filter) where T : CustomCraftingMenu { _craftingService.AddOrUpdateIngredientFilter(filter); } public void UnregisterMenuIngredientFilters() where T : CustomCraftingMenu { _craftingService.TryRemoveIngredientFilter(); } public bool TryGetRegisteredIngredientFilters(out MenuIngredientFilters filter) where T : CustomCraftingMenu { return _craftingService.TryGetIngredientFilter(out filter); } public void RegisterRecipeVisibiltyController(IRecipeVisibiltyController visibiltyController) where T : CustomCraftingMenu { _recipeDisplayService.AddOrUpdateRecipeVisibiltyController(visibiltyController); } public void UnregisterRecipeVisibiltyController() where T : CustomCraftingMenu { _recipeDisplayService.TryRemoveRecipeVisibiltyController(); } public void RegisterCompatibleIngredientMatcher(ICompatibleIngredientMatcher matcher) where T : CustomCraftingMenu { _craftingService.AddOrUpdateCompatibleIngredientMatcher(matcher); } public void RegisterConsumedItemSelector(IConsumedItemSelector itemSelector) where T : CustomCraftingMenu { _craftingService.AddOrUpdateConsumedItemSelector(itemSelector); } public void UnregisterConsumedItemSelector() where T : CustomCraftingMenu { _craftingService.TryRemoveConsumedItemSelector(); } public void RegisterRecipeSelectorDisplayConfig(RecipeSelectorDisplayConfig config) where T : CustomCraftingMenu { _recipeDisplayService.AddUpdateDisplayConfig(config); } public bool TryGetRegisteredRecipeDisplayConfig(out RecipeSelectorDisplayConfig config) where T : CustomCraftingMenu { return _recipeDisplayService.TryGetDisplayConfig(out config); } public void RegisterStaticIngredients(IEnumerable ingredients) where T : CustomCraftingMenu { _recipeDisplayService.AddOrUpdateStaticIngredients(ingredients); } public void UnregisterStaticIngredients() where T : CustomCraftingMenu { _recipeDisplayService.TryRemoveStaticIngredients(); } public void EnableCraftingMenu() where T : CustomCraftingMenu { if (!_craftingMenus.TryGetValue(typeof(T), out var _)) { throw new ArgumentException($"CustomCraftingMenu {typeof(T)} is not a registered menu type. Menus " + "must be registered using RegisterCraftingMenu and loaded before they can be enabled or disabled.", "T"); } IEnumerable enumerable = SplitScreenManager.Instance.LocalPlayers.Select((SplitPlayer p) => p.AssignedCharacter); foreach (Character item in enumerable) { int playerID = item.OwnerPlayerSys.PlayerID; if (_characterMenus.TryGetValue(playerID, out var value2)) { CraftingMenuMetadata meta = value2.FirstOrDefault((CraftingMenuMetadata m) => m.MenuType == typeof(T)); _menuUiService.EnableMenuTab(item.CharacterUI, meta); } } } public void DisableCraftingMenu() where T : CustomCraftingMenu { if (!_craftingMenus.TryGetValue(typeof(T), out var _)) { throw new ArgumentException($"CustomCraftingMenu {typeof(T)} is not a registered menu type. Menus " + "must be registered using RegisterCraftingMenu and loaded before they can be enabled or disabled.", "T"); } IEnumerable enumerable = SplitScreenManager.Instance.LocalPlayers.Select((SplitPlayer p) => p.AssignedCharacter); foreach (Character item in enumerable) { int playerID = item.OwnerPlayerSys.PlayerID; if (_characterMenus.TryGetValue(playerID, out var value2)) { CraftingMenuMetadata meta = value2.FirstOrDefault((CraftingMenuMetadata m) => m.MenuType == typeof(T)); _menuUiService.DisableMenuTab(item.CharacterUI, meta); } } } private void ValidateRecipe(Recipe recipe) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Invalid comparison between Unknown and I4 //IL_013d: Unknown result type (might be due to invalid IL or missing references) if (recipe.IsFullySetup) { return; } string text = $"Recipe '{recipe.RecipeID} - {recipe.Name}' IsFullySetup is false."; if (recipe.Results == null || recipe.Results.Length == 0 || recipe.Results[0] == null) { throw new ArgumentException(text + " The recipe's Results are not configured properly. Either the Results are empty or null.", "recipe"); } if ((Object)(object)recipe.Results[0].RefItem == (Object)null) { throw new ArgumentException($"{text} Recipe's Results[0].RefItem is null. Ensure ItemID '{recipe.Results[0].ItemID}' of the result has a valid Prefab.", "recipe"); } if (recipe.Ingredients == null || recipe.Ingredients.Length == 0) { throw new ArgumentException(text + " Recipe's Ingredients are null or empty. Recipe must have ingredients set.", "recipe"); } for (int i = 0; i < recipe.Ingredients.Length; i++) { if ((int)recipe.Ingredients[i].ActionType == 1 && (Object)(object)recipe.Ingredients[i].AddedIngredient == (Object)null) { throw new ArgumentException($"{text} Recipe ingredient Ingredients[{i}] is an AddSpecificIngredient ActionType, but has no AddedIngredient set. " + "An AddSpecificIngredient ingredient must have a non null AddedIngredient.", "recipe"); } if ((int)recipe.Ingredients[i].ActionType == 0 && !((UidSelector)(object)recipe.Ingredients[i].AddedIngredientType).IsSet) { throw new ArgumentException($"{text} Recipe ingredient Ingredients[{i}] is an AddGenericIngredient ActionType, but it's AddedIngredientType.IsSet property returned false. " + "Ensure the Tag is configured properly for this AddGenericIngredient ingredient type.", "recipe"); } } } private void TryAddRecipes() { IEnumerable>> enumerable = _customRecipes.Where((KeyValuePair> rt) => _craftingStationTypes.ContainsKey(rt.Key)); foreach (KeyValuePair> stationRecipes in enumerable) { List list = stationRecipes.Value.Where((KeyValuePair kvp) => (int)kvp.Value.CustomCraftingType == 0).Select(delegate(KeyValuePair kvp) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) kvp.Value.CustomCraftingType = _craftingStationTypes[stationRecipes.Key]; kvp.Value.Recipe.SetCraftingType(_craftingStationTypes[stationRecipes.Key]); return kvp.Value.Recipe; }).ToList(); Logger.LogDebug(string.Format("{0}:{1}:: Registering {2} recipes for crafting station type {3}.", "CustomCraftingModule", "TryAddRecipes", list?.Count(), stationRecipes.Key)); _customRecipeService.AddRecipes(list); } } private void AddCraftingTabAndFooter(CharacterUI characterUI) { Type[] array = characterUI.GetPrivateField("MenuTypes"); int num = array.Length; Array.Resize(ref array, array.Length + _craftingMenus.Count); for (int num2 = _registeredMenus.Count - 1; num2 >= 0; num2--) { CraftingMenuMetadata craftingMenuMetadata = _registeredMenus[num2]; craftingMenuMetadata.MenuScreenNo = num++; array[craftingMenuMetadata.MenuScreenNo] = craftingMenuMetadata.MenuType; _menuUiService.AddMenuTab(characterUI, craftingMenuMetadata.TabName, craftingMenuMetadata.TabDisplayName, craftingMenuMetadata.TabButtonName, craftingMenuMetadata.MenuScreenNo, craftingMenuMetadata.OrderAfterTab, craftingMenuMetadata.MenuIcons); _menuUiService.AddFooter(characterUI, craftingMenuMetadata.MenuScreenNo, craftingMenuMetadata.FooterName); } characterUI.SetPrivateField("MenuTypes", array); MenuPanel[] array2 = characterUI.GetPrivateField("m_menus"); if (array2 != null && array2.Length < array.Length) { Array.Resize(ref array2, array.Length); } else { array2 = (MenuPanel[])(object)new MenuPanel[array.Length]; } characterUI.SetPrivateField("m_menus", array2); } private void AddCustomCraftingMenus(CraftingMenu baseCraftingMenu) { //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) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair craftingMenu in _craftingMenus) { Type key = craftingMenu.Key; CraftingMenuMetadata value = craftingMenu.Value; Type type = key; GameObject val = _menuUiService.AddCustomMenu(baseCraftingMenu, value); CustomCraftingMenu customCraftingMenu = (CustomCraftingMenu)(object)val.GetComponent(type); if (!customCraftingMenu.PermanentCraftingStationType.HasValue) { customCraftingMenu.CustomCraftingType = _craftingStationTypes[type]; Logger.LogDebug("CustomCraftingModule::AddCustomCraftingMenus(): " + string.Format("Set {0} to {1} for ", "CustomCraftingType", _craftingStationTypes[type]) + $"type {value.MenuType}"); } if (customCraftingMenu.IsCustomCraftingStation()) { _customRecipeService.AddOrGetCraftingStationRecipes(customCraftingMenu.GetRecipeCraftingType()); } } } } public class AvailableIngredientFilter { public enum FilterLogic { IncludeItems, ExcludeItems, OnlyItems } public Tag InventoryFilterTag { get; set; } public FilterLogic EnchantFilter { get; set; } = FilterLogic.ExcludeItems; public HashSet ItemTypes { get; set; } = new HashSet(); public FilterLogic SpecificItemFilter { get; set; } = FilterLogic.IncludeItems; public HashSet SpecificItemIDs { get; set; } = new HashSet(); } public class CraftingMenuEvents { public delegate void MenuHidingDelegate(CustomCraftingMenu menu); public delegate void MenuLoadedDelegate(CustomCraftingMenu menu); public delegate void MenuStartingDelegate(CustomCraftingMenu menu); public delegate void MenuShowingDelegate(CustomCraftingMenu menu); public delegate void DynamicCraftCompleteDelegate(DynamicCraftingResult result, int resultMultiplier, CustomCraftingMenu menu); public event MenuHidingDelegate MenuHiding; public event MenuLoadedDelegate MenuLoaded; public event MenuStartingDelegate MenuStarting; public event MenuShowingDelegate MenuShowing; public event DynamicCraftCompleteDelegate DynamicCraftComplete; internal void InvokeMenuHiding(CustomCraftingMenu menu) { this.MenuHiding?.Invoke(menu); } internal void InvokeMenuLoading(CustomCraftingMenu menu) { this.MenuLoaded?.Invoke(menu); } internal void InvokeMenuStarting(CustomCraftingMenu menu) { this.MenuStarting?.Invoke(menu); } internal void InvokeMenuShowing(CustomCraftingMenu menu) { this.MenuShowing?.Invoke(menu); } internal void InvokeDynamicCraftComplete(DynamicCraftingResult result, int resultMultiplier, CustomCraftingMenu menu) { this.DynamicCraftComplete?.Invoke(result, resultMultiplier, menu); } } internal class CraftingMenuMetadata { public Type MenuType { get; set; } public string TabName { get; set; } public string TabDisplayName { get; set; } public string TabButtonName { get; set; } public MenuIcons MenuIcons { get; set; } public string OrderAfterTab { get; set; } = "btnCrafting"; public string MenuName { get; set; } public string FooterName { get; set; } public int MenuScreenNo { get; set; } = -1; public CustomCraftingMenu MenuPanel { get; set; } public GameObject MenuTab { get; set; } public GameObject MenuFooter { get; set; } public GameObject MenuDisplay { get; set; } public CraftingMenuMetadata Clone() { return new CraftingMenuMetadata { MenuType = MenuType, TabName = TabName, TabDisplayName = TabDisplayName, TabButtonName = TabButtonName, MenuIcons = MenuIcons, OrderAfterTab = OrderAfterTab, MenuName = MenuName, FooterName = FooterName, MenuScreenNo = MenuScreenNo, MenuPanel = MenuPanel, MenuTab = MenuTab, MenuFooter = MenuFooter, MenuDisplay = MenuDisplay }; } } public class CustomCraftingMenu : CraftingMenu { private static readonly IModifLogger nullLogger = new NullLogger(); private Func _loggerFactory = () => nullLogger; private CraftingType? _permenantCraftingStationType; private CraftingType _customCraftingType; private bool _hideFreeCraftingRecipe = false; public IngredientCraftData IngredientCraftData = new IngredientCraftData(); protected Dictionary _craftingBackgrounds = new Dictionary(); private int[] _selectorIngredientMap = null; private bool showRecurseCheck = false; public CustomCraftingModule ParentCraftingModule { get; private set; } private RecipeDisplayService RecipeDisplayService => ParentCraftingModule.RecipeDisplayService; protected virtual string ModId { get; set; } protected IModifLogger Logger => LoggerFactory(); protected Func LoggerFactory { get { return _loggerFactory; } set { _loggerFactory = value; } } public CraftingType? PermanentCraftingStationType { get { return _permenantCraftingStationType; } protected set { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (value.HasValue && !value.Value.IsDefinedValue()) { throw new ArgumentOutOfRangeException("Value must be one of the built in Recipe.CraftingType values."); } _permenantCraftingStationType = value; } } public CraftingType CustomCraftingType { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return _customCraftingType; } internal set { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (value.IsDefinedValue()) { throw new ArgumentOutOfRangeException("Value must not be one of the built in Recipe.CraftingType values."); } _customCraftingType = value; } } public bool HideFreeCraftingRecipe { get { return _hideFreeCraftingRecipe; } protected set { _hideFreeCraftingRecipe = value; } } protected CraftingStation _craftingStation { get { return ((CraftingMenu)(object)this).GetPrivateField("m_craftingStation"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_craftingStation", value); } } protected Text _lblStationName { get { return ((CraftingMenu)(object)this).GetPrivateField("m_lblStationName"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_lblStationName", value); } } protected bool _simpleMode { get { return ((CraftingMenu)(object)this).GetPrivateField("m_simpleMode"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_simpleMode", value); } } protected CraftingType _currentlyDisplayedCraftingType { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return ((CraftingMenu)(object)this).GetPrivateField("m_currentlyDisplayedCraftingType"); } set { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((CraftingMenu)(object)this).SetPrivateField("m_currentlyDisplayedCraftingType", value); } } protected Sprite _survivalCraftingBg { get { return ((CraftingMenu)(object)this).GetPrivateField("m_survivalCraftingBg"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_survivalCraftingBg", value); } } protected Sprite _cookingPotCraftingBg { get { return ((CraftingMenu)(object)this).GetPrivateField("m_cookingPotCraftingBg"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_cookingPotCraftingBg", value); } } protected Sprite _cookingFireCraftingBg { get { return ((CraftingMenu)(object)this).GetPrivateField("m_cookingFireCraftingBg"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_cookingFireCraftingBg", value); } } protected Sprite _alchemyCraftingBg { get { return ((CraftingMenu)(object)this).GetPrivateField("m_alchemyCraftingBg"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_alchemyCraftingBg", value); } } protected Image _imgCraftingBackground { get { return ((CraftingMenu)(object)this).GetPrivateField("m_imgCraftingBackground"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_imgCraftingBackground", value); } } protected Image _singleIngredientBackground { get { return ((CraftingMenu)(object)this).GetPrivateField("m_singleIngredientBackground"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_singleIngredientBackground", value); } } protected Image _multipleIngrenentsBrackground { get { return ((CraftingMenu)(object)this).GetPrivateField("m_multipleIngrenentsBrackground"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_multipleIngrenentsBrackground", value); } } internal IngredientSelector _ingredientSelectorTemplate { get { return ((CraftingMenu)(object)this).GetPrivateField("m_ingredientSelectorTemplate"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_ingredientSelectorTemplate", value); } } internal IngredientSelector[] _ingredientSelectors { get { return ((CraftingMenu)(object)this).GetPrivateField("m_ingredientSelectors"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_ingredientSelectors", value); } } private List _ingredientSelectorCachedItems { get { return ((CraftingMenu)(object)this).GetPrivateField>("ingredientSelectorCachedItems"); } set { ((CraftingMenu)(object)this).SetPrivateField>("ingredientSelectorCachedItems", value); } } private ItemListSelector _tempSelectorWindow { get { return ((CraftingMenu)(object)this).GetPrivateField("m_tempSelectorWindow"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_tempSelectorWindow", value); } } private Transform _selectorWindowPos { get { return ((CraftingMenu)(object)this).GetPrivateField("m_selectorWindowPos"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_selectorWindowPos", value); } } internal int[] _lastFreeRecipeIngredientIDs { get { return ((CraftingMenu)(object)this).GetPrivateField("m_lastFreeRecipeIngredientIDs"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_lastFreeRecipeIngredientIDs", value); } } protected Text _lblFreeRecipeDescription { get { return ((CraftingMenu)(object)this).GetPrivateField("m_lblFreeRecipeDescription"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_lblFreeRecipeDescription", value); } } protected DictionaryExt _availableIngredients { get { return ((CraftingMenu)(object)this).GetPrivateField>("m_availableIngredients"); } set { ((CraftingMenu)(object)this).SetPrivateField>("m_availableIngredients", value); } } protected static string[] _freeRecipesLocKey { get { return typeof(CraftingMenu).GetField("m_freeRecipesLocKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as string[]; } set { typeof(CraftingMenu).GetField("m_freeRecipesLocKey", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, value); } } protected List _allRecipes { get { return ((CraftingMenu)(object)this).GetPrivateField>("m_allRecipes"); } set { ((CraftingMenu)(object)this).SetPrivateField>("m_allRecipes", value); } } protected List> _complexeRecipes { get { return ((CraftingMenu)(object)this).GetPrivateField>>("m_complexeRecipes"); } set { ((CraftingMenu)(object)this).SetPrivateField>>("m_complexeRecipes", value); } } protected bool _refreshComplexeRecipeRequired { get { return ((CraftingMenu)(object)this).GetPrivateField("m_refreshComplexeRecipeRequired"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_refreshComplexeRecipeRequired", value); } } protected int _lastFreeRecipeIndex { get { return ((CraftingMenu)(object)this).GetPrivateField("m_lastFreeRecipeIndex"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_lastFreeRecipeIndex", value); } } protected int _lastRecipeIndex { get { return ((CraftingMenu)(object)this).GetPrivateField("m_lastRecipeIndex"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_lastRecipeIndex", value); } } internal RecipeDisplay _recipeDisplayTemplate { get { return ((CraftingMenu)(object)this).GetPrivateField("m_recipeDisplayTemplate"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_recipeDisplayTemplate", value); } } internal List _recipeDisplays { get { return ((CraftingMenu)(object)this).GetPrivateField>("m_recipeDisplays"); } set { ((CraftingMenu)(object)this).SetPrivateField>("m_recipeDisplays", value); } } internal RectTransform _recipeSeparator { get { return ((CraftingMenu)(object)this).GetPrivateField("m_recipeSeparator"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_recipeSeparator", value); } } internal RecipeResultDisplay _recipeResultDisplay { get { return ((CraftingMenu)(object)this).GetPrivateField("m_recipeResultDisplay"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_recipeResultDisplay", value); } } internal RecipeDisplay _freeRecipeDisplay { get { return ((CraftingMenu)(object)this).GetPrivateField("m_freeRecipeDisplay"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_freeRecipeDisplay", value); } } internal ItemDetailsDisplay _itemDetailPanel { get { return ((CraftingMenu)(object)this).GetPrivateField("m_itemDetailPanel"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_itemDetailPanel", value); } } internal GameObject _freeRecipeDescriptionPanel { get { return ((CraftingMenu)(object)this).GetPrivateField("m_freeRecipeDescriptionPanel"); } set { ((CraftingMenu)(object)this).SetPrivateField("m_freeRecipeDescriptionPanel", value); } } internal Action ResetFreeRecipeLastIngredients => delegate { ((CraftingMenu)(object)this).InvokePrivateMethod("ResetFreeRecipeLastIngredients", Array.Empty()); }; protected Action RefreshAutoRecipe => delegate { ((CraftingMenu)(object)this).InvokePrivateMethod("RefreshAutoRecipe", Array.Empty()); }; protected Action CancelCrafting => delegate { ((CraftingMenu)(object)this).InvokePrivateMethod("CancelCrafting", Array.Empty()); }; protected Action SetCraftButtonEnable => delegate(bool show) { ((CraftingMenu)(object)this).InvokePrivateMethod("SetCraftButtonEnable", new object[1] { show }); }; protected Action RefreshFreeRecipeResult => delegate { ((CraftingMenu)(object)this).InvokePrivateMethod("RefreshFreeRecipeResult", Array.Empty()); }; protected Action CloseItemSelectionWindow => delegate { ((CraftingMenu)(object)this).InvokePrivateMethod("CloseItemSelectionWindow", Array.Empty()); }; internal bool BaseShowDone { get; private set; } internal int GetLastRecipeIndex() { return _lastRecipeIndex; } internal int SetLastRecipeIndex(int lastRecipeIndex) { return _lastRecipeIndex = lastRecipeIndex; } protected override void AwakeInit() { //IL_0087: 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) Logger.LogDebug("CustomCraftingMenu::AwakeInit() called on type " + ((object)this).GetType().Name); if (string.IsNullOrEmpty(ModId)) { throw new InvalidOperationException(string.Format("AwakeInit() was invoked on type {0} before property {1} was set. ", ((object)this).GetType(), "ModId") + "A CustomCraftingMenu must have it's ModId configured before it can be used."); } try { ParentCraftingModule = ModifModules.GetCustomCraftingModule(ModId); if (PermanentCraftingStationType.HasValue) { _currentlyDisplayedCraftingType = PermanentCraftingStationType.Value; Logger.LogDebug($"CustomCraftingMenu::AwakeInit(): Set m_craftingStationType to {PermanentCraftingStationType}. Current value: {_currentlyDisplayedCraftingType}"); } ((CraftingMenu)this).AwakeInit(); RecipeDisplayService.ExtendIngredientSelectors(this); _selectorIngredientMap = new int[_ingredientSelectors.Length]; } catch (Exception ex) { Logger.LogException("CustomCraftingMenu::AwakeInit() Exception.", ex); } } protected override void StartInit() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0066: Unknown result type (might be due to invalid IL or missing references) string text = ((object)this).GetType().Name + "::StartInit():"; try { ParentCraftingModule.CraftingMenuEvents.InvokeMenuStarting(this); } catch (Exception ex) { Logger.LogException(text + " Exception invoking event with InvokeMenuStarting().", ex); } CraftingType currentlyDisplayedCraftingType = _currentlyDisplayedCraftingType; _currentlyDisplayedCraftingType = GetRecipeCraftingType(); ((CraftingMenu)this).StartInit(); _currentlyDisplayedCraftingType = currentlyDisplayedCraftingType; if (HideFreeCraftingRecipe) { ((UIElement)_freeRecipeDisplay).Hide(); ((Component)_freeRecipeDisplay).gameObject.SetActive(false); } } public override void Show() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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) string text = ((object)this).GetType().Name + "::Show():"; try { Logger.LogDebug(text + " Started."); try { ParentCraftingModule.CraftingMenuEvents.InvokeMenuShowing(this); } catch (Exception ex) { Logger.LogException(text + " Exception invoking event with InvokeMenuShowing().", ex); } if (PermanentCraftingStationType.HasValue && PermanentCraftingStationType.Value.IsDefinedValue() && !showRecurseCheck) { Logger.LogDebug($"{text} {((object)this).GetType().Name} is a permenant {PermanentCraftingStationType} crafting station."); showRecurseCheck = true; Show(PermanentCraftingStationType.Value); return; } showRecurseCheck = false; Logger.LogDebug($"{text} Before base.Show(). _lastRecipeIndex: {_lastRecipeIndex}"); BaseShowDone = false; ((CraftingMenu)this).Show(); BaseShowDone = true; Logger.LogDebug($"{text} After base.Show(). _lastRecipeIndex: {_lastRecipeIndex}"); ResetFreeRecipeLastIngredients(); Logger.LogDebug($"{text} Getting Recipes for CraftingType {GetRecipeCraftingType()} and character '{((UIElement)this).LocalCharacter.UID}'."); List recipes = RecipeManager.Instance.GetRecipes(GetRecipeCraftingType(), ((UIElement)this).LocalCharacter); RecipeDisplayService.AddStaticIngredients(this, ref recipes); _allRecipes = recipes; _refreshComplexeRecipeRequired = true; RefreshAutoRecipe(); for (int i = 0; i < _selectorIngredientMap.Length; i++) { _selectorIngredientMap[i] = -1; } RecipeDisplayService.PositionSelectors((CraftingMenu)(object)this, _ingredientSelectors); RecipeDisplayService.ResetRecipeDisplaySelection(this, resetSelection: true); } catch (Exception ex2) { Logger.LogException(text + " Exception.", ex2); } } private void Show(CraftingType craftingStationType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 if ((int)craftingStationType != 0 && (int)craftingStationType != 1 && (int)craftingStationType != 2) { throw new ArgumentException("Invalid CraftingType. Allowed CraftingTypes are Cooking, Alchemy and Survival.", "craftingStationType"); } int num = 5010205; if ((int)craftingStationType == 1) { num = 1900001; } Item val = ResourcesPrefabManager.Instance.GetItemPrefab(num); if ((Object)(object)val == (Object)null) { val = ResourcesPrefabManager.Instance.GenerateItem(num.ToString()); } ((MenuPanel)this).Show((Item)(object)((Component)val).gameObject.GetComponentInChildren()); } protected override void OnHide() { try { RecipeDisplayService.OnMenuHiding(this); } catch (Exception ex) { Logger.LogException(((object)this).GetType().Name + "::OnHide: Error invoking RecipeDisplayService.OnMenuHiding(this).", ex); } ((CraftingMenu)this).OnHide(); } public Recipe GetSelectedRecipe() { return (_lastRecipeIndex != -1) ? _complexeRecipes[_lastRecipeIndex].Value : null; } public List GetSelectedIngredients() { return (from s in _ingredientSelectors where ((s != null) ? s.AssignedIngredient : null) != null && !s.IsMissingIngredient select s.AssignedIngredient).ToList(); } public bool TryOnIngredientSelectorClicked(int selectorIndex) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Invalid comparison between Unknown and I4 //IL_0217: 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) if (_selectorIngredientMap[selectorIndex] == -1) { return false; } IngredientSelector val = _ingredientSelectors[selectorIndex]; List ingredientSelectorCachedItems = _ingredientSelectorCachedItems; ingredientSelectorCachedItems.Clear(); DictionaryExt availableIngredients = _availableIngredients; int num = _selectorIngredientMap[selectorIndex]; int lastRecipeIndex = _lastRecipeIndex; if (lastRecipeIndex != -1) { if ((int)_complexeRecipes[lastRecipeIndex].Value.Ingredients[num].ActionType == 0) { IList stepCompatibleIngredients = _recipeDisplays[lastRecipeIndex].GetStepCompatibleIngredients(num); CompatibleIngredient val2 = default(CompatibleIngredient); for (int i = 0; i < stepCompatibleIngredients.Count; i++) { if (availableIngredients.TryGetValue(stepCompatibleIngredients[i], ref val2) && val2.AvailableQty > 0) { ingredientSelectorCachedItems.Add(val2.ItemID); } } } } else { for (int j = 0; j < availableIngredients.Count; j++) { if (availableIngredients.Values[j].AvailableQty > 0 || val.AssignedIngredient == availableIngredients.Values[j]) { ingredientSelectorCachedItems.Add(availableIngredients.Values[j].ItemID); } } } if (ingredientSelectorCachedItems.Count <= 0) { return true; } _tempSelectorWindow = ((UIElement)this).m_characterUI.GetListSelector(); ItemListSelector tempSelectorWindow = _tempSelectorWindow; if (Object.op_Implicit((Object)(object)_tempSelectorWindow)) { tempSelectorWindow.onItemHovered = base.RefreshItemDetailDisplay; tempSelectorWindow.onItemClicked = delegate(IItemDisplay _display) { IngredientSelectorChanged(selectorIndex, (_display != null) ? _display.RefItem.ItemID : (-1)); CloseItemSelectionWindow(); }; tempSelectorWindow.Position = (Object.op_Implicit((Object)(object)_selectorWindowPos) ? _selectorWindowPos.position : ((Component)this).transform.position); tempSelectorWindow.Title = val.Text; tempSelectorWindow.ShowSelector((IList)ingredientSelectorCachedItems, ((Component)val).gameObject, lastRecipeIndex == -1); } return true; } private void IngredientSelectorChanged(int selectorIndex, int itemID) { CompatibleIngredient val = default(CompatibleIngredient); _availableIngredients.TryGetValue(itemID, ref val); int num = _selectorIngredientMap[selectorIndex]; IngredientSelector[] ingredientSelectors = _ingredientSelectors; RecipeIngredient val2 = ((_lastRecipeIndex != -1) ? _complexeRecipes[_lastRecipeIndex].Value.Ingredients[num] : null); ingredientSelectors[selectorIndex].Set(val2, val); if (_lastRecipeIndex != -1) { return; } RefreshFreeRecipeResult(); bool obj = false; for (int i = 0; i < ingredientSelectors.Length; i++) { if (ingredientSelectors[i].AssignedIngredient != null) { obj = true; } } SetCraftButtonEnable(obj); } private void SetSelectorIngredientMap(int recipeIndex, List ingredients) { int lastRecipeIndex = _lastRecipeIndex; IngredientSelector[] ingredientSelectors = _ingredientSelectors; RecipeIngredient[] ingredients2 = _complexeRecipes[recipeIndex].Value.Ingredients; Dictionary dictionary = ingredients.ToDictionary((StaticIngredient s) => s.IngredientID, (StaticIngredient s) => s); for (int i = 0; i < _selectorIngredientMap.Length; i++) { _selectorIngredientMap[i] = -1; } for (int j = 0; j < _selectorIngredientMap.Length; j++) { Logger.LogDebug($"OnRecipeSelectedOverride:: ingIndex:{j}, recipeIngredients.Length: {ingredients2.Length}"); if (ingredients2.Length > j) { Logger.LogDebug($"OnRecipeSelectedOverride:: recipeIngredients[ingIndex] is CustomRecipeIngredient: {ingredients2[j] is CustomRecipeIngredient}"); if (ingredients2[j] is CustomRecipeIngredient) { Logger.LogDebug($"staticIngredients.TryGetValue(customIngredient.CustomRecipeIngredientID, out var staticConfig): {dictionary.TryGetValue(((CustomRecipeIngredient)(object)ingredients2[j]).CustomRecipeIngredientID, out var _)}"); } } if (ingredients2.Length > j && ingredients2[j] is CustomRecipeIngredient customRecipeIngredient && dictionary.TryGetValue(customRecipeIngredient.CustomRecipeIngredientID, out var value2)) { int ingredientSlotPosition = (int)value2.IngredientSlotPosition; _selectorIngredientMap[ingredientSlotPosition] = j; } } int k = 0; for (int l = 0; l < _selectorIngredientMap.Length; l++) { if (_selectorIngredientMap[l] == -1) { for (; Extensions.Contains(_selectorIngredientMap, k); k++) { } if (k < ingredients2.Length) { _selectorIngredientMap[l] = k; Logger.LogDebug($"SetSelectorIngredientMap:: _selectorIngredientMap Slot {l}'s ingredient set to IngredientIndex {k}"); k++; } } } } internal void SetSelectorsNavigation(int recipeIndex) { if (RecipeDisplayService.TryGetDisplayConfig(((object)this).GetType(), out var config) && recipeIndex != -1) { IngredientSelector[] ingredientSelectors = _ingredientSelectors; RecipeResultDisplay recipeResultDisplay = _recipeResultDisplay; Button craftButton = ((recipeResultDisplay != null) ? ((Component)recipeResultDisplay).GetComponent