Decompiled source of Artisan v1.0.2
Artisan.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using Artisan.Features.Inventory; using Artisan.Localization; using Artisan.Shared.Reflection; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FMODUnity; using HarmonyLib; using Mirror; using Mirror.RemoteCalls; using TMPro; using UnityEngine; using UnityEngine.UI; using YAPYAP; using YAPYAP.Npc.Shopkeeper; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Artisan")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Artisan")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("2295655e-9260-4eae-a7c1-b44cabf62fea")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace Artisan { [BepInPlugin("gamedroit.artisan", "Artisan", "1.0.2")] public sealed class ArtisanMod : BaseUnityPlugin { private Harmony harmony; public static ConfigEntry<bool> EnableTeleBlastDamagePatch; public static ConfigEntry<bool> MakeTeleBlastDamageOtherPlayers; public static ConfigEntry<int> TeleBlastSpellDamage; public static ConfigEntry<bool> MakeAeroDamageOtherPlayers; public static ConfigEntry<bool> EnableAeroDamagePatch; public static ConfigEntry<int> AeroSpellDamage; public static ConfigEntry<bool> EnableExtendedInventorySlots; public static ConfigEntry<int> MaxInventorySlots; public static ConfigEntry<bool> EnableInventorySlotUpgrades; public static ConfigEntry<int> ExtraSlotBasePrice; public static ConfigEntry<float> ExtraSlotPriceMultiplier; public static ConfigEntry<bool> EnableShowMonstersHealthBar; public static ConfigEntry<bool> EnableShowMonsterDamageIndicator; public static ConfigEntry<float> MonsterHealthBarExtraHeightOffset; internal static ManualLogSource Logger { get; private set; } public void Awake() { //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; EnableAeroDamagePatch = ((BaseUnityPlugin)this).Config.Bind<bool>("Aero", "Enable Aero Damage Patch", true, "Enable or disable the damage patch for Aero spell."); MakeAeroDamageOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Aero", "Make Aero Damage Other Players", false, "Allow Aero spell to damage other players when the damage patch is enabled."); AeroSpellDamage = ((BaseUnityPlugin)this).Config.Bind<int>("Aero", "Aero Spell Damage", 2, "Amount of damage the Aero spell will deal when the damage patch is enabled."); EnableTeleBlastDamagePatch = ((BaseUnityPlugin)this).Config.Bind<bool>("TeleBlast", "Enable TeleBlast Damage Patch", true, "Enable or disable the damage patch for TeleBlast spell."); MakeTeleBlastDamageOtherPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("TeleBlast", "Make TeleBlast Damage Other Players", false, "Allow TeleBlast spell to damage other players when the damage patch is enabled."); TeleBlastSpellDamage = ((BaseUnityPlugin)this).Config.Bind<int>("TeleBlast", "TeleBlast Spell Damage", 5, "Amount of damage the TeleBlast spell will deal when the damage patch is enabled."); EnableExtendedInventorySlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "Enable Extended Inventory Slots", true, "Enable or disable increasing the inventory from 3 to 6 slots."); MaxInventorySlots = ((BaseUnityPlugin)this).Config.Bind<int>("Inventory", "Max Inventory Slots", 6, "Maximum inventory slots. Vanilla is 3. Recommended value is 6."); EnableInventorySlotUpgrades = ((BaseUnityPlugin)this).Config.Bind<bool>("Inventory", "Enable Inventory Slot Upgrades", true, "Enable or disable the ability to upgrade inventory slots. When disabled, all extra slots will be available from the start without needing to purchase them."); ExtraSlotBasePrice = ((BaseUnityPlugin)this).Config.Bind<int>("Inventory", "Extra Slot Base Price", 40, "Base price for the first extra inventory slot. Each subsequent slot will cost more based on the multiplier."); ExtraSlotPriceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Inventory", "Extra Slot Price Multiplier", 1.5f, "Price multiplier for each additional inventory slot. For example, with a base price of 40 and a multiplier of 1.5, the first extra slot would cost 40, the second would cost 60 (40 * 1.5), the third would cost 90 (60 * 1.5), and so on."); EnableShowMonstersHealthBar = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Enable Show Monsters Health Bar", true, "Enable or disable showing monsters' health bars."); EnableShowMonsterDamageIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "Enable Show Monster Damage Indicator", true, "Enable or disable showing damage indicators on monsters."); MonsterHealthBarExtraHeightOffset = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Monster Health Bar Extra Height Offset", 0.45f, "Additional height offset for monster health bars to prevent overlap with the monster's model."); if (EnableInventorySlotUpgrades.Value) { ArtisanText.Add((SystemLanguage)10, "inventory_upgrade_full", "Backpack fully upgraded"); ArtisanText.Add((SystemLanguage)10, "inventory_upgrade_buy", "(Hold) Upgrade backpack ({0} Gold)"); ArtisanText.Add((SystemLanguage)28, "inventory_upgrade_full", "Mochila totalmente melhorada"); ArtisanText.Add((SystemLanguage)28, "inventory_upgrade_buy", "(Segurar) Melhorar mochila ({0} Ouros)"); } harmony = new Harmony("gamedroit.artisan"); ArtisanInventoryUpgradeNetwork.Register(); try { harmony.PatchAll(Assembly.GetExecutingAssembly()); foreach (MethodBase patchedMethod in harmony.GetPatchedMethods()) { Logger.LogInfo((object)("Patched: " + patchedMethod.DeclaringType?.FullName + "." + patchedMethod.Name)); } } catch (Exception arg) { Logger.LogError((object)$"Harmony patch failed: {arg}"); } Logger.LogInfo((object)"Artisan mod is loaded and initialized."); } public void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } } namespace Artisan.Shared.Reflection { public static class HarmonyUtil { public static void CopyMatchingFieldsIncludingBaseTypes(object source, object target) { if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } Type type = source.GetType(); while (type != null && type != typeof(MonoBehaviour)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly) { FieldInfo fieldInfo2 = FindFieldInHierarchy(target.GetType(), fieldInfo.Name); if (!(fieldInfo2 == null) && !fieldInfo2.IsStatic && !fieldInfo2.IsInitOnly && !(fieldInfo2.FieldType != fieldInfo.FieldType)) { fieldInfo2.SetValue(target, fieldInfo.GetValue(source)); } } } type = type.BaseType; } } private static FieldInfo FindFieldInHierarchy(Type type, string fieldName) { while (type != null && type != typeof(MonoBehaviour)) { FieldInfo field = type.GetField(fieldName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } return null; } public static void CopySpellConfiguration(Spell source, Spell target) { HashSet<string> hashSet = new HashSet<string> { "spellData", "casterPawn", "NetworkcasterIdentity", "currentCharges", "isCasting", "isInitialized", "lastCastTime", "regenerationStartTime", "netIdentity", "syncObjects", "syncVarDirtyBits", "connectionToClient", "connectionToServer" }; Type type = ((object)source).GetType(); while (type != null && type != typeof(MonoBehaviour)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !hashSet.Contains(fieldInfo.Name)) { FieldInfo fieldInfo2 = AccessTools.Field(((object)target).GetType(), fieldInfo.Name); if (!(fieldInfo2 == null) && !(fieldInfo2.FieldType != fieldInfo.FieldType)) { fieldInfo2.SetValue(target, fieldInfo.GetValue(source)); } } } type = type.BaseType; } } public static void CopyMatchingFields(object source, object target) { if (source == null) { throw new ArgumentNullException("source"); } if (target == null) { throw new ArgumentNullException("target"); } Type type = source.GetType(); Type type2 = target.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic) { FieldInfo fieldInfo2 = AccessTools.Field(type2, fieldInfo.Name); if (!(fieldInfo2 == null) && !fieldInfo2.IsStatic && !fieldInfo2.IsInitOnly && !(fieldInfo2.FieldType != fieldInfo.FieldType)) { object value = fieldInfo.GetValue(source); fieldInfo2.SetValue(target, value); ArtisanMod.Logger.LogInfo((object)("Copied field '" + fieldInfo.Name + "' from '" + type.Name + "' to '" + type2.Name + "'.")); } } } } public static void CopySerializedSpellFields(Spell source, Spell target) { Type type = ((object)source).GetType(); while (type != null && type != typeof(Spell)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && !(AccessTools.Field(((object)target).GetType(), fieldInfo.Name) == null)) { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } } type = type.BaseType; } } public static void CopySerializedFields<T>(T source, T target) where T : ScriptableObject { if ((Object)(object)source == (Object)null) { throw new ArgumentNullException("source"); } if ((Object)(object)target == (Object)null) { throw new ArgumentNullException("target"); } Type type = typeof(T); while (type != null && type != typeof(ScriptableObject)) { FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && !fieldInfo.IsNotSerialized) { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } } type = type.BaseType; } } public static T GetFieldValue<T>(object instance, string fieldName) { if (instance == null) { return default(T); } FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (fieldInfo == null && instance.GetType().BaseType != null) { fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName); } if (fieldInfo == null) { ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'.")); return default(T); } object value = fieldInfo.GetValue(instance); if (value is T) { return (T)value; } return default(T); } public static void SetFieldValue<T>(object instance, string fieldName, T value) { if (instance != null) { FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); if (fieldInfo == null && instance.GetType().BaseType != null) { fieldInfo = AccessTools.Field(instance.GetType().BaseType, fieldName); } if (fieldInfo == null) { ArtisanMod.Logger.LogWarning((object)("Field '" + fieldName + "' was not found on '" + instance.GetType().FullName + "'.")); } else { fieldInfo.SetValue(instance, value); } } } } } namespace Artisan.Localization { public static class ArtisanLocalization { internal static IList VoskTranslators; internal static object DefaultVoskTranslator; internal static VoskLocalisation[] VoskLocalisations; internal static bool IsVoskLoaded = false; internal static Dictionary<SystemLanguage, object> QueuedTranslations = new Dictionary<SystemLanguage, object>(); internal static void ProcessQueuedTranslations() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (!IsVoskLoaded) { return; } foreach (KeyValuePair<SystemLanguage, object> queuedTranslation in QueuedTranslations) { if (queuedTranslation.Value is ArtisanVoiceCommand[] voiceCommands) { AddVoiceCommand(queuedTranslation.Key, voiceCommands); } } QueuedTranslations.Clear(); } public static void AddVoiceCommand(SystemLanguage language, ArtisanVoiceCommand[] voiceCommands) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if (!IsVoskLoaded) { ArtisanMod.Logger.LogWarning((object)$"Vosk is not loaded yet. Queuing {voiceCommands.Length} voice commands for language {language} to be added later."); QueuedTranslations[language] = voiceCommands; return; } int voskTranslatorIndex = GetVoskTranslatorIndex(language); object obj = ((voskTranslatorIndex == -1) ? DefaultVoskTranslator : VoskTranslators[voskTranslatorIndex]); if (obj == null) { ArtisanMod.Logger.LogError((object)$"Failed to find a Vosk translator for language {language}."); return; } Dictionary<string, string[]> fieldValue = HarmonyUtil.GetFieldValue<Dictionary<string, string[]>>(obj, "_commands"); string[] fieldValue2 = HarmonyUtil.GetFieldValue<string[]>(obj, "_grammar"); if (fieldValue == null || fieldValue2 == null) { ArtisanMod.Logger.LogError((object)$"Failed to access the commands or grammar of the Vosk translator for language {language}."); return; } HashSet<string> hashSet = new HashSet<string>(fieldValue2); foreach (ArtisanVoiceCommand artisanVoiceCommand in voiceCommands) { if (fieldValue.ContainsKey(artisanVoiceCommand.Key)) { if (!artisanVoiceCommand.OverwriteExisting) { ArtisanMod.Logger.LogWarning((object)$"Command for key '{artisanVoiceCommand.Key}' already exists in language {language}. Use overwrite=true to replace it."); continue; } ArtisanMod.Logger.LogWarning((object)$"Overwriting existing command for key '{artisanVoiceCommand.Key}' in language {language}."); } string[] array = ToCommandWords(artisanVoiceCommand.Command); if (array.Length == 0) { ArtisanMod.Logger.LogWarning((object)$"Command '{artisanVoiceCommand.Command}' for key '{artisanVoiceCommand.Key}' in language {language} does not contain any valid words."); continue; } fieldValue[artisanVoiceCommand.Key] = array; string[] array2 = array; foreach (string item in array2) { if (!hashSet.Contains(item)) { hashSet.Add(item); } } } HarmonyUtil.SetFieldValue(obj, "_grammar", hashSet.ToArray()); ArtisanMod.Logger.LogInfo((object)$"Added {voiceCommands.Length} voice commands to language {language}. Total grammar size is now {hashSet.Count}."); } private static string[] ToCommandWords(string value) { if (string.IsNullOrEmpty(value)) { return new string[0]; } return (from word in value.Split(new char[2] { '-', ' ' }, StringSplitOptions.RemoveEmptyEntries) select word.Trim() into word where !string.IsNullOrEmpty(word) select word.ToUpperInvariant()).ToArray(); } private static int GetVoskTranslatorIndex(SystemLanguage language) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) string systemCulture = CultureInfo.CurrentCulture.Name; int num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language && l.CultureCode == systemCulture && !l.IsOptional); if (num == -1) { num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language && !l.IsOptional); } if (num == -1) { num = VoskLocalisations.ToList().FindIndex((VoskLocalisation l) => l.Language == language); } return num; } } [HarmonyPatch(typeof(VoiceManager), "LoadLocalisationData")] public static class VoiceLocalizationPatches { [HarmonyPostfix] private static void Postfix(VoiceManager __instance) { IList fieldValue = HarmonyUtil.GetFieldValue<IList>(__instance, "_voskTranslators"); object fieldValue2 = HarmonyUtil.GetFieldValue<object>(__instance, "_defaultTranslator"); VoskLocalisation[] fieldValue3 = HarmonyUtil.GetFieldValue<VoskLocalisation[]>(__instance, "_voskLocalisations"); ArtisanLocalization.VoskTranslators = fieldValue; ArtisanLocalization.VoskLocalisations = fieldValue3; ArtisanLocalization.DefaultVoskTranslator = fieldValue2; ArtisanMod.Logger.LogInfo((object)$"Loaded {fieldValue.Count} Vosk translators and {fieldValue3.Length} Vosk localisations"); ArtisanLocalization.IsVoskLoaded = true; ArtisanLocalization.ProcessQueuedTranslations(); } } public static class ArtisanText { private static readonly Dictionary<SystemLanguage, Dictionary<string, string>> Translations = new Dictionary<SystemLanguage, Dictionary<string, string>>(); public static void Add(SystemLanguage language, string key, string value) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!Translations.TryGetValue(language, out var value2)) { value2 = new Dictionary<string, string>(); Translations[language] = value2; } value2[key] = value; } public static string Translate(string key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) SystemLanguage key2 = (SystemLanguage)10; LocalisationManager val = default(LocalisationManager); if (Service.Get<LocalisationManager>(ref val) && val.CurrentTranslator != null) { key2 = val.CurrentTranslator.Language; } if (Translations.TryGetValue(key2, out var value) && value.TryGetValue(key, out var value2)) { return value2; } if (Translations.TryGetValue((SystemLanguage)10, out var value3) && value3.TryGetValue(key, out var value4)) { return value4; } return key; } public static string Format(string key, params object[] args) { return string.Format(Translate(key), args); } } public sealed class ArtisanVoiceCommand { public string Key { get; private set; } public string Command { get; private set; } public bool OverwriteExisting { get; private set; } public ArtisanVoiceCommand(string key, string command, bool overwriteExisting = false) { Key = key; Command = command; OverwriteExisting = overwriteExisting; } } } namespace Artisan.Features.Spells { [HarmonyPatch(typeof(ProjectilePush), "OnTargetHit")] public class ProjectilePushDamagePatch { private static readonly Dictionary<int, HashSet<uint>> DamagedTargetsByProjectile = new Dictionary<int, HashSet<uint>>(); public static void Prefix(ProjectilePush __instance, Collider target, Rigidbody targetRigidbody, NetworkIdentity targetIdentity) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || (Object)(object)__instance == (Object)null || (Object)(object)target == (Object)null || (Object)(object)targetRigidbody == (Object)null || (Object)(object)targetIdentity == (Object)null) { return; } bool flag = IsAeroProjectile(__instance); bool flag2 = IsLevitationBlastProjectile(__instance); if ((!flag && !flag2) || (flag && !ArtisanMod.EnableAeroDamagePatch.Value) || (flag2 && !ArtisanMod.EnableTeleBlastDamagePatch.Value)) { return; } int num = (flag ? ArtisanMod.AeroSpellDamage.Value : (flag2 ? ArtisanMod.TeleBlastSpellDamage.Value : 0)); bool flag3 = (flag ? ArtisanMod.MakeAeroDamageOtherPlayers.Value : (flag2 && ArtisanMod.MakeTeleBlastDamageOtherPlayers.Value)); LayerMask fieldValue = HarmonyUtil.GetFieldValue<LayerMask>(__instance, "pushableLayer"); if (((1 << ((Component)target).gameObject.layer) & ((LayerMask)(ref fieldValue)).value) == 0) { return; } HashSet<Rigidbody> fieldValue2 = HarmonyUtil.GetFieldValue<HashSet<Rigidbody>>(__instance, "affectedRigidbodies"); if ((fieldValue2 != null && fieldValue2.Contains(targetRigidbody)) || !((NetworkBehaviour)__instance).isServer) { return; } NetworkIdentity fieldValue3 = HarmonyUtil.GetFieldValue<NetworkIdentity>(__instance, "Caster"); Vector3 forward = ((Component)__instance).transform.forward; if (TryMarkTargetDamaged(__instance, targetIdentity)) { NpcBehaviour val = default(NpcBehaviour); if (((Component)targetIdentity).TryGetComponent<NpcBehaviour>(ref val)) { val.OnHit(num, forward, false, fieldValue3); } Pawn val2 = default(Pawn); if (flag3 && ((Component)targetIdentity).TryGetComponent<Pawn>(ref val2) && (Object)(object)val2.Hurtbox != (Object)null) { uint num2 = (((Object)(object)fieldValue3 != (Object)null) ? fieldValue3.netId : 0u); val2.Hurtbox.OnHit(num, 0f, forward, (StatusSO)null, false, false, false, num2); } } } public static void ClearProjectile(ProjectilePush projectile) { if (!((Object)(object)projectile == (Object)null)) { DamagedTargetsByProjectile.Remove(((Object)projectile).GetInstanceID()); } } private static bool TryMarkTargetDamaged(ProjectilePush projectile, NetworkIdentity targetIdentity) { if ((Object)(object)projectile == (Object)null || (Object)(object)targetIdentity == (Object)null) { return false; } int instanceID = ((Object)projectile).GetInstanceID(); uint netId = targetIdentity.netId; if (!DamagedTargetsByProjectile.TryGetValue(instanceID, out var value)) { value = new HashSet<uint>(); DamagedTargetsByProjectile[instanceID] = value; } if (value.Contains(netId)) { return false; } value.Add(netId); return true; } private static bool IsAeroProjectile(ProjectilePush projectile) { Spell fieldValue = HarmonyUtil.GetFieldValue<Spell>(projectile, "OwnerSpell"); if ((Object)(object)fieldValue == (Object)null) { return false; } return ((object)fieldValue).GetType() == typeof(PushSpell); } private static bool IsLevitationBlastProjectile(ProjectilePush projectile) { Spell fieldValue = HarmonyUtil.GetFieldValue<Spell>(projectile, "OwnerSpell"); if ((Object)(object)fieldValue == (Object)null) { return false; } return ((object)fieldValue).GetType() == typeof(LevitationBlastSpell); } } [HarmonyPatch(typeof(ProjectilePush), "OnDestroy")] public class ProjectilePushDamageCleanupPatch { public static void Prefix(ProjectilePush __instance) { if (!((Object)(object)__instance == (Object)null)) { ProjectilePushDamagePatch.ClearProjectile(__instance); } } } } namespace Artisan.Features.Monsters { [HarmonyPatch] public static class NpcHurtboxClientHitFxPatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return AccessTools.Method(typeof(NpcHurtbox), "UserCode_RpcOnHit__Int32__Vector3", (Type[])null, (Type[])null); } [HarmonyPostfix] private static void Postfix(NpcHurtbox __instance, int damage, Vector3 forceDir) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (!ArtisanMod.EnableShowMonstersHealthBar.Value && !ArtisanMod.EnableShowMonsterDamageIndicator.Value)) { return; } try { if (ArtisanMod.EnableShowMonstersHealthBar.Value) { ArtisanEnemyHealthBar artisanEnemyHealthBar = ((Component)__instance).GetComponent<ArtisanEnemyHealthBar>(); if ((Object)(object)artisanEnemyHealthBar == (Object)null) { artisanEnemyHealthBar = ((Component)__instance).gameObject.AddComponent<ArtisanEnemyHealthBar>(); } artisanEnemyHealthBar.EnsureInitialized(); artisanEnemyHealthBar.ResetTimer(); artisanEnemyHealthBar.UpdateHealthDisplay(); } if (ArtisanMod.EnableShowMonsterDamageIndicator.Value) { ArtisanDamageTextFactory.Create(GetDamageIndicatorPosition(__instance), Mathf.Clamp(damage, 1, 9999)); } } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[MonsterHealthBar] Failed to render hit UI: " + ex)); } } private static Vector3 GetDamageIndicatorPosition(NpcHurtbox __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_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) Vector3 position = ((Component)__instance).transform.position; NpcBehaviour val = default(NpcBehaviour); if (((Component)__instance).TryGetComponent<NpcBehaviour>(ref val)) { if ((Object)(object)val.Rigidbody != (Object)null) { position = ((Component)val.Rigidbody).transform.position; } else if ((Object)(object)val.CameraTargetTransform != (Object)null) { position = val.CameraTargetTransform.position; } } return position + new Vector3(Random.Range(-0.5f, 0.5f), Random.Range(1f, 1.5f), Random.Range(-0.5f, 0.5f)); } } public class ArtisanDamageText3D : MonoBehaviour { private TextMeshPro textComponent; private float timer = 1.5f; private Vector3 baseWorldPosition; private float floatHeight; private void Awake() { textComponent = ((Component)this).GetComponent<TextMeshPro>(); } private void Start() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) baseWorldPosition = ((Component)this).transform.position; if (!((Object)(object)Camera.main == (Object)null)) { ((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position); } } private void Update() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) floatHeight += Time.deltaTime * 0.8f; ((Component)this).transform.position = baseWorldPosition + Vector3.up * floatHeight; if ((Object)(object)Camera.main != (Object)null) { ((Component)this).transform.rotation = Quaternion.LookRotation(((Component)this).transform.position - ((Component)Camera.main).transform.position); } timer -= Time.deltaTime; if (timer > 0f && timer < 0.75f) { float num = Mathf.Lerp(1f, 0.5f, (0.75f - timer) / 0.75f); ((Component)this).transform.localScale = Vector3.one * num; } if ((Object)(object)textComponent != (Object)null) { ((Graphic)textComponent).color = new Color(((Graphic)textComponent).color.r, ((Graphic)textComponent).color.g, ((Graphic)textComponent).color.b, Mathf.Clamp01(timer * 2f)); } if (timer <= 0f) { Object.Destroy((Object)(object)((Component)this).gameObject); } } public void Setup(float time) { timer = time; } } public static class ArtisanDamageTextFactory { public static void Create(Vector3 position, int damage) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("DamageText", new Type[2] { typeof(TextMeshPro), typeof(ArtisanDamageText3D) }); TextMeshPro component = val.GetComponent<TextMeshPro>(); ArtisanDamageText3D component2 = val.GetComponent<ArtisanDamageText3D>(); ((TMP_Text)component).alignment = (TextAlignmentOptions)514; ((TMP_Text)component).text = $"-{damage}"; Color color = default(Color); float fontSize; float time; if (damage >= 50) { color = Color.red; fontSize = 6f; time = 3f; } else if (damage >= 25) { color = Color.yellow; fontSize = 5f; time = 2f; } else { ((Color)(ref color))..ctor(1f, 0.5f, 0f); fontSize = 4f; time = 1.5f; } ((Graphic)component).color = color; ((TMP_Text)component).fontSize = fontSize; val.transform.position = position; component2.Setup(time); } } public sealed class ArtisanEnemyHealthBar : MonoBehaviour { private sealed class Billboard : MonoBehaviour { private Camera mainCamera; private void LateUpdate() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mainCamera == (Object)null) { mainCamera = Camera.main; } if (!((Object)(object)mainCamera == (Object)null)) { ((Component)this).transform.rotation = Quaternion.Euler(((Component)mainCamera).transform.eulerAngles.x, ((Component)mainCamera).transform.eulerAngles.y, 0f); } } } private static Sprite sharedWhiteSprite; private readonly Vector2 size = new Vector2(20f, 2.5f); private readonly Color backgroundColor = new Color(0.3f, 0.3f, 0.3f, 0.9f); private readonly Color healthColor = Color.red; private float lastDamageTime; private bool isActive = true; private bool initialized; private Vector3 worldOffset = new Vector3(0f, 1.25f, 0f); private Canvas canvas; private Image foreground; private Image background; private TextMeshProUGUI healthText; private NpcHurtbox npcHurtbox; private NpcBehaviour npcBehaviour; private Transform followTransform; private Camera mainCamera; private float targetFillAmount = 1f; private int lastHealthCurrent = int.MinValue; private int lastHealthMax = int.MinValue; private float nextVisibilityUpdateTime; private float nextFollowResolveTime; private float nextOffsetResolveTime; public void EnsureInitialized() { if (!initialized) { npcHurtbox = ((Component)this).GetComponent<NpcHurtbox>(); if (!((Object)(object)npcHurtbox == (Object)null)) { npcBehaviour = ((Component)this).GetComponent<NpcBehaviour>(); followTransform = ResolveFollowTransform(); mainCamera = Camera.main; InitializeCanvas(); UpdateWorldOffsetFromBounds(force: true); UpdateCanvasWorldPosition(); UpdateHealthDisplay(); ResetTimer(); initialized = true; } } } public void ResetTimer() { lastDamageTime = Time.time; if (!isActive && (Object)(object)canvas != (Object)null) { ReactivateHealthBar(); } } public void UpdateHealthDisplay() { if (!((Object)(object)npcHurtbox == (Object)null)) { int num = Mathf.Max(0, npcHurtbox.MaxHealth); int num2 = Mathf.Clamp(npcHurtbox.Health, 0, num); if (num > 0) { targetFillAmount = Mathf.Clamp01((float)num2 / (float)num); } else { targetFillAmount = 0f; } UpdateHealthText(); } } private void InitializeCanvas() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ArtisanEnemyHealthCanvas"); canvas = val.AddComponent<Canvas>(); canvas.renderMode = (RenderMode)2; ((Component)canvas).transform.SetParent(((Object)(object)followTransform != (Object)null) ? followTransform : ((Component)this).transform, false); ((Component)canvas).transform.localPosition = worldOffset; RectTransform component = ((Component)canvas).GetComponent<RectTransform>(); component.sizeDelta = size; ((Transform)component).localScale = new Vector3(0.03f, 0.03f, 0.03f); background = CreateBarElement(((Component)canvas).transform, backgroundColor, "Background"); foreground = CreateBarElement(((Component)canvas).transform, healthColor, "Foreground"); foreground.type = (Type)3; foreground.fillMethod = (FillMethod)0; foreground.fillOrigin = 0; foreground.fillAmount = targetFillAmount; val.AddComponent<Billboard>(); CreateHealthText(((Component)canvas).transform); } private Transform ResolveFollowTransform() { if ((Object)(object)npcBehaviour != (Object)null) { if ((Object)(object)npcBehaviour.Rigidbody != (Object)null) { return ((Component)npcBehaviour.Rigidbody).transform; } if ((Object)(object)npcBehaviour.CameraTargetTransform != (Object)null) { return npcBehaviour.CameraTargetTransform; } } return ((Component)this).transform; } private Transform ResolveBoundsRoot() { if (!((Object)(object)npcBehaviour != (Object)null)) { return ((Component)this).transform; } return ((Component)npcBehaviour).transform; } private void Update() { EnsureInitialized(); if (!initialized || !isActive) { return; } if (Time.time - lastDamageTime > 10f) { HideHealthBar(); } else if (!((Object)(object)npcHurtbox == (Object)null) && !((Object)(object)foreground == (Object)null) && !((Object)(object)background == (Object)null)) { RefreshFollowTransform(); UpdateWorldOffsetFromBounds(force: false); UpdateCanvasWorldPosition(); UpdateHealthValues(); UpdateForegroundAnimation(); if (Time.time >= nextVisibilityUpdateTime) { UpdateCanvasVisibility(); nextVisibilityUpdateTime = Time.time + 0.1f; } } } private void RefreshFollowTransform() { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (Time.time < nextFollowResolveTime) { return; } Transform val = ResolveFollowTransform(); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)followTransform) { followTransform = val; if ((Object)(object)canvas != (Object)null) { ((Component)canvas).transform.SetParent(followTransform, false); ((Component)canvas).transform.localPosition = worldOffset; } UpdateWorldOffsetFromBounds(force: true); } nextFollowResolveTime = Time.time + 0.5f; } private void UpdateHealthValues() { int health = npcHurtbox.Health; int maxHealth = npcHurtbox.MaxHealth; if (maxHealth > 0 && (health != lastHealthCurrent || maxHealth != lastHealthMax)) { lastHealthCurrent = health; lastHealthMax = maxHealth; targetFillAmount = Mathf.Clamp01((float)health / (float)maxHealth); UpdateHealthText(); } } private void UpdateForegroundAnimation() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) foreground.fillAmount = Mathf.Lerp(foreground.fillAmount, targetFillAmount, Time.deltaTime * 10f); Color color = ((Graphic)foreground).color; if (targetFillAmount < 0.3f) { float num = Mathf.PingPong(Time.time * 2f, 1f); ((Graphic)foreground).color = new Color(1f, num, num, color.a); } else { ((Graphic)foreground).color = new Color(healthColor.r, healthColor.g, healthColor.b, color.a); } } private void UpdateWorldOffsetFromBounds(bool force) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!force && Time.time < nextOffsetResolveTime) { return; } nextOffsetResolveTime = Time.time + 1f; Transform val = ResolveBoundsRoot(); if (!((Object)(object)val == (Object)null) && !((Object)(object)followTransform == (Object)null) && TryGetWorldBounds(val, out var bounds)) { float y = followTransform.position.y; float num = Mathf.Clamp(((Bounds)(ref bounds)).max.y - y + 0.15f, 0.35f, 12f); float num2 = ((ArtisanMod.MonsterHealthBarExtraHeightOffset != null) ? ArtisanMod.MonsterHealthBarExtraHeightOffset.Value : 0.55f); float num3 = Mathf.Clamp(num + num2, 0.35f, 20f); if (!(Mathf.Abs(worldOffset.y - num3) <= 0.01f)) { worldOffset = new Vector3(worldOffset.x, num3, worldOffset.z); UpdateCanvasWorldPosition(); } } } private void UpdateCanvasWorldPosition() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)canvas == (Object)null) && !((Object)(object)followTransform == (Object)null)) { ((Component)canvas).transform.position = followTransform.position + new Vector3(worldOffset.x, 0f, worldOffset.z) + Vector3.up * worldOffset.y; } } private static bool TryGetWorldBounds(Transform root, out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); bool flag = false; Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } if (flag) { return true; } Renderer[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } return flag; } private void CreateHealthText(Transform parent) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("HealthText"); val.transform.SetParent(parent, false); healthText = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)healthText).alignment = (TextAlignmentOptions)514; ((TMP_Text)healthText).fontSize = 10f; ((Graphic)healthText).color = Color.white; ((TMP_Text)healthText).margin = new Vector4(0f, 0f, 0f, 10f); RectTransform component = ((Component)healthText).GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = new Vector2(0f, 5f); component.sizeDelta = new Vector2(100f, 20f); } private void UpdateHealthText() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)healthText == (Object)null) && !((Object)(object)npcHurtbox == (Object)null)) { int num = Mathf.Max(0, npcHurtbox.MaxHealth); int num2 = Mathf.Clamp(npcHurtbox.Health, 0, num); ((TMP_Text)healthText).text = num2 + "/" + num; if (num > 0 && (float)num2 / (float)num < 0.3f) { ((Graphic)healthText).color = Color.yellow; } else { ((Graphic)healthText).color = Color.white; } } } private Image CreateBarElement(Transform parent, Color color, string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); Image val2 = val.AddComponent<Image>(); val2.sprite = GetSharedWhiteSprite(); ((Graphic)val2).color = color; RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.one; component.offsetMin = Vector2.zero; component.offsetMax = Vector2.zero; return val2; } private static Sprite GetSharedWhiteSprite() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sharedWhiteSprite != (Object)null) { return sharedWhiteSprite; } Texture2D whiteTexture = Texture2D.whiteTexture; sharedWhiteSprite = Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f)); return sharedWhiteSprite; } private void UpdateCanvasVisibility() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mainCamera == (Object)null) { mainCamera = Camera.main; } if (!((Object)(object)mainCamera == (Object)null) && !((Object)(object)foreground == (Object)null) && !((Object)(object)background == (Object)null)) { Vector3 val = (((Object)(object)canvas != (Object)null) ? ((Component)canvas).transform.position : ((Component)this).transform.position); float num = Vector3.Distance(((Component)mainCamera).transform.position, val); float num2 = Mathf.Clamp01(1f - num / 50f); ((Graphic)foreground).color = new Color(((Graphic)foreground).color.r, ((Graphic)foreground).color.g, ((Graphic)foreground).color.b, num2); ((Graphic)background).color = new Color(backgroundColor.r, backgroundColor.g, backgroundColor.b, num2 * 0.8f); if ((Object)(object)healthText != (Object)null) { ((TMP_Text)healthText).alpha = num2; } } } private void ReactivateHealthBar() { isActive = true; if ((Object)(object)canvas != (Object)null) { ((Component)canvas).gameObject.SetActive(true); } UpdateHealthDisplay(); UpdateCanvasVisibility(); } private void HideHealthBar() { isActive = false; if ((Object)(object)canvas != (Object)null) { ((Component)canvas).gameObject.SetActive(false); } } private void OnDestroy() { if ((Object)(object)canvas != (Object)null) { Object.Destroy((Object)(object)((Component)canvas).gameObject); } canvas = null; } } } namespace Artisan.Features.Inventory { public static class ArtisanInventoryUpgradeEffects { private const string ShopkeeperPurchaseRpcName = "RpcOnPurchaseMade"; private const string ChestName = "Artisan_InventoryUpgradeChest"; public static void PlayPurchaseSuccess(PawnInventory inventory) { if (!((Object)(object)inventory == (Object)null)) { PlayShopkeeperPurchaseReaction(); } } public static void PlayLocalPurchaseSfx() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) EventReference val = FindShopPurchaseSfx(); AudioManager val2 = default(AudioManager); if (!((EventReference)(ref val)).IsNull && Service.Get<AudioManager>(ref val2)) { Vector3 val3 = FindPurchaseSfxPosition(); val2.PlayEvent(val, val3, 1f, true, (Transform)null, true); } } private static void PlayShopkeeperPurchaseReaction() { ShopkeeperStateMachine val = Object.FindFirstObjectByType<ShopkeeperStateMachine>(); if (!((Object)(object)val == (Object)null)) { MethodInfo methodInfo = AccessTools.Method(typeof(ShopkeeperStateMachine), "RpcOnPurchaseMade", (Type[])null, (Type[])null); if (methodInfo == null) { ArtisanMod.Logger.LogWarning((object)"Could not find ShopkeeperStateMachine.RpcOnPurchaseMade."); } else { methodInfo.Invoke(val, new object[1]); } } } private static EventReference FindShopPurchaseSfx() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) Shop val = Object.FindFirstObjectByType<Shop>(); if ((Object)(object)val == (Object)null) { return default(EventReference); } return HarmonyUtil.GetFieldValue<EventReference>(val, "purchaseSfx"); } private static Vector3 FindPurchaseSfxPosition() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("Artisan_InventoryUpgradeChest"); if ((Object)(object)val != (Object)null) { return val.transform.position; } Shop val2 = Object.FindFirstObjectByType<Shop>(); if ((Object)(object)val2 != (Object)null) { return ((Component)val2).transform.position; } return Vector3.zero; } } public static class ArtisanInventoryUpgradeNetwork { private const string CommandSignature = "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()"; private const string TargetRpcSignature = "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()"; private static readonly int CommandHash = Extensions.GetStableHashCode("System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()"); private static readonly int TargetRpcHash = Extensions.GetStableHashCode("System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()"); private static bool registered; public static void Register() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown if (!registered) { RemoteProcedureCalls.RegisterCommand(typeof(PawnInventory), "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()", new RemoteCallDelegate(InvokeCmdPurchaseInventoryUpgrade), false); RemoteProcedureCalls.RegisterRpc(typeof(PawnInventory), "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()", new RemoteCallDelegate(InvokeTargetRpcInventoryUpgradePurchased)); registered = true; ArtisanMod.Logger.LogInfo((object)"Registered Artisan inventory upgrade command."); } } public static void RequestPurchase(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return; } if (NetworkServer.active) { if (ArtisanInventoryUpgradeService.TryPurchaseNextUpgrade(inventory)) { SendPurchaseSuccess(inventory, ((NetworkBehaviour)inventory).connectionToClient); } return; } NetworkWriterPooled val = NetworkWriterPool.Get(); try { AccessTools.Method(typeof(NetworkBehaviour), "SendCommandInternal", (Type[])null, (Type[])null).Invoke(inventory, new object[5] { "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::CmdPurchaseInventoryUpgrade()", CommandHash, val, 0, true }); } finally { NetworkWriterPool.Return(val); } } private static void InvokeCmdPurchaseInventoryUpgrade(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection) { if (NetworkServer.active) { PawnInventory val = (PawnInventory)(object)((obj is PawnInventory) ? obj : null); if (!((Object)(object)val == (Object)null) && ArtisanInventoryUpgradeService.TryPurchaseNextUpgrade(val)) { SendPurchaseSuccess(val, senderConnection); } } } private static void SendPurchaseSuccess(PawnInventory inventory, NetworkConnectionToClient connection) { if ((Object)(object)inventory == (Object)null) { return; } ArtisanInventoryUpgradeEffects.PlayPurchaseSuccess(inventory); if (connection == null) { return; } NetworkWriterPooled val = NetworkWriterPool.Get(); try { AccessTools.Method(typeof(NetworkBehaviour), "SendTargetRPCInternal", (Type[])null, (Type[])null).Invoke(inventory, new object[5] { connection, "System.Void Artisan.Features.Inventory.ArtisanInventoryUpgradeNetwork::TargetRpcInventoryUpgradePurchased()", TargetRpcHash, val, 0 }); } finally { NetworkWriterPool.Return(val); } } private static void InvokeTargetRpcInventoryUpgradePurchased(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection) { ArtisanInventoryUpgradeEffects.PlayLocalPurchaseSfx(); ArtisanLockedSlotOverlayPatch.RefreshCurrentInventory(); } } [HarmonyPatch] public static class ArtisanInventoryLockedSlotPatch { private static bool HasAvailablePickupSpace(PawnInventory inventory) { if ((Object)(object)inventory == (Object)null) { return false; } if (ArtisanInventoryUpgradeService.GetFirstUnlockedEmptySlot(inventory) >= 0) { return true; } PawnPropInteractions component = ((Component)inventory).GetComponent<PawnPropInteractions>(); if ((Object)(object)component != (Object)null) { return (Object)(object)component.NetworkCurrentLeftHandNetworkProp == (Object)null; } return false; } [HarmonyPatch(typeof(PawnInventory), "SelectSlotWithMainHand")] [HarmonyPrefix] private static bool SelectSlotWithMainHandPrefix(PawnInventory __instance, int slotIndex) { return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSelectSlotWithMainHand__Int32")] [HarmonyPrefix] private static bool CmdSelectSlotPrefix(PawnInventory __instance, int slotIndex) { return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdSwapSlotWithRightHand__Int32")] [HarmonyPrefix] private static bool CmdSwapSlotPrefix(PawnInventory __instance, int slotIndex) { return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdMoveItemInInventory__UInt32__Int32")] [HarmonyPrefix] private static bool CmdMoveItemPrefix(PawnInventory __instance, uint sourcePropNetId, int targetSlotIndex) { return ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, targetSlotIndex); } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdCycleSlot__Boolean")] [HarmonyPrefix] private static bool CmdCycleSlotPrefix(PawnInventory __instance, bool cycleForward) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return true; } int unlockedSlotCount = ArtisanInventoryUpgradeService.GetUnlockedSlotCount(__instance); if (unlockedSlotCount <= 0) { return false; } int num = __instance.CurrentMainHandSlot; for (int i = 0; i < unlockedSlotCount; i++) { num = (cycleForward ? (num - 1) : (num + 1)); if (num < 0) { num = unlockedSlotCount - 1; } else if (num >= unlockedSlotCount) { num = 0; } if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, num)) { __instance.SelectSlotWithMainHand(num); return false; } } return false; } [HarmonyPatch(typeof(PawnInventory), "UserCode_CmdAttemptPickup__NetworkPuppetProp")] [HarmonyPrefix] private static bool CmdAttemptPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return true; } int currentMainHandSlot = __instance.CurrentMainHandSlot; if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, currentMainHandSlot)) { return true; } __instance.ServerTryPickup(prop, 0); return false; } [HarmonyPatch(typeof(UIInventory), "OnSlotDrop")] [HarmonyPrefix] private static bool OnSlotDropPrefix(UIInventory __instance, UIInventorySlot targetSlot) { PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory"); UIInventorySlot fieldValue2 = HarmonyUtil.GetFieldValue<UIInventorySlot>(__instance, "_draggedSlot"); if ((Object)(object)fieldValue == (Object)null || (Object)(object)targetSlot == (Object)null) { return true; } if (IsLockedInventorySlot(fieldValue, targetSlot) || IsLockedInventorySlot(fieldValue, fieldValue2)) { __instance.StopDrag(); return false; } return true; } [HarmonyPatch(typeof(PawnInventory), "ServerTryPickup")] [HarmonyPrefix] private static bool ServerTryPickupPrefix(PawnInventory __instance, NetworkPuppetProp prop, int preferredSlotIndex, ref bool __result) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return true; } if ((Object)(object)prop == (Object)null || !prop.CanPickedUpBy(((NetworkBehaviour)__instance).netIdentity)) { __result = false; return false; } if (preferredSlotIndex == -1) { preferredSlotIndex = __instance.CurrentMainHandSlot; } if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, preferredSlotIndex) && __instance.ServerTryPickupInventorySlotOnly(prop, preferredSlotIndex)) { __result = true; return false; } PawnPropInteractions fieldValue = HarmonyUtil.GetFieldValue<PawnPropInteractions>(__instance, "propInteractions"); if ((Object)(object)fieldValue != (Object)null && (Object)(object)fieldValue.NetworkCurrentLeftHandNetworkProp == (Object)null) { prop.ServerHandleHeld(fieldValue, false); __result = true; return false; } int firstUnlockedEmptySlot = ArtisanInventoryUpgradeService.GetFirstUnlockedEmptySlot(__instance); if (firstUnlockedEmptySlot < 0) { __result = false; return false; } __result = __instance.ServerTryPickupInventorySlotOnly(prop, firstUnlockedEmptySlot); return false; } [HarmonyPatch(typeof(PawnInventory), "ServerTryPickupInventorySlotOnly")] [HarmonyPrefix] private static bool ServerTryPickupInventorySlotOnlyPrefix(PawnInventory __instance, int slotIndex, ref bool __result) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return true; } if (ArtisanInventoryUpgradeService.IsSlotUnlocked(__instance, slotIndex)) { return true; } __result = false; return false; } [HarmonyPatch(typeof(NetworkPuppetProp), "CanInteract")] [HarmonyPostfix] private static void NetworkPuppetPropCanInteractPostfix(NetworkPuppetProp __instance, NetworkIdentity identity, ref bool __result) { if (__result && ArtisanInventoryUpgradeService.IsEnabled()) { PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>()); if (!((Object)(object)val == (Object)null) && !HasAvailablePickupSpace(val)) { __result = false; } } } [HarmonyPatch(typeof(NetworkPuppetProp), "ShowTooltip")] [HarmonyPrefix] private static bool NetworkPuppetPropShowTooltipPrefix(NetworkPuppetProp __instance, NetworkIdentity identity) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return true; } PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>()); if ((Object)(object)val == (Object)null) { return true; } if (HasAvailablePickupSpace(val)) { return true; } UIManager instance = UIManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.uiTooltip == (Object)null) { return false; } string text = __instance.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")"; instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, __instance.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, __instance.IsGrabable, false, (string)null, (InputTarget)9, true, false); return false; } [HarmonyPatch(typeof(PropIngredient), "CustomTooltipAction")] [HarmonyPostfix] private static void PropIngredientCustomTooltipActionPostfix(PropIngredient __instance, Interactable interactable, NetworkIdentity identity) { if (!ArtisanInventoryUpgradeService.IsEnabled()) { return; } PawnInventory val = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>()); if ((Object)(object)val == (Object)null || HasAvailablePickupSpace(val)) { return; } NetworkPuppetProp val2 = (NetworkPuppetProp)(object)((interactable is NetworkPuppetProp) ? interactable : null); if ((Object)(object)val2 == (Object)null) { val2 = ((Component)__instance).GetComponent<NetworkPuppetProp>(); } if (!((Object)(object)val2 == (Object)null)) { UIManager instance = UIManager.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.uiTooltip == (Object)null)) { string text = val2.DisplayName + " (" + instance.uiTooltip.InventoryFullStr + ")"; instance.uiTooltip.ShowTooltip(text, (InputTarget)2, false, false, (string)null, (InputTarget)8, val2.IsGrabable, false, val2.IsGrabable ? instance.uiTooltip.DefaultGrabStr : string.Empty, (InputTarget)8, val2.IsGrabable, false); } } } [HarmonyPatch(typeof(UIInventory), "OnDragHoverEnter")] [HarmonyPrefix] private static bool OnDragHoverEnterPrefix(UIInventory __instance, UIInventorySlot slot) { return !IsLockedInventorySlot(HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory"), slot); } [HarmonyPatch(typeof(UIInventorySlot), "OnBeginDrag")] [HarmonyPrefix] private static bool OnBeginDragPrefix(UIInventorySlot __instance) { return !IsLockedInventorySlot(HarmonyUtil.GetFieldValue<PawnInventory>(HarmonyUtil.GetFieldValue<UIInventory>(__instance, "_inventory"), "_playerInventory"), __instance); } private static bool IsLockedInventorySlot(PawnInventory inventory, UIInventorySlot slot) { if ((Object)(object)inventory == (Object)null || (Object)(object)slot == (Object)null || slot.IsHandSlot) { return false; } return !ArtisanInventoryUpgradeService.IsSlotUnlocked(inventory, slot.SlotIndex); } } [HarmonyPatch(typeof(Interactable), "Interact")] public static class ArtisanInventoryUpgradeStationInteractPatch { private static bool Prefix(Interactable __instance) { return !(__instance is ArtisanInventoryUpgradeStationInteractable); } } [HarmonyPatch(typeof(Shop), "OnStartClient")] public static class ArtisanInventoryUpgradeStationPatch { private const string PrefabName = "Chest_Small_interactive"; private const string ObjectName = "Artisan_InventoryUpgradeChest"; private static void Postfix(Shop __instance) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameObject.Find("Artisan_InventoryUpgradeChest") != (Object)null) && ArtisanInventoryUpgradeService.IsEnabled()) { GameObject val = FindPrefab("Chest_Small_interactive"); if ((Object)(object)val == (Object)null) { ArtisanMod.Logger.LogWarning((object)"Could not find prefab: Chest_Small_interactive"); return; } Vector3 val2 = ((Component)__instance).transform.position + ((Component)__instance).transform.right * -2f; val2.y += 0.25f; GameObject obj = Object.Instantiate<GameObject>(val, val2, Quaternion.Euler(0f, ((Component)__instance).transform.eulerAngles.y, 0f)); ((Object)obj).name = "Artisan_InventoryUpgradeChest"; obj.SetActive(true); StripGameplayComponents(obj); EnsureCollider(obj); ArtisanInventoryUpgradeStationInteractable artisanInventoryUpgradeStationInteractable = obj.AddComponent<ArtisanInventoryUpgradeStationInteractable>(); ((Interactable)artisanInventoryUpgradeStationInteractable).HoldInteractDuration = 1.25f; ((Interactable)artisanInventoryUpgradeStationInteractable).RefreshLocalInteractable(); ArtisanMod.Logger.LogInfo((object)"Spawned inventory upgrade chest in lobby."); } } private static GameObject FindPrefab(string prefabName) { GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && (((Object)val).name == prefabName || ((Object)val).name == prefabName + ".prefab")) { return val; } } return null; } private static void StripGameplayComponents(GameObject root) { Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true); for (int num = componentsInChildren.Length - 1; num >= 0; num--) { Component val = componentsInChildren[num]; if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is MeshRenderer) && !(val is SkinnedMeshRenderer) && !(val is MeshFilter) && !(val is Animator) && !(val is Collider)) { Object.Destroy((Object)(object)val); } } SetActiveRecursively(root.transform); } private static void SetActiveRecursively(Transform transform) { ((Component)transform).gameObject.SetActive(true); for (int i = 0; i < transform.childCount; i++) { SetActiveRecursively(transform.GetChild(i)); } } private static void EnsureCollider(GameObject root) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)root.GetComponentInChildren<Collider>() != (Object)null)) { BoxCollider obj = root.AddComponent<BoxCollider>(); obj.size = new Vector3(1.2f, 0.8f, 0.8f); obj.center = new Vector3(0f, 0.4f, 0f); } } } public sealed class ArtisanInventoryUpgradeStationInteractable : Interactable { protected override void Awake() { ((Interactable)this).Awake(); ((Interactable)this).CanInteractAction += CannotInteract; ((Interactable)this).CanHoldInteractAction += CanHoldInteract; ((Interactable)this).CustomTooltipAction += ShowTooltip; } protected override void OnDestroy() { ((Interactable)this).CanInteractAction -= CannotInteract; ((Interactable)this).CanHoldInteractAction -= CanHoldInteract; ((Interactable)this).CustomTooltipAction -= ShowTooltip; ((Interactable)this).OnDestroy(); } public void ShowUpgradeTooltip(NetworkIdentity identity) { ShowTooltip((Interactable)(object)this, identity); } private bool CannotInteract(NetworkIdentity identity, Interactable interactable) { return false; } private bool CanHoldInteract(NetworkIdentity identity, Interactable interactable) { PawnInventory inventory = GetInventory(identity); if ((Object)(object)inventory != (Object)null) { return ArtisanInventoryUpgradeService.CanPurchaseNextUpgrade(inventory); } return false; } private void ShowTooltip(Interactable interactable, NetworkIdentity identity) { PawnInventory inventory = GetInventory(identity); if (!((Object)(object)inventory == (Object)null)) { int unlockedExtraSlots = ArtisanInventoryUpgradeService.GetUnlockedExtraSlots(inventory); int maxExtraSlots = ArtisanInventoryUpgradeService.GetMaxExtraSlots(); if (unlockedExtraSlots >= maxExtraSlots) { UIManager.Instance.uiTooltip.ShowTooltip(ArtisanText.Format("inventory_upgrade_full"), (InputTarget)2, false, false, (string)null, (InputTarget)8, true, false, (string)null, (InputTarget)9, true, false); return; } int nextUpgradePrice = ArtisanInventoryUpgradeService.GetNextUpgradePrice(inventory); bool flag = ArtisanInventoryUpgradeService.CanPurchaseNextUpgrade(inventory); UIManager.Instance.uiTooltip.ShowTooltip(ArtisanText.Format("inventory_upgrade_buy", nextUpgradePrice), (InputTarget)2, flag, true, (string)null, (InputTarget)8, true, false, (string)null, (InputTarget)9, true, false); } } private static PawnInventory GetInventory(NetworkIdentity identity) { if (!((Object)(object)identity == (Object)null)) { return ((Component)identity).GetComponent<PawnInventory>(); } return null; } } [HarmonyPatch(typeof(Interactable), "HoldInteract")] public static class ArtisanInventoryUpgradeStationHoldPatch { [CompilerGenerated] private sealed class <RefreshTooltipAfterPurchase>d__1 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ArtisanInventoryUpgradeStationInteractable station; public NetworkIdentity identity; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RefreshTooltipAfterPurchase>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.15f); <>1__state = 1; return true; case 1: { <>1__state = -1; if ((Object)(object)station == (Object)null) { return false; } ((Interactable)station).RefreshLocalInteractable(); ArtisanLockedSlotOverlayPatch.RefreshCurrentInventory(); UIManager instance = UIManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.uiTooltip == (Object)null) { return false; } station.ShowUpgradeTooltip(identity); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static bool Prefix(Interactable __instance, NetworkIdentity identity) { if (!(__instance is ArtisanInventoryUpgradeStationInteractable)) { return true; } PawnInventory inventory = (((Object)(object)identity == (Object)null) ? null : ((Component)identity).GetComponent<PawnInventory>()); UIManager instance = UIManager.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.uiTooltip != (Object)null) { instance.uiTooltip.HideTooltip(); } ArtisanInventoryUpgradeNetwork.RequestPurchase(inventory); ArtisanInventoryUpgradeStationInteractable artisanInventoryUpgradeStationInteractable = __instance as ArtisanInventoryUpgradeStationInteractable; if ((Object)(object)artisanInventoryUpgradeStationInteractable != (Object)null) { ((MonoBehaviour)artisanInventoryUpgradeStationInteractable).StartCoroutine(RefreshTooltipAfterPurchase(artisanInventoryUpgradeStationInteractable, identity)); } return false; } [IteratorStateMachine(typeof(<RefreshTooltipAfterPurchase>d__1))] private static IEnumerator RefreshTooltipAfterPurchase(ArtisanInventoryUpgradeStationInteractable station, NetworkIdentity identity) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RefreshTooltipAfterPurchase>d__1(0) { station = station, identity = identity }; } } [HarmonyPatch] public static class InventoryPersistencePatch { [CompilerGenerated] private sealed class <TargetMethods>d__0 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = AccessTools.Method(typeof(PawnInventory), "ServerSerializeToKvp", (Type[])null, (Type[])null); <>1__state = 1; return true; case 1: <>1__state = -1; <>2__current = AccessTools.Method(typeof(PawnInventory), "ServerTryRestoreFromKvp", (Type[])null, (Type[])null); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__0(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } [IteratorStateMachine(typeof(<TargetMethods>d__0))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__0(-2); } private static void Postfix(PawnInventory __instance, SaveManager save, string playerId, MethodBase __originalMethod) { if (!IsEnabled() || (Object)(object)__instance == (Object)null || (Object)(object)save == (Object)null || string.IsNullOrEmpty(playerId)) { return; } try { if (__originalMethod.Name == "ServerSerializeToKvp") { SerializeExtendedSlots(__instance, save, playerId); } else if (__originalMethod.Name == "ServerTryRestoreFromKvp") { RestoreExtendedSlots(__instance, save, playerId); } } catch (Exception ex) { ArtisanMod.Logger.LogWarning((object)("[InventoryPersistence] Failed: " + ex.Message)); } } private static void SerializeExtendedSlots(PawnInventory inventory, SaveManager save, string playerId) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) string keyPrefix = GetKeyPrefix(playerId); int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots(); save.SetInt(keyPrefix + ".SLOT_COUNT", maxInventorySlots); save.SetInt(keyPrefix + ".MAIN", Mathf.Clamp(inventory.CurrentMainHandSlot, 0, maxInventorySlots - 1)); MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "SerializeProp", (Type[])null, (Type[])null); if (methodInfo == null) { return; } for (int i = 0; i < maxInventorySlots; i++) { NetworkPuppetProp val = null; if (i < inventory.Items.Count) { InventoryItem val2 = inventory.Items[i]; if (!((InventoryItem)(ref val2)).IsEmpty) { val2 = inventory.Items[i]; val = ((InventoryItem)(ref val2)).PropInstance; } } methodInfo.Invoke(inventory, new object[3] { save, keyPrefix + ".S" + i, val }); } } private static void RestoreExtendedSlots(PawnInventory inventory, SaveManager save, string playerId) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) string keyPrefix = GetKeyPrefix(playerId); int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots(); MethodInfo methodInfo = AccessTools.Method(typeof(PawnInventory), "TryRestoreProp", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PawnInventory), "ServerAddItemToSlot", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { return; } InventoryItem val3 = default(InventoryItem); for (int i = 3; i < maxInventorySlots; i++) { if (i < inventory.Items.Count) { InventoryItem val = inventory.Items[i]; if (!((InventoryItem)(ref val)).IsEmpty) { continue; } } object[] array = new object[4] { save, keyPrefix + ".S" + i, playerId, null }; if (!(bool)methodInfo.Invoke(inventory, array) || array[3] == null) { continue; } object obj = array[3]; NetworkPuppetProp val2 = (NetworkPuppetProp)((obj is NetworkPuppetProp) ? obj : null); if (!((Object)(object)val2 == (Object)null)) { ((InventoryItem)(ref val3))..ctor(val2); if ((bool)methodInfo2.Invoke(inventory, new object[2] { i, val3 })) { AccessTools.Field(typeof(PawnInventory), "propInteractions")?.GetValue(inventory); SetPropInInventory(val2, inventory); } } } RestoreSelectedMainSlot(inventory, save, keyPrefix, maxInventorySlots); NormalizeRestoredInventoryProps(inventory); } private static void SetPropInInventory(NetworkPuppetProp prop, PawnInventory inventory) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)prop == (Object)null) && !((Object)(object)inventory == (Object)null)) { object? obj = AccessTools.Field(typeof(PawnInventory), "propInteractions")?.GetValue(inventory); PawnPropInteractions val = (PawnPropInteractions)((obj is PawnPropInteractions) ? obj : null); if ((Object)(object)val != (Object)null) { prop.ServerSetInInventory(val); } else { prop.CurrentState = new PropStateData((PropState)2, (PawnPropInteractions)null, true); } } } private static void NormalizeRestoredInventoryProps(PawnInventory inventory) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventory == (Object)null) { return; } int currentMainHandSlot = inventory.CurrentMainHandSlot; for (int i = 0; i < inventory.Items.Count; i++) { if (i != currentMainHandSlot) { InventoryItem val = inventory.Items[i]; if (!((InventoryItem)(ref val)).IsEmpty && !((Object)(object)((InventoryItem)(ref val)).PropInstance == (Object)null)) { SetPropInInventory(((InventoryItem)(ref val)).PropInstance, inventory); } } } if (currentMainHandSlot >= 0 && currentMainHandSlot < inventory.Items.Count) { InventoryItem val2 = inventory.Items[currentMainHandSlot]; if (!((InventoryItem)(ref val2)).IsEmpty) { inventory.SelectSlotWithMainHand(currentMainHandSlot); } } } private static void RestoreSelectedMainSlot(PawnInventory inventory, SaveManager save, string keyPrefix, int maxSlots) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) int num = default(int); if (!save.TryGetInt(keyPrefix + ".MAIN", ref num)) { return; } num = Mathf.Clamp(num, 0, maxSlots - 1); if (num < inventory.Items.Count) { InventoryItem val = inventory.Items[num]; if (!((InventoryItem)(ref val)).IsEmpty) { inventory.SelectSlotWithMainHand(num); } } } private static string GetKeyPrefix(string playerId) { return "PLAYER." + playerId + ".INV"; } private static bool IsEnabled() { if (ArtisanMod.EnableExtendedInventorySlots != null) { return ArtisanMod.EnableExtendedInventorySlots.Value; } return false; } } [HarmonyPatch] public static class InventorySlotLimitPatch { [CompilerGenerated] private sealed class <TargetMethods>d__1 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IDisposable, IEnumerator { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private Type <type>5__2; private string[] <>7__wrap2; private int <>7__wrap3; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <type>5__2 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0078; } <>1__state = -1; <type>5__2 = typeof(PawnInventory); <>7__wrap2 = TargetMethodNames; <>7__wrap3 = 0; goto IL_0086; IL_0078: <>7__wrap3++; goto IL_0086; IL_0086: if (<>7__wrap3 < <>7__wrap2.Length) { string text = <>7__wrap2[<>7__wrap3]; MethodInfo methodInfo = AccessTools.Method(<type>5__2, text, (Type[])null, (Type[])null); if (methodInfo != null) { <>2__current = methodInfo; <>1__state = 1; return true; } goto IL_0078; } <>7__wrap2 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__1(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <Transpiler>d__2 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IDisposable, IEnumerator { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; private IEnumerable<CodeInstruction> instructions; public IEnumerable<CodeInstruction> <>3__instructions; private IEnumerator<CodeInstruction> <>7__wrap1; CodeInstruction IEnumerator<CodeInstruction>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Transpiler>d__2(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = instructions.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; case 2: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { CodeInstruction current = <>7__wrap1.Current; if (!IsEnabled()) { <>2__current = current; <>1__state = 1; return true; } if (IsLdcI4(current, 3)) { current.opcode = OpCodes.Call; current.operand = AccessTools.Method(typeof(InventorySlotLimitPatch), "GetMaxInventorySlots", (Type[])null, (Type[])null); } else if (IsLdcI4(current, 2)) { current.opcode = OpCodes.Call; current.operand = AccessTools.Method(typeof(InventorySlotLimitPatch), "GetMaxInventorySlotIndex", (Type[])null, (Type[])null); } <>2__current = current; <>1__state = 2; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator() { <Transpiler>d__2 <Transpiler>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <Transpiler>d__ = this; } else { <Transpiler>d__ = new <Transpiler>d__2(0); } <Transpiler>d__.instructions = <>3__instructions; return <Transpiler>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<CodeInstruction>)this).GetEnumerator(); } } private static readonly string[] TargetMethodNames = new string[12] { "OnStartServer", "OnStartClient", "IsFull", "ServerTryAddItem", "ServerAddItemToSlot", "ServerRemoveFromSlot", "SelectSlotWithMainHand", "ServerSerializeToKvp", "ServerTryRestoreFromKvp", "UserCode_CmdCycleSlot__Boolean", "UserCode_CmdMoveItemInInventory__UInt32__Int32", "UserCode_CmdSwapSlotWithRightHand__Int32" }; [IteratorStateMachine(typeof(<TargetMethods>d__1))] [HarmonyTargetMethods] private static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__1(-2); } [IteratorStateMachine(typeof(<Transpiler>d__2))] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Transpiler>d__2(-2) { <>3__instructions = instructions }; } public static int GetMaxInventorySlots() { if (!IsEnabled()) { return 3; } return Mathf.Clamp(ArtisanMod.MaxInventorySlots.Value, 3, 8); } public static int GetMaxInventorySlotIndex() { return GetMaxInventorySlots() - 1; } private static bool IsEnabled() { if (ArtisanMod.EnableExtendedInventorySlots != null) { return ArtisanMod.EnableExtendedInventorySlots.Value; } return false; } private static bool IsLdcI4(CodeInstruction instruction, int value) { if (value == 2 && instruction.opcode == OpCodes.Ldc_I4_2) { return true; } if (value == 3 && instruction.opcode == OpCodes.Ldc_I4_3) { return true; } if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num) { return num == value; } if (instruction.opcode == OpCodes.Ldc_I4_S && instruction.operand is sbyte b) { return b == value; } return false; } } [HarmonyPatch(typeof(UIInventory), "OnStartPawnAuthorityChanged")] public static class UIInventorySlotExpansionPatch { private static void Prefix(UIInventory __instance) { if ((Object)(object)__instance == (Object)null || ArtisanMod.EnableExtendedInventorySlots == null || !ArtisanMod.EnableExtendedInventorySlots.Value) { return; } UIInventorySlot[] fieldValue = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(__instance, "inventorySlots"); int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots(); if (fieldValue == null || fieldValue.Length == 0 || fieldValue.Length >= maxInventorySlots) { return; } UIInventorySlot val = fieldValue[0]; if ((Object)(object)val == (Object)null) { return; } Transform parent = ((Component)val).transform.parent; if ((Object)(object)parent == (Object)null) { return; } UIInventorySlot[] array = (UIInventorySlot[])(object)new UIInventorySlot[maxInventorySlots]; for (int i = 0; i < fieldValue.Length; i++) { array[i] = fieldValue[i]; } for (int j = fieldValue.Length; j < maxInventorySlots; j++) { GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent); ((Object)val2).name = "ArtisanInventorySlot_" + j; val2.SetActive(true); UIInventorySlot component = val2.GetComponent<UIInventorySlot>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); continue; } LayoutElement component2 = val2.GetComponent<LayoutElement>(); if ((Object)(object)component2 != (Object)null) { component2.ignoreLayout = true; } array[j] = component; } HarmonyUtil.SetFieldValue(__instance, "inventorySlots", array); } } [HarmonyPatch(typeof(UIInventory), "Update")] public static class UIInventoryExtendedHotkeysPatch { private static readonly KeyCode[] SlotKeys; private static void Postfix(UIInventory __instance) { if (ArtisanMod.EnableExtendedInventorySlots == null || !ArtisanMod.EnableExtendedInventorySlots.Value) { return; } PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(__instance, "_playerInventory"); if ((Object)(object)fieldValue == (Object)null) { return; } int maxInventorySlots = InventorySlotLimitPatch.GetMaxInventorySlots(); for (int i = 3; i < maxInventorySlots && i < 8; i++) { if (ArtisanInventoryUpgradeService.IsSlotUnlocked(fieldValue, i) && Input.GetKeyDown(SlotKeys[i - 3])) { fieldValue.CmdSelectSlotWithMainHand(i); break; } } } static UIInventoryExtendedHotkeysPatch() { KeyCode[] array = new KeyCode[5]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); SlotKeys = (KeyCode[])(object)array; } } public static class ArtisanInventoryUpgradeService { private const int VanillaSlotCount = 3; private const string UnlockedExtraSlotsKey = ".UNLOCKED_EXTRA_SLOTS"; public static bool IsEnabled() { if (ArtisanMod.EnableExtendedInventorySlots != null && ArtisanMod.EnableExtendedInventorySlots.Value && ArtisanMod.EnableInventorySlotUpgrades != null) { return ArtisanMod.EnableInventorySlotUpgrades.Value; } return false; } public static int GetMaxExtraSlots() { return Mathf.Max(0, InventorySlotLimitPatch.GetMaxInventorySlots() - 3); } public static int GetUnlockedExtraSlots(PawnInventory inventory) { if (!IsEnabled()) { return GetMaxExtraSlots(); } Pawn pawn = GetPawn(inventory); if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId)) { return 0; } SaveManager val = default(SaveManager); if (!Service.Get<SaveManager>(ref val)) { return 0; } int num = default(int); if (!val.TryGetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), ref num)) { return 0; } return Mathf.Clamp(num, 0, GetMaxExtraSlots()); } public static int GetUnlockedSlotCount(PawnInventory inventory) { return 3 + GetUnlockedExtraSlots(inventory); } public static bool IsSlotUnlocked(PawnInventory inventory, int slotIndex) { if (slotIndex < 3) { return true; } if (slotIndex >= 0) { return slotIndex < GetUnlockedSlotCount(inventory); } return false; } public static int GetNextUpgradePrice(PawnInventory inventory) { int unlockedExtraSlots = GetUnlockedExtraSlots(inventory); int num = Mathf.Max(0, ArtisanMod.ExtraSlotBasePrice.Value); float num2 = Mathf.Max(1f, ArtisanMod.ExtraSlotPriceMultiplier.Value); return Mathf.CeilToInt((float)num * Mathf.Pow(num2, (float)unlockedExtraSlots)); } public static bool CanPurchaseNextUpgrade(PawnInventory inventory) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled()) { return false; } if (!NetworkServer.active) { return false; } if ((Object)(object)GameManager.Instance == (Object)null || (int)GameManager.Instance.CurrentGameState != 0) { return false; } Pawn pawn = GetPawn(inventory); if ((Object)(object)pawn == (Object)null || string.IsNullOrEmpty(pawn.PlayerId)) { return false; } if (GetUnlockedExtraSlots(inventory) >= GetMaxExtraSlots()) { return false; } return GameManager.Instance.Gold >= GetNextUpgradePrice(inventory); } public static bool TryPurchaseNextUpgrade(PawnInventory inventory) { if (!CanPurchaseNextUpgrade(inventory)) { return false; } Pawn pawn = GetPawn(inventory); SaveManager val = default(SaveManager); if ((Object)(object)pawn == (Object)null || !Service.Get<SaveManager>(ref val)) { return false; } int nextUpgradePrice = GetNextUpgradePrice(inventory); int num = GetUnlockedExtraSlots(inventory) + 1; GameManager.Instance.ModifyGold(-nextUpgradePrice); val.SetInt(GetUnlockedExtraSlotsKey(pawn.PlayerId), num); inventory.ServerPersistInventory(); return true; } public static int GetFirstUnlockedEmptySlot(PawnInventory inventory) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)inventory == (Object)null) { return -1; } int unlockedSlotCount = GetUnlockedSlotCount(inventory); for (int i = 0; i < unlockedSlotCount; i++) { if (!IsSlotUnlocked(inventory, i)) { continue; } if (i < inventory.Items.Count) { InventoryItem val = inventory.Items[i]; if (!((InventoryItem)(ref val)).IsEmpty) { continue; } } return i; } return -1; } private static Pawn GetPawn(PawnInventory inventory) { if (!((Object)(object)inventory == (Object)null)) { return ((Component)inventory).GetComponent<Pawn>(); } return null; } private static string GetUnlockedExtraSlotsKey(string playerId) { return "PLAYER." + playerId + ".INV.UNLOCKED_EXTRA_SLOTS"; } } [HarmonyPatch] public static class ArtisanLockedSlotOverlayPatch { [HarmonyPatch(typeof(UIInventory), "RefreshInventoryDisplay")] [HarmonyPostfix] private static void RefreshInventoryDisplayPostfix(UIInventory __instance) { Refresh(__instance); } public static void RefreshCurrentInventory() { if (!((Object)(object)UIManager.Instance == (Object)null) && !((Object)(object)UIManager.Instance.uiGame == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer == (Object)null) && !((Object)(object)UIManager.Instance.uiGame.uiPlayer.uiInventory == (Object)null)) { Refresh(UIManager.Instance.uiGame.uiPlayer.uiInventory); } } private static void Refresh(UIInventory inventoryUi) { if ((Object)(object)inventoryUi == (Object)null) { return; } PawnInventory fieldValue = HarmonyUtil.GetFieldValue<PawnInventory>(inventoryUi, "_playerInventory"); if ((Object)(object)fieldValue == (Object)null) { return; } UIInventorySlot[] fieldValue2 = HarmonyUtil.GetFieldValue<UIInventorySlot[]>(inventory