using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using IL.RoR2; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using MonoMod.Cil; using On.RoR2; using On.RoR2.Items; using RoR2; using RoR2.Orbs; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("FunctionalCouplerRework")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("FunctionalCouplerRework")] [assembly: AssemblyTitle("FunctionalCouplerRework")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FunctionalCouplerRework { public class Class1 { } internal sealed class PassiveEquipmentManager { private readonly Plugin plugin; private readonly ManualLogSource logger; private readonly Dictionary> manuallyAppliedBuffs = new Dictionary>(); private readonly HashSet pendingCollectiveRepairs = new HashSet(); private readonly HashSet pendingVoidRepairs = new HashSet(); private readonly HashSet pendingEarthRepairs = new HashSet(); private readonly HashSet pendingHauntedRepairs = new HashSet(); private readonly HashSet pendingBeadRepairs = new HashSet(); private readonly HashSet deferredInventoryChanges = new HashSet(); private int temporaryInventoryMutationDepth; internal PassiveEquipmentManager(Plugin plugin) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown this.plugin = plugin; logger = plugin.Log; EquipmentSlot.MyFixedUpdate += new Manipulator(PatchWoodspriteFollowerRequirement); MultiShopCardUtils.OnPurchase += new hook_OnPurchase(MultiShopCardUtils_OnPurchase); } internal void OnInventoryChanged(CharacterBody body) { if (Object.op_Implicit((Object)(object)body)) { if (temporaryInventoryMutationDepth > 0) { deferredInventoryChanges.Add(body); return; } ReconcileInactiveEquipmentBuffs(body); ScheduleCollectiveRepairIfNeeded(body); ScheduleVoidRepairIfNeeded(body); ScheduleEarthRepairIfNeeded(body); ScheduleHauntedRepairIfNeeded(body); ScheduleBeadRepairIfNeeded(body); } } internal void BeginTemporaryInventoryMutation() { temporaryInventoryMutationDepth++; } internal void EndTemporaryInventoryMutation() { if (temporaryInventoryMutationDepth <= 0) { logger.LogWarning((object)"[FCR INVENTORY] Temporary inventory mutation depth underflow."); temporaryInventoryMutationDepth = 0; return; } temporaryInventoryMutationDepth--; if (temporaryInventoryMutationDepth > 0 || deferredInventoryChanges.Count == 0) { return; } CharacterBody[] array = (CharacterBody[])(object)new CharacterBody[deferredInventoryChanges.Count]; deferredInventoryChanges.CopyTo(array); deferredInventoryChanges.Clear(); foreach (CharacterBody val in array) { if (Object.op_Implicit((Object)(object)val)) { OnInventoryChanged(val); } } } internal bool TryFindStoredEquipment(Inventory inventory, EquipmentIndex targetEquipment, out uint foundSlot, out uint foundSet) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) foundSlot = 0u; foundSet = 0u; int equipmentSlotCount = inventory.GetEquipmentSlotCount(); for (uint num = 0u; num < equipmentSlotCount; num++) { int equipmentSetCount = inventory.GetEquipmentSetCount(num); for (uint num2 = 0u; num2 < equipmentSetCount; num2++) { if (inventory.GetEquipment(num, num2).equipmentIndex == targetEquipment) { foundSlot = num; foundSet = num2; return true; } } } return false; } internal void OnBodyDestroyed(CharacterBody body) { RemoveManuallyAppliedBuffs(body); pendingCollectiveRepairs.Remove(body); pendingVoidRepairs.Remove(body); pendingEarthRepairs.Remove(body); pendingHauntedRepairs.Remove(body); pendingBeadRepairs.Remove(body); deferredInventoryChanges.Remove(body); } private void ReconcileInactiveEquipmentBuffs(CharacterBody body) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_004f: 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_0054: 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) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Invalid comparison between Unknown and I4 //IL_0080: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null) { return; } EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex; HashSet hashSet = new HashSet(); int equipmentSlotCount = inventory.GetEquipmentSlotCount(); for (uint num = 0u; num < equipmentSlotCount; num++) { int equipmentSetCount = inventory.GetEquipmentSetCount(num); for (uint num2 = 0u; num2 < equipmentSetCount; num2++) { EquipmentIndex equipmentIndex = inventory.GetEquipment(num, num2).equipmentIndex; if ((int)equipmentIndex != -1 && equipmentIndex != currentEquipmentIndex) { BuffDef val = EquipmentCatalog.GetEquipmentDef(equipmentIndex)?.passiveBuffDef; if (!((Object)(object)val == (Object)null) && (int)val.buffIndex != -1) { hashSet.Add(val.buffIndex); } } } } if (!manuallyAppliedBuffs.TryGetValue(body, out var value)) { value = new HashSet(); manuallyAppliedBuffs[body] = value; } List list = new List(); foreach (BuffIndex item in value) { if (!hashSet.Contains(item)) { list.Add(item); } } foreach (BuffIndex item2 in list) { if (body.HasBuff(item2)) { body.RemoveBuff(item2); } value.Remove(item2); } foreach (BuffIndex item3 in hashSet) { if (!value.Contains(item3)) { body.AddBuff(item3); value.Add(item3); } } if (value.Count == 0) { manuallyAppliedBuffs.Remove(body); } } private void ScheduleCollectiveRepairIfNeeded(CharacterBody body) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && NetworkServer.active) { BuffIndex buffIndex = Buffs.EliteCollective.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && pendingCollectiveRepairs.Add(body)) { ((MonoBehaviour)plugin).StartCoroutine(RepairCollectiveBehaviorNextFrame(body)); } } } private IEnumerator RepairCollectiveBehaviorNextFrame(CharacterBody body) { yield return null; pendingCollectiveRepairs.Remove(body); if (!Object.op_Implicit((Object)(object)body) || !NetworkServer.active) { yield break; } Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || inventory.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { yield break; } BuffIndex buffIndex = Buffs.EliteCollective.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && body.HasBuff(buffIndex) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent())) { if (Object.op_Implicit((Object)(object)body.AddItemBehavior(1))) { logger.LogInfo((object)("[FCR COLLECTIVE] Restored missing AffixCollectiveBehavior on " + ((Object)body).name + " after deferred destruction.")); } else { logger.LogWarning((object)("[FCR COLLECTIVE] Tried to restore AffixCollectiveBehavior on " + ((Object)body).name + ", but vanilla returned null.")); } } } private void ScheduleVoidRepairIfNeeded(CharacterBody body) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && NetworkServer.active) { BuffIndex buffIndex = Buffs.EliteVoid.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && pendingVoidRepairs.Add(body)) { ((MonoBehaviour)plugin).StartCoroutine(RepairVoidBehaviorNextFrame(body)); } } } private IEnumerator RepairVoidBehaviorNextFrame(CharacterBody body) { yield return null; pendingVoidRepairs.Remove(body); if (!Object.op_Implicit((Object)(object)body) || !NetworkServer.active) { yield break; } Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || inventory.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { yield break; } BuffIndex buffIndex = Buffs.EliteVoid.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && body.HasBuff(buffIndex) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent())) { if (Object.op_Implicit((Object)(object)body.AddItemBehavior(1))) { logger.LogInfo((object)("[FCR VOID] Restored missing AffixVoidBehavior on " + ((Object)body).name + " after deferred destruction.")); } else { logger.LogWarning((object)("[FCR VOID] Tried to restore AffixVoidBehavior on " + ((Object)body).name + ", but vanilla returned null.")); } } } private void ScheduleEarthRepairIfNeeded(CharacterBody body) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && NetworkServer.active) { BuffIndex buffIndex = Buffs.EliteEarth.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && pendingEarthRepairs.Add(body)) { ((MonoBehaviour)plugin).StartCoroutine(RepairEarthBehaviorNextFrame(body)); } } } private IEnumerator RepairEarthBehaviorNextFrame(CharacterBody body) { yield return null; pendingEarthRepairs.Remove(body); if (!Object.op_Implicit((Object)(object)body) || !NetworkServer.active) { yield break; } Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || inventory.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { yield break; } BuffIndex buffIndex = Buffs.EliteEarth.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && body.HasBuff(buffIndex) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent())) { if (Object.op_Implicit((Object)(object)body.AddItemBehavior(1))) { logger.LogInfo((object)("[FCR EARTH] Restored missing AffixEarthBehavior on " + ((Object)body).name + " after deferred destruction.")); } else { logger.LogWarning((object)("[FCR EARTH] Tried to restore AffixEarthBehavior on " + ((Object)body).name + ", but vanilla returned null.")); } } } private void ScheduleHauntedRepairIfNeeded(CharacterBody body) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && NetworkServer.active) { BuffIndex buffIndex = Buffs.AffixHaunted.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && pendingHauntedRepairs.Add(body)) { ((MonoBehaviour)plugin).StartCoroutine(RepairHauntedBehaviorNextFrame(body)); } } } private IEnumerator RepairHauntedBehaviorNextFrame(CharacterBody body) { yield return null; pendingHauntedRepairs.Remove(body); if (!Object.op_Implicit((Object)(object)body) || !NetworkServer.active) { yield break; } Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || inventory.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { yield break; } BuffIndex buffIndex = Buffs.AffixHaunted.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && body.HasBuff(buffIndex) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent())) { if (Object.op_Implicit((Object)(object)body.AddItemBehavior(1))) { logger.LogInfo((object)("[FCR HAUNTED] Restored missing AffixHauntedBehavior on " + ((Object)body).name + " after deferred destruction.")); } else { logger.LogWarning((object)("[FCR HAUNTED] Tried to restore AffixHauntedBehavior on " + ((Object)body).name + ", but vanilla returned null.")); } } } private void ScheduleBeadRepairIfNeeded(CharacterBody body) { //IL_0015: 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_002c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && NetworkServer.active) { BuffIndex buffIndex = Buffs.EliteBead.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && pendingBeadRepairs.Add(body)) { ((MonoBehaviour)plugin).StartCoroutine(RepairBeadBehaviorNextFrame(body)); } } } private IEnumerator RepairBeadBehaviorNextFrame(CharacterBody body) { yield return null; pendingBeadRepairs.Remove(body); if (!Object.op_Implicit((Object)(object)body) || !NetworkServer.active) { yield break; } Inventory inventory = body.inventory; if ((Object)(object)inventory == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || inventory.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { yield break; } BuffIndex buffIndex = Buffs.EliteBead.buffIndex; if (manuallyAppliedBuffs.TryGetValue(body, out var value) && value.Contains(buffIndex) && body.HasBuff(buffIndex) && !Object.op_Implicit((Object)(object)((Component)body).GetComponent())) { if (Object.op_Implicit((Object)(object)body.AddItemBehavior(1))) { logger.LogInfo((object)("[FCR BEAD] Restored missing AffixBeadBehavior on " + ((Object)body).name + " after deferred destruction.")); } else { logger.LogWarning((object)("[FCR BEAD] Tried to restore AffixBeadBehavior on " + ((Object)body).name + ", but vanilla returned null.")); } } } private void MultiShopCardUtils_OnPurchase(orig_OnPurchase orig, PayCostContext context, int moneyCost) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_01f7: Unknown result type (might be due to invalid IL or missing references) CharacterMaster activatorMaster = context.activatorMaster; Inventory val = (Object.op_Implicit((Object)(object)activatorMaster) ? activatorMaster.inventory : null); if ((Object)(object)val == (Object)null || val.currentEquipmentIndex == Equipment.MultiShopCard.equipmentIndex) { orig.Invoke(context, moneyCost); return; } if (!activatorMaster.hasBody || (int)Plugin.FunctionalCouplerIndex == -1 || val.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0 || val.GetEquipmentDisabled() || !TryFindStoredEquipment(val, Equipment.MultiShopCard.equipmentIndex, out var foundSlot, out var foundSet)) { orig.Invoke(context, moneyCost); return; } if (val.GetEquipment(foundSlot, foundSet).charges <= 0) { orig.Invoke(context, moneyCost); return; } CharacterBody body = activatorMaster.GetBody(); if (!Object.op_Implicit((Object)(object)body) || !Object.op_Implicit((Object)(object)body.equipmentSlot)) { orig.Invoke(context, moneyCost); return; } bool flag = false; if (moneyCost > 0) { flag = true; GoldOrb val2 = new GoldOrb(); GameObject purchasedObject = context.purchasedObject; Vector3? obj; if (purchasedObject == null) { obj = null; } else { Transform transform = purchasedObject.transform; obj = ((transform != null) ? new Vector3?(transform.position) : ((Vector3?)null)); } ((Orb)val2).origin = (Vector3)(((??)obj) ?? body.corePosition); ((Orb)val2).target = body.mainHurtBox; val2.goldAmount = (uint)(0.1f * (float)moneyCost); GoldOrb val3 = val2; OrbManager.instance.AddOrb((Orb)(object)val3); } GameObject purchasedObject2 = context.purchasedObject; ShopTerminalBehavior val4 = ((purchasedObject2 != null) ? purchasedObject2.GetComponent() : null); if (Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)val4.serverMultiShopController)) { flag = true; val4.serverMultiShopController.SetCloseOnTerminalPurchase(context.purchasedObject.GetComponent(), false); } GameObject purchasedObject3 = context.purchasedObject; DroneVendorTerminalBehavior val5 = ((purchasedObject3 != null) ? purchasedObject3.GetComponent() : null); if (Object.op_Implicit((Object)(object)val5) && Object.op_Implicit((Object)(object)val5.serverMultiShopController)) { flag = true; val5.serverMultiShopController.SetCloseOnTerminalPurchase(context.purchasedObject.GetComponent(), false); } if (flag) { body.equipmentSlot.OnEquipmentExecuted((byte)foundSlot, (byte)foundSet, Equipment.MultiShopCard.equipmentIndex); logger.LogInfo((object)$"[FCR CARD] Used stored Executive Card from slot {foundSlot}, set {foundSet} without touching the active equipment."); } } private void PatchWoodspriteFollowerRequirement(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (!val.TryGotoNext((MoveType)2, new Func[2] { delegate(Instruction instruction) { //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) if (instruction.OpCode == OpCodes.Ldsfld) { object operand = instruction.Operand; FieldReference val2 = (FieldReference)((operand is FieldReference) ? operand : null); if (val2 != null && ((MemberReference)val2).Name == "PassiveHealing") { return ((MemberReference)((MemberReference)val2).DeclaringType).FullName == "RoR2.RoR2Content/Equipment"; } } return false; }, (Instruction instruction) => ILPatternMatchingExt.MatchCallOrCallvirt(instruction, "op_Equality") })) { logger.LogError((object)"[FCR WOODSPRITE] Failed to locate the passive-healing follower requirement in EquipmentSlot.MyFixedUpdate. Stored Woodsprite support was not patched."); return; } val.Emit(OpCodes.Ldarg_0); val.EmitDelegate>((Func)ShouldHavePassiveHealingFollower); logger.LogInfo((object)"[FCR WOODSPRITE] Patched EquipmentSlot.MyFixedUpdate so stored Woodsprite can use vanilla follower management."); } private bool ShouldHavePassiveHealingFollower(bool vanillaShouldHaveFollower, EquipmentSlot equipmentSlot) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (vanillaShouldHaveFollower) { return true; } if (!Object.op_Implicit((Object)(object)equipmentSlot)) { return false; } CharacterBody characterBody = equipmentSlot.characterBody; Inventory val = ((characterBody != null) ? characterBody.inventory : null); if ((Object)(object)val == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || val.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { return false; } uint foundSlot; uint foundSet; return TryFindStoredEquipment(val, Equipment.PassiveHealing.equipmentIndex, out foundSlot, out foundSet); } private void RemoveManuallyAppliedBuffs(CharacterBody body) { //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_002c: 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) if (!Object.op_Implicit((Object)(object)body) || !manuallyAppliedBuffs.TryGetValue(body, out var value)) { return; } foreach (BuffIndex item in value) { if (body.HasBuff(item)) { body.RemoveBuff(item); } } manuallyAppliedBuffs.Remove(body); } } [BepInPlugin("thatguy119407.functionalcouplerrework", "Functional Coupler Rework", "1.0.4")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "thatguy119407.functionalcouplerrework"; public const string PluginName = "Functional Coupler Rework"; public const string PluginVersion = "1.0.4"; private static Plugin instance; private static ItemIndex functionalCouplerIndex = (ItemIndex)(-1); private PassiveEquipmentManager passiveEquipmentManager; private SeedReviveManager seedReviveManager; private FieldInfo itemDisplayRuleSetField; private MethodInfo instantiateDisplayRuleGroupMethod; private FieldInfo forceUpdateField; private FieldInfo collectiveFoundDisplaysField; private FieldInfo collectiveAnimatorsField; private FieldInfo collectiveHornPairsField; private bool checkedCatalog; private bool attemptedDisplayMethodResolution; private bool displayMethodsResolved; internal static Plugin Instance => instance; internal static ItemIndex FunctionalCouplerIndex => functionalCouplerIndex; internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown instance = this; passiveEquipmentManager = new PassiveEquipmentManager(this); seedReviveManager = new SeedReviveManager(passiveEquipmentManager, ((BaseUnityPlugin)this).Logger); CharacterBody.OnInventoryChanged += new hook_OnInventoryChanged(CharacterBody_OnInventoryChanged); CharacterBody.OnDestroy += new hook_OnDestroy(CharacterBody_OnDestroy); CharacterModel.OnInventoryChanged += new hook_OnInventoryChanged(CharacterModel_OnInventoryChanged); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Functional Coupler Rework v1.0.4 loaded."); CharacterMaster.OnBodyDeath += new hook_OnBodyDeath(CharacterMaster_OnBodyDeath); } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown CharacterBody.OnInventoryChanged -= new hook_OnInventoryChanged(CharacterBody_OnInventoryChanged); CharacterBody.OnDestroy -= new hook_OnDestroy(CharacterBody_OnDestroy); CharacterModel.OnInventoryChanged -= new hook_OnInventoryChanged(CharacterModel_OnInventoryChanged); if ((Object)(object)instance == (Object)(object)this) { instance = null; } CharacterMaster.OnBodyDeath -= new hook_OnBodyDeath(CharacterMaster_OnBodyDeath); } private void CharacterBody_OnInventoryChanged(orig_OnInventoryChanged orig, CharacterBody self) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self); if (Object.op_Implicit((Object)(object)self)) { Inventory inventory = self.inventory; if (!((Object)(object)inventory == (Object)null) && (int)functionalCouplerIndex != -1 && inventory.GetItemCountEffective(functionalCouplerIndex) > 0) { passiveEquipmentManager.OnInventoryChanged(self); } } } private void CharacterModel_OnInventoryChanged(orig_OnInventoryChanged orig, CharacterModel self) { orig.Invoke(self); if (Object.op_Implicit((Object)(object)self) && Object.op_Implicit((Object)(object)self.body) && !((Object)(object)self.body.inventory == (Object)null)) { EnsureDisplayKeeper(self); } } private void EnsureDisplayKeeper(CharacterModel characterModel) { FunctionalCouplerDisplayKeeper functionalCouplerDisplayKeeper = ((Component)characterModel).GetComponent(); if (!Object.op_Implicit((Object)(object)functionalCouplerDisplayKeeper)) { functionalCouplerDisplayKeeper = ((Component)characterModel).gameObject.AddComponent(); } functionalCouplerDisplayKeeper.Initialize(characterModel); functionalCouplerDisplayKeeper.ReconcileImmediately(); } internal bool ShouldMaintainInactiveDisplays(CharacterModel model) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)model) || !Object.op_Implicit((Object)(object)model.body) || (Object)(object)model.body.inventory == (Object)null) { return false; } if ((int)functionalCouplerIndex == -1) { return false; } return model.body.inventory.GetItemCountEffective(functionalCouplerIndex) > 0; } internal void ReconcileInactiveDisplays(CharacterModel characterModel) { //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_004c: 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_0056: 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_005b: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (!ShouldMaintainInactiveDisplays(characterModel) || !ResolveDisplayMethods()) { return; } Inventory inventory = characterModel.body.inventory; EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex; HashSet hashSet = new HashSet(); int equipmentSlotCount = inventory.GetEquipmentSlotCount(); for (uint num = 0u; num < equipmentSlotCount; num++) { int equipmentSetCount = inventory.GetEquipmentSetCount(num); for (uint num2 = 0u; num2 < equipmentSetCount; num2++) { EquipmentIndex equipmentIndex = inventory.GetEquipment(num, num2).equipmentIndex; if ((int)equipmentIndex != -1 && equipmentIndex != currentEquipmentIndex && !((Object)(object)EquipmentCatalog.GetEquipmentDef(equipmentIndex)?.passiveBuffDef == (Object)null)) { hashSet.Add(equipmentIndex); } } } bool flag = false; foreach (EquipmentIndex item in hashSet) { List equipmentDisplayObjects = characterModel.GetEquipmentDisplayObjects(item); bool flag2 = false; for (int i = 0; i < equipmentDisplayObjects.Count; i++) { if (Object.op_Implicit((Object)(object)equipmentDisplayObjects[i])) { flag2 = true; break; } } if (!flag2 && TryInstantiateEquipmentDisplay(characterModel, item)) { flag = true; } } if (flag) { ResetCollectiveDisplaySearch(characterModel.body); } } private bool ResolveDisplayMethods() { if (attemptedDisplayMethodResolution) { return displayMethodsResolved; } attemptedDisplayMethodResolution = true; BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; itemDisplayRuleSetField = typeof(CharacterModel).GetField("itemDisplayRuleSet", bindingAttr); forceUpdateField = typeof(CharacterModel).GetField("forceUpdate", bindingAttr); instantiateDisplayRuleGroupMethod = typeof(CharacterModel).GetMethod("InstantiateDisplayRuleGroup", bindingAttr, null, new Type[3] { typeof(DisplayRuleGroup), typeof(ItemIndex), typeof(EquipmentIndex) }, null); collectiveFoundDisplaysField = typeof(AffixCollectiveDisplayBehaviour).GetField("_foundDisplays", bindingAttr); collectiveAnimatorsField = typeof(AffixCollectiveDisplayBehaviour).GetField("_animatorsFromRings", bindingAttr); collectiveHornPairsField = typeof(AffixCollectiveDisplayBehaviour).GetField("_hornPairs", bindingAttr); if (itemDisplayRuleSetField == null || instantiateDisplayRuleGroupMethod == null || forceUpdateField == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"[FCR DISPLAY] Could not resolve CharacterModel display members."); return false; } displayMethodsResolved = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"[FCR DISPLAY] Successfully resolved display members."); return true; } private bool TryInstantiateEquipmentDisplay(CharacterModel characterModel, EquipmentIndex equipmentIndex) { //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_020e: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) try { object? value = itemDisplayRuleSetField.GetValue(characterModel); ItemDisplayRuleSet val = (ItemDisplayRuleSet)((value is ItemDisplayRuleSet) ? value : null); if (!Object.op_Implicit((Object)(object)val)) { return false; } DisplayRuleGroup equipmentDisplayRuleGroup = val.GetEquipmentDisplayRuleGroup(equipmentIndex); if (((DisplayRuleGroup)(ref equipmentDisplayRuleGroup)).isEmpty) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[FCR DISPLAY] Empty display rule group for " + DescribeEquipment(equipmentIndex) + ".")); return false; } instantiateDisplayRuleGroupMethod.Invoke(characterModel, new object[3] { equipmentDisplayRuleGroup, (object)(ItemIndex)(-1), equipmentIndex }); List equipmentDisplayObjects = characterModel.GetEquipmentDisplayObjects(equipmentIndex); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; for (int i = 0; i < equipmentDisplayObjects.Count; i++) { GameObject val2 = equipmentDisplayObjects[i]; if (!Object.op_Implicit((Object)(object)val2)) { continue; } num++; val2.SetActive(true); ItemDisplay component = val2.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { continue; } num2++; component.SetVisibilityLevel(characterModel.visibility); component.RefreshRenderers(); if (component.rendererInfos == null) { continue; } for (int j = 0; j < component.rendererInfos.Length; j++) { Renderer renderer = component.rendererInfos[j].renderer; if (Object.op_Implicit((Object)(object)renderer)) { num3++; if (renderer.enabled) { num4++; } } } } forceUpdateField.SetValue(characterModel, true); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[FCR DISPLAY] Added inactive display for " + DescribeEquipment(equipmentIndex) + "; " + $"objects={num}, ItemDisplays={num2}, " + $"renderers={num3}, enabledRenderers={num4}, " + $"modelVisibility={characterModel.visibility}.")); return num > 0; } catch (TargetInvocationException ex) { Exception arg = ex.InnerException ?? ex; ((BaseUnityPlugin)this).Logger.LogError((object)$"[FCR DISPLAY] Failed to instantiate {DescribeEquipment(equipmentIndex)}:\n{arg}"); return false; } catch (Exception arg2) { ((BaseUnityPlugin)this).Logger.LogError((object)$"[FCR DISPLAY] Failed to instantiate {DescribeEquipment(equipmentIndex)}:\n{arg2}"); return false; } } private void ResetCollectiveDisplaySearch(CharacterBody body) { if (!Object.op_Implicit((Object)(object)body) || collectiveFoundDisplaysField == null) { return; } AffixCollectiveDisplayBehaviour[] array = Object.FindObjectsOfType(); foreach (AffixCollectiveDisplayBehaviour val in array) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.affixCollectiveAttachmentBehaviour) && Object.op_Implicit((Object)(object)val.affixCollectiveAttachmentBehaviour.attachment) && !((Object)(object)val.affixCollectiveAttachmentBehaviour.attachment.attachedBody != (Object)(object)body)) { collectiveFoundDisplaysField.SetValue(val, false); object obj = collectiveAnimatorsField?.GetValue(val); obj?.GetType().GetMethod("Clear")?.Invoke(obj, null); object obj2 = collectiveHornPairsField?.GetValue(val); obj2?.GetType().GetMethod("Clear")?.Invoke(obj2, null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[FCR DISPLAY] Reset AffixCollectiveDisplayBehaviour so it can discover the newly added inactive displays."); } } } private string DescribeEquipment(EquipmentIndex equipmentIndex) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipmentIndex); if (!((Object)(object)equipmentDef == (Object)null)) { return $"{((Object)equipmentDef).name} [{equipmentIndex}]"; } return $"UnknownEquipment({equipmentIndex})"; } private void CharacterMaster_OnBodyDeath(orig_OnBodyDeath orig, CharacterMaster self, CharacterBody body) { if (seedReviveManager == null) { orig.Invoke(self, body); } else { seedReviveManager.OnBodyDeath(orig, self, body); } } private void CharacterBody_OnDestroy(orig_OnDestroy orig, CharacterBody self) { passiveEquipmentManager?.OnBodyDestroyed(self); orig.Invoke(self); } private void Update() { //IL_0015: 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_0025: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!checkedCatalog && ItemCatalog.itemCount != 0) { functionalCouplerIndex = Items.ExtraEquipment.itemIndex; if ((int)functionalCouplerIndex != -1) { checkedCatalog = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Functional Coupler catalog index resolved: {functionalCouplerIndex}"); } } } } internal sealed class FunctionalCouplerDisplayKeeper : MonoBehaviour { private CharacterModel characterModel; private float nextReconcileTime; internal void Initialize(CharacterModel model) { characterModel = model; } internal void ReconcileImmediately() { nextReconcileTime = 0f; Reconcile(); } private void Update() { if (!(Time.unscaledTime < nextReconcileTime)) { Reconcile(); } } private void Reconcile() { nextReconcileTime = Time.unscaledTime + 0.5f; if (!Object.op_Implicit((Object)(object)characterModel)) { Object.Destroy((Object)(object)this); return; } Plugin instance = Plugin.Instance; if ((Object)(object)instance == (Object)null) { Object.Destroy((Object)(object)this); } else if (!instance.ShouldMaintainInactiveDisplays(characterModel)) { Object.Destroy((Object)(object)this); } else { instance.ReconcileInactiveDisplays(characterModel); } } } internal sealed class SeedReviveManager { private readonly PassiveEquipmentManager passiveEquipmentManager; private readonly ManualLogSource logger; internal SeedReviveManager(PassiveEquipmentManager passiveEquipmentManager, ManualLogSource logger) { this.passiveEquipmentManager = passiveEquipmentManager; this.logger = logger; } internal void OnBodyDeath(orig_OnBodyDeath orig, CharacterMaster master, CharacterBody body) { //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019e: 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_0031: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) Inventory val = (Object.op_Implicit((Object)(object)master) ? master.inventory : null); if (!NetworkServer.active || (Object)(object)val == (Object)null || (Object)(object)body == (Object)null || (int)Plugin.FunctionalCouplerIndex == -1 || val.GetItemCountEffective(Plugin.FunctionalCouplerIndex) <= 0) { orig.Invoke(master, body); return; } EquipmentIndex equipmentIndex = Equipment.HealAndRevive.equipmentIndex; EquipmentIndex equipmentIndex2 = Equipment.HealAndReviveConsumed.equipmentIndex; if (val.currentEquipmentIndex == equipmentIndex) { orig.Invoke(master, body); return; } if (!passiveEquipmentManager.TryFindStoredEquipment(val, equipmentIndex, out var foundSlot, out var foundSet)) { orig.Invoke(master, body); return; } uint activeEquipmentSlot = val.activeEquipmentSlot; if (val.activeEquipmentSet == null || val.activeEquipmentSet.Length <= activeEquipmentSlot) { logger.LogWarning((object)"[FCR SEED] Could not resolve the active equipment set. Vanilla death handling will run unchanged."); orig.Invoke(master, body); return; } uint num = val.activeEquipmentSet[activeEquipmentSlot]; if (foundSlot == activeEquipmentSlot && foundSet == num) { orig.Invoke(master, body); return; } EquipmentState equipment = val.GetEquipment(activeEquipmentSlot, num); EquipmentState equipment2 = val.GetEquipment(foundSlot, foundSet); if (equipment2.equipmentIndex != equipmentIndex) { orig.Invoke(master, body); return; } EquipmentState val2 = equipment2; bool flag = false; passiveEquipmentManager.BeginTemporaryInventoryMutation(); try { val.SetEquipment(equipment2, activeEquipmentSlot, num); val.SetEquipment(equipment, foundSlot, foundSet); orig.Invoke(master, body); flag = true; EquipmentState equipment3 = val.GetEquipment(activeEquipmentSlot, num); if (equipment3.equipmentIndex == equipmentIndex2) { val2 = equipment3; logger.LogInfo((object)("[FCR SEED] Vanilla consumed stored Seed of Life from " + $"slot {foundSlot}, set {foundSet} to revive {((Object)body).name}.")); } } finally { try { val.SetEquipment(equipment, activeEquipmentSlot, num); val.SetEquipment(val2, foundSlot, foundSet); } finally { passiveEquipmentManager.EndTemporaryInventoryMutation(); } } if (!flag) { logger.LogWarning((object)"[FCR SEED] Vanilla death handling did not complete normally; the temporary equipment swap was rolled back."); } } } }