Decompiled source of SummonInheritanceFix v1.4.0

SummonInheritanceFix.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HG;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RiskOfOptions;
using RiskOfOptions.OptionConfigs;
using RiskOfOptions.Options;
using RoR2;
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("SummonInheritanceFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: AssemblyProduct("SummonInheritanceFix")]
[assembly: AssemblyTitle("SummonInheritanceFix")]
[assembly: AssemblyVersion("1.3.0.0")]
[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 SummonInheritanceFix
{
	public static class ItemBehaviorScanner
	{
		private static Type itemBehaviorType;

		private static bool itemBehaviorLookedUp;

		private static Dictionary<string, ItemDef> normalizedItems;

		public static Type ItemBehaviorType
		{
			get
			{
				if (!itemBehaviorLookedUp)
				{
					itemBehaviorLookedUp = true;
					try
					{
						itemBehaviorType = typeof(CharacterBody).GetNestedType("ItemBehavior", BindingFlags.Public | BindingFlags.NonPublic);
					}
					catch
					{
						itemBehaviorType = null;
					}
				}
				return itemBehaviorType;
			}
		}

		public static void Run()
		{
			try
			{
				Type type = ItemBehaviorType;
				if (type == null)
				{
					SummonInheritancePlugin.Log.LogInfo((object)"ItemBehaviorScanner: CharacterBody.ItemBehavior not found in this game version, static scan skipped.");
					return;
				}
				Assembly assembly = typeof(CharacterBody).Assembly;
				string name = assembly.GetName().Name;
				EnsureNormalizedItems();
				int num = 0;
				List<string> list = new List<string>();
				List<string> list2 = new List<string>();
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly2 in assemblies)
				{
					if (assembly2 == assembly || assembly2 == typeof(ItemBehaviorScanner).Assembly || assembly2.IsDynamic || !ReferencesAssembly(assembly2, name))
					{
						continue;
					}
					foreach (Type item in SafeGetTypes(assembly2))
					{
						if (item == null || item == type || item.IsAbstract || !type.IsAssignableFrom(item))
						{
							continue;
						}
						num++;
						if (!TypeSpawnsAllies(item))
						{
							continue;
						}
						ItemDef val = ResolveItemDef(item);
						if ((Object)(object)val != (Object)null)
						{
							if (!ModConfig.IsSummonItemName(((Object)val).name))
							{
								ModConfig.AddAutoSummonItem(((Object)val).name);
								list.Add(((Object)val).name + " (" + item.FullName + ")");
							}
						}
						else
						{
							list2.Add(item.FullName);
						}
					}
				}
				SummonInheritancePlugin.Log.LogInfo((object)("ItemBehaviorScanner: scanned " + num + " mod item-behaviour classes."));
				if (list.Count > 0)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("ItemBehaviorScanner: items detected as summoners (will not be inherited): " + string.Join(", ", list)));
				}
				if (list2.Count > 0)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("ItemBehaviorScanner: these behaviour classes spawn allies but their item could not be resolved (add the item to ExtraSummonItems if needed): " + string.Join(", ", list2)));
				}
			}
			catch (Exception ex)
			{
				SummonInheritancePlugin.Log.LogWarning((object)("ItemBehaviorScanner failed: " + ex));
			}
		}

		private static bool ReferencesAssembly(Assembly asm, string name)
		{
			try
			{
				AssemblyName[] referencedAssemblies = asm.GetReferencedAssemblies();
				for (int i = 0; i < referencedAssemblies.Length; i++)
				{
					if (referencedAssemblies[i].Name == name)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static IEnumerable<Type> SafeGetTypes(Assembly asm)
		{
			try
			{
				return asm.GetTypes();
			}
			catch (ReflectionTypeLoadException ex)
			{
				return ex.Types;
			}
			catch
			{
				return new Type[0];
			}
		}

		private static bool TypeSpawnsAllies(Type type)
		{
			try
			{
				MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < methods.Length; i++)
				{
					if (MethodCallsSpawn(methods[i]))
					{
						return true;
					}
				}
				ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < constructors.Length; i++)
				{
					if (MethodCallsSpawn(constructors[i]))
					{
						return true;
					}
				}
				Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
				for (int i = 0; i < nestedTypes.Length; i++)
				{
					if (TypeSpawnsAllies(nestedTypes[i]))
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool MethodCallsSpawn(MethodBase method)
		{
			try
			{
				MethodBody methodBody = method.GetMethodBody();
				if (methodBody == null)
				{
					return false;
				}
				byte[] iLAsByteArray = methodBody.GetILAsByteArray();
				if (iLAsByteArray == null)
				{
					return false;
				}
				Module module = method.Module;
				Type[] genericTypeArguments = ((method.DeclaringType != null && method.DeclaringType.IsGenericType) ? method.DeclaringType.GetGenericArguments() : null);
				Type[] genericMethodArguments = (method.IsGenericMethod ? method.GetGenericArguments() : null);
				for (int i = 0; i < iLAsByteArray.Length - 4; i++)
				{
					byte b = iLAsByteArray[i];
					if (b != 40 && b != 111 && b != 115)
					{
						continue;
					}
					int num = BitConverter.ToInt32(iLAsByteArray, i + 1);
					int num2 = num >> 24;
					if (num2 != 6 && num2 != 10 && num2 != 43)
					{
						continue;
					}
					try
					{
						MethodBase methodBase = module.ResolveMethod(num, genericTypeArguments, genericMethodArguments);
						if (methodBase != null && IsSpawnCall(methodBase))
						{
							return true;
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool IsSpawnCall(MethodBase target)
		{
			Type declaringType = target.DeclaringType;
			if (declaringType == null)
			{
				return false;
			}
			string name = declaringType.Name;
			string name2 = target.Name;
			if (name == "DirectorCore" && name2 == "TrySpawnObject")
			{
				return true;
			}
			if (name == "MasterSummon")
			{
				return true;
			}
			if (name.EndsWith("SpawnCard") && (name2 == "DoSpawn" || name2 == "Spawn"))
			{
				return true;
			}
			return false;
		}

		public static ItemDef ResolveItemDef(Type behaviorType)
		{
			try
			{
				Type type = behaviorType;
				while (type != null)
				{
					object singleton = GetSingleton(type);
					if (singleton != null)
					{
						ItemDef val = FindItemDefMember(singleton);
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
					type = type.DeclaringType;
				}
				EnsureNormalizedItems();
				Type type2 = behaviorType;
				while (type2 != null)
				{
					string text = NormalizeTypeName(type2.Name);
					if (text.Length >= 4 && normalizedItems.TryGetValue(text, out var value))
					{
						return value;
					}
					type2 = type2.DeclaringType;
				}
			}
			catch
			{
			}
			return null;
		}

		private static object GetSingleton(Type type)
		{
			Type type2 = type;
			while (type2 != null && type2 != typeof(object))
			{
				try
				{
					PropertyInfo[] properties = type2.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (PropertyInfo propertyInfo in properties)
					{
						if (string.Equals(propertyInfo.Name, "instance", StringComparison.OrdinalIgnoreCase) && propertyInfo.GetIndexParameters().Length == 0 && propertyInfo.CanRead)
						{
							object value = propertyInfo.GetValue(null, null);
							if (value != null)
							{
								return value;
							}
						}
					}
					FieldInfo[] fields = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						if (string.Equals(fieldInfo.Name, "instance", StringComparison.OrdinalIgnoreCase))
						{
							object value2 = fieldInfo.GetValue(null);
							if (value2 != null)
							{
								return value2;
							}
						}
					}
				}
				catch
				{
				}
				type2 = type2.BaseType;
			}
			return null;
		}

		private static ItemDef FindItemDefMember(object instance)
		{
			Type type = instance.GetType();
			try
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (typeof(ItemDef).IsAssignableFrom(fieldInfo.FieldType))
					{
						object? value = fieldInfo.GetValue(instance);
						ItemDef val = (ItemDef)((value is ItemDef) ? value : null);
						if ((Object)(object)val != (Object)null)
						{
							return val;
						}
					}
				}
				PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (PropertyInfo propertyInfo in properties)
				{
					if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0 && typeof(ItemDef).IsAssignableFrom(propertyInfo.PropertyType))
					{
						object? value2 = propertyInfo.GetValue(instance, null);
						ItemDef val2 = (ItemDef)((value2 is ItemDef) ? value2 : null);
						if ((Object)(object)val2 != (Object)null)
						{
							return val2;
						}
					}
				}
			}
			catch
			{
			}
			return null;
		}

		private unsafe static void EnsureNormalizedItems()
		{
			//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_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_0024: Unknown result type (might be due to invalid IL or missing references)
			if (normalizedItems != null)
			{
				return;
			}
			normalizedItems = new Dictionary<string, ItemDef>();
			GenericStaticEnumerable<ItemIndex, AllItemsEnumerator> allItems = ItemCatalog.allItems;
			AllItemsEnumerator enumerator = allItems.GetEnumerator();
			try
			{
				while (((AllItemsEnumerator)(ref enumerator)).MoveNext())
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(((AllItemsEnumerator)(ref enumerator)).Current);
					if (!((Object)(object)itemDef == (Object)null) && !string.IsNullOrEmpty(((Object)itemDef).name))
					{
						string text = NormalizeItemName(((Object)itemDef).name);
						if (text.Length > 0 && !normalizedItems.ContainsKey(text))
						{
							normalizedItems[text] = itemDef;
						}
					}
				}
			}
			finally
			{
				((IDisposable)(*(AllItemsEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose();
			}
		}

		private static string NormalizeItemName(string name)
		{
			string text = Letters(name);
			if (text.StartsWith("ITEM") && text.Length > 4)
			{
				text = text.Substring(4);
			}
			return text;
		}

		private static string NormalizeTypeName(string name)
		{
			string text = Letters(name);
			string[] array = new string[8] { "BODYBEHAVIOR", "BODYBEHAVIOUR", "BEHAVIOURSERVER", "BEHAVIORSERVER", "BEHAVIOUR", "BEHAVIOR", "SERVER", "ITEM" };
			foreach (string text2 in array)
			{
				if (text.EndsWith(text2) && text.Length > text2.Length)
				{
					text = text.Substring(0, text.Length - text2.Length);
					break;
				}
			}
			return text;
		}

		private static string Letters(string value)
		{
			char[] array = new char[value.Length];
			int length = 0;
			foreach (char c in value)
			{
				if (char.IsLetterOrDigit(c))
				{
					array[length++] = char.ToUpperInvariant(c);
				}
			}
			return new string(array, 0, length);
		}
	}
	public static class ModConfig
	{
		private static readonly string[] BuiltinSummonItems = new string[10] { "BeetleGland", "RoboBallBuddy", "TitanGoldDuringTP", "Squid", "GhostOnKill", "Ghost", "MinorConstructOnKill", "VoidMegaCrabItem", "GummyClone", "MinionLeash" };

		private static readonly string[] BuiltinSummonEquipment = new string[1] { "DroneBackup" };

		private static readonly HashSet<string> summonItemSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> summonEquipmentSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public static ConfigEntry<bool> BlockSummonItems = null;

		public static ConfigEntry<bool> BlockSummonEquipment = null;

		public static ConfigEntry<string> ExtraSummonItems = null;

		public static ConfigEntry<string> ExtraSummonEquipment = null;

		public static ConfigEntry<int> MaxInheritingMinionsPerOwner = null;

		public static ConfigEntry<bool> AutoDetectSummoners = null;

		public static ConfigEntry<bool> ProactiveBehaviorScan = null;

		private static readonly HashSet<string> autoSummonSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public static ConfigEntry<string> LearnedSummonItems = null;

		private static readonly HashSet<string> learnedSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		public static ConfigEntry<bool> VerboseLogging = null;

		public static ConfigEntry<bool> DumpItemCodenames = null;

		public static ConfigEntry<bool> ModEnabled = null;

		public static ConfigEntry<bool> LiveSync = null;

		public static ConfigEntry<bool> InheritEquipment = null;

		public static ConfigEntry<float> ItemStackMultiplier = null;

		public static ConfigEntry<int> ItemCountCap = null;

		public static ConfigEntry<bool> InheritModdedOrUnknownTiers = null;

		public static readonly Dictionary<ItemTier, ConfigEntry<bool>> TierConfigs = new Dictionary<ItemTier, ConfigEntry<bool>>();

		public static readonly Dictionary<string, ConfigEntry<bool>> TierDefNameConfigs = new Dictionary<string, ConfigEntry<bool>>(StringComparer.OrdinalIgnoreCase);

		public static ConfigEntry<bool> InheritDronesAndTurrets = null;

		public static ConfigEntry<bool> InheritBeetleGuards = null;

		public static ConfigEntry<bool> InheritAurelionite = null;

		public static ConfigEntry<bool> InheritSolusProbes = null;

		public static ConfigEntry<bool> InheritSquidTurrets = null;

		public static ConfigEntry<bool> InheritGhosts = null;

		public static ConfigEntry<bool> InheritBackupDrones = null;

		public static ConfigEntry<bool> InheritDevoted = null;

		public static ConfigEntry<bool> InheritOtherMinions = null;

		public static ConfigEntry<bool> InheritDios = null;

		public static ConfigEntry<string> BlacklistedItems = null;

		private static readonly HashSet<string> parsedBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static ConfigFile configFile;

		private static bool riskOfOptionsInstalled;

		public static void Init(ConfigFile config)
		{
			configFile = config;
			riskOfOptionsInstalled = Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions");
			ModEnabled = config.Bind<bool>("1. General", "ModEnabled", true, "Enable or disable the SummonInheritance mod.");
			LiveSync = config.Bind<bool>("1. General", "LiveSync", true, "Dynamically update living summons' inventories whenever you pick up new items during a stage.");
			InheritEquipment = config.Bind<bool>("1. General", "InheritEquipment", true, "Whether summons also inherit the player's active equipment.");
			ItemStackMultiplier = config.Bind<float>("1. General", "ItemStackMultiplier", 1f, "Fraction of player's item count given to summons (1.0 = 100%, 0.5 = 50%).");
			ItemCountCap = config.Bind<int>("1. General", "ItemCountCap", 0, "Maximum stacks of any single item granted to a summon (0 = uncapped).");
			InheritModdedOrUnknownTiers = config.Bind<bool>("2. Item Tiers", "InheritModdedOrUnknownTiers", true, "Automatically inherit items belonging to custom modded or uncataloged tiers (e.g. Starstorm 2 Relics, DLC tiers).");
			BindBaseTier(config, (ItemTier)0, "InheritTier_Tier1", "Common (White)");
			BindBaseTier(config, (ItemTier)1, "InheritTier_Tier2", "Uncommon (Green)");
			BindBaseTier(config, (ItemTier)2, "InheritTier_Tier3", "Legendary (Red)");
			BindBaseTier(config, (ItemTier)4, "InheritTier_Boss", "Boss (Yellow)");
			BindBaseTier(config, (ItemTier)3, "InheritTier_Lunar", "Lunar (Blue)");
			BindBaseTier(config, (ItemTier)6, "InheritTier_VoidTier1", "Void Common");
			BindBaseTier(config, (ItemTier)7, "InheritTier_VoidTier2", "Void Uncommon");
			BindBaseTier(config, (ItemTier)8, "InheritTier_VoidTier3", "Void Legendary");
			BindBaseTier(config, (ItemTier)9, "InheritTier_VoidBoss", "Void Boss");
			InheritDronesAndTurrets = config.Bind<bool>("3. Summon Types", "InheritDronesAndTurrets", true, "Inherit items on purchaseable drones and gunner turrets.");
			InheritBeetleGuards = config.Bind<bool>("3. Summon Types", "InheritBeetleGuards", true, "Inherit items on Queen's Gland Beetle Guards.");
			InheritAurelionite = config.Bind<bool>("3. Summon Types", "InheritAurelionite", true, "Inherit items on Halcyon Seed Golden Titan (Aurelionite).");
			InheritSolusProbes = config.Bind<bool>("3. Summon Types", "InheritSolusProbes", true, "Inherit items on Empathy Cores Solus Probes.");
			InheritSquidTurrets = config.Bind<bool>("3. Summon Types", "InheritSquidTurrets", true, "Inherit items on Squid Polyp turrets.");
			InheritGhosts = config.Bind<bool>("3. Summon Types", "InheritGhosts", true, "Inherit items on Happiest Mask ghosts.");
			InheritBackupDrones = config.Bind<bool>("3. Summon Types", "InheritBackupDrones", true, "Inherit items on The Back-up equipment strike drones.");
			InheritDevoted = config.Bind<bool>("3. Summon Types", "InheritDevoted", true, "Inherit items on Devoted Lemurians and Seekers of the Storm allies.");
			InheritOtherMinions = config.Bind<bool>("3. Summon Types", "InheritOtherMinions", true, "Inherit items on any other minion/creature belonging to your team (including modded summons).");
			InheritDios = config.Bind<bool>("4. Safety & Blacklist", "InheritDios", false, "Allow summons to inherit ExtraLife (Dio's Best Friend). Disabled by default to prevent drone revival bugs.");
			BlacklistedItems = config.Bind<string>("4. Safety & Blacklist", "BlacklistedItems", "LunarPrimaryReplacement, LunarSecondaryReplacement, LunarUtilityReplacement, LunarSpecialReplacement, TitanGoldDuringTP, RoboBallBuddy, BeetleGland, MinionLeash, Ghost", "Comma-separated item codenames to blacklist from being given to summons.");
			BlockSummonItems = config.Bind<bool>("5. Loop Protection", "BlockSummonItems", true, "Never copy items that spawn extra drones/allies (Queen's Gland, Defiant Gouge, Zoea, Squid Polyp, Happiest Mask, ...) onto summons. Prevents infinite summon loops. Strongly recommended.");
			BlockSummonEquipment = config.Bind<bool>("5. Loop Protection", "BlockSummonEquipment", true, "Never copy equipment that spawns allies (The Back-up) onto summons. Prevents infinite summon loops. Strongly recommended.");
			ExtraSummonItems = config.Bind<string>("5. Loop Protection", "ExtraSummonItems", "", "Comma-separated extra item codenames that spawn allies (use this for modded items). Added on top of the built-in list.");
			ExtraSummonEquipment = config.Bind<string>("5. Loop Protection", "ExtraSummonEquipment", "", "Comma-separated extra equipment codenames that spawn allies (use this for modded equipment). Added on top of the built-in list.");
			MaxInheritingMinionsPerOwner = config.Bind<int>("5. Loop Protection", "MaxInheritingMinionsPerOwner", 40, "Safety net: maximum number of minions per player that may receive inherited items at the same time (0 = unlimited). Stops runaway spawn loops caused by unknown modded summon items.");
			AutoDetectSummoners = config.Bind<bool>("5. Loop Protection", "AutoDetectSummoners", true, "Behaviour-based detection: if an inheriting minion summons an ally, the new ally is blocked from inheriting and the responsible item is learned automatically (works for modded items, no names needed).");
			ProactiveBehaviorScan = config.Bind<bool>("5. Loop Protection", "ProactiveBehaviorScan", true, "At startup, scan the item-behaviour classes of installed mods; items whose code spawns allies (DirectorCore.TrySpawnObject / MasterSummon) are never inherited, before anything spawns. Detected items are listed in the log.");
			LearnedSummonItems = config.Bind<string>("5. Loop Protection", "LearnedSummonItems", "", "Filled in automatically by AutoDetectSummoners. Comma-separated item codenames learned to spawn allies. You can edit or clear it.");
			VerboseLogging = config.Bind<bool>("5. Loop Protection", "VerboseLogging", false, "Log every item/equipment that gets blocked from inheritance. Useful for testing.");
			DumpItemCodenames = config.Bind<bool>("5. Loop Protection", "DumpItemCodenames", false, "On game load, print the codename of every item and equipment to the BepInEx log so you can find names for the Extra* lists.");
			RebuildSummonSets();
			UpdateBlacklistCache();
			BlacklistedItems.SettingChanged += delegate
			{
				UpdateBlacklistCache();
			};
			ExtraSummonItems.SettingChanged += delegate
			{
				RebuildSummonSets();
			};
			ExtraSummonEquipment.SettingChanged += delegate
			{
				RebuildSummonSets();
			};
			LearnedSummonItems.SettingChanged += delegate
			{
				RebuildSummonSets();
			};
			if (riskOfOptionsInstalled)
			{
				TryRegisterBaseRiskOfOptions();
			}
			((ResourceAvailability)(ref ItemTierCatalog.availability)).CallWhenAvailable((Action)OnItemTierCatalogAvailable);
			((ResourceAvailability)(ref ItemCatalog.availability)).CallWhenAvailable((Action)OnItemCatalogAvailable);
			((ResourceAvailability)(ref EquipmentCatalog.availability)).CallWhenAvailable((Action)OnEquipmentCatalogAvailable);
		}

		private static void RebuildSummonSets()
		{
			summonItemSet.Clear();
			summonEquipmentSet.Clear();
			string[] builtinSummonItems = BuiltinSummonItems;
			foreach (string item in builtinSummonItems)
			{
				summonItemSet.Add(item);
			}
			builtinSummonItems = BuiltinSummonEquipment;
			foreach (string item2 in builtinSummonItems)
			{
				summonEquipmentSet.Add(item2);
			}
			AddCsv((ExtraSummonItems != null) ? ExtraSummonItems.Value : null, summonItemSet);
			learnedSet.Clear();
			AddCsv((LearnedSummonItems != null) ? LearnedSummonItems.Value : null, learnedSet);
			foreach (string item3 in learnedSet)
			{
				summonItemSet.Add(item3);
			}
			AddCsv((ExtraSummonEquipment != null) ? ExtraSummonEquipment.Value : null, summonEquipmentSet);
		}

		private static void AddCsv(string csv, HashSet<string> target)
		{
			if (string.IsNullOrWhiteSpace(csv))
			{
				return;
			}
			string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					target.Add(text);
				}
			}
		}

		public static bool IsSummonItemName(string name)
		{
			if (!summonItemSet.Contains(name))
			{
				return autoSummonSet.Contains(name);
			}
			return true;
		}

		public static void AddAutoSummonItem(string name)
		{
			if (!string.IsNullOrEmpty(name))
			{
				autoSummonSet.Add(name);
			}
		}

		public static void LearnSummonItem(string name)
		{
			if (!string.IsNullOrEmpty(name) && !summonItemSet.Contains(name))
			{
				summonItemSet.Add(name);
				learnedSet.Add(name);
				LearnedSummonItems.Value = string.Join(", ", learnedSet);
			}
		}

		public static bool IsSummonItem(ItemDef itemDef)
		{
			if ((Object)(object)itemDef == (Object)null || BlockSummonItems == null || !BlockSummonItems.Value)
			{
				return false;
			}
			if (!summonItemSet.Contains(((Object)itemDef).name))
			{
				return autoSummonSet.Contains(((Object)itemDef).name);
			}
			return true;
		}

		public static bool IsSummonEquipment(EquipmentIndex index)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if ((int)index == -1 || BlockSummonEquipment == null || !BlockSummonEquipment.Value)
			{
				return false;
			}
			EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(index);
			if ((Object)(object)equipmentDef != (Object)null)
			{
				return summonEquipmentSet.Contains(((Object)equipmentDef).name);
			}
			return false;
		}

		private unsafe static void OnItemCatalogAvailable()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				List<string> list = new List<string>();
				foreach (string item in summonItemSet)
				{
					if ((int)ItemCatalog.FindItemIndex(item) == -1)
					{
						list.Add(item);
					}
				}
				if (list.Count > 0)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("Loop protection: these summon-item names were not found in the item catalog (harmless, may be renamed or from a mod that is not installed): " + string.Join(", ", list)));
				}
				else
				{
					SummonInheritancePlugin.Log.LogInfo((object)("Loop protection: all " + summonItemSet.Count + " summon-item names resolved."));
				}
				if (DumpItemCodenames.Value)
				{
					List<string> list2 = new List<string>();
					GenericStaticEnumerable<ItemIndex, AllItemsEnumerator> allItems = ItemCatalog.allItems;
					AllItemsEnumerator enumerator2 = allItems.GetEnumerator();
					try
					{
						while (((AllItemsEnumerator)(ref enumerator2)).MoveNext())
						{
							ItemDef itemDef = ItemCatalog.GetItemDef(((AllItemsEnumerator)(ref enumerator2)).Current);
							if ((Object)(object)itemDef != (Object)null)
							{
								list2.Add(((Object)itemDef).name);
							}
						}
					}
					finally
					{
						((IDisposable)(*(AllItemsEnumerator*)(&enumerator2))/*cast due to .constrained prefix*/).Dispose();
					}
					SummonInheritancePlugin.Log.LogInfo((object)("ITEM CODENAMES: " + string.Join(", ", list2)));
				}
				if (ProactiveBehaviorScan.Value)
				{
					ItemBehaviorScanner.Run();
				}
			}
			catch (Exception ex)
			{
				SummonInheritancePlugin.Log.LogWarning((object)("Item catalog check failed: " + ex));
			}
		}

		private static void OnEquipmentCatalogAvailable()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			try
			{
				List<string> list = new List<string>();
				foreach (string item in summonEquipmentSet)
				{
					if ((int)EquipmentCatalog.FindEquipmentIndex(item) == -1)
					{
						list.Add(item);
					}
				}
				if (list.Count > 0)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("Loop protection: these summon-equipment names were not found in the equipment catalog: " + string.Join(", ", list)));
				}
				else
				{
					SummonInheritancePlugin.Log.LogInfo((object)("Loop protection: all " + summonEquipmentSet.Count + " summon-equipment names resolved."));
				}
				if (!DumpItemCodenames.Value)
				{
					return;
				}
				List<string> list2 = new List<string>();
				for (int i = 0; i < EquipmentCatalog.equipmentCount; i++)
				{
					EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef((EquipmentIndex)i);
					if ((Object)(object)equipmentDef != (Object)null)
					{
						list2.Add(((Object)equipmentDef).name);
					}
				}
				SummonInheritancePlugin.Log.LogInfo((object)("EQUIPMENT CODENAMES: " + string.Join(", ", list2)));
			}
			catch (Exception ex)
			{
				SummonInheritancePlugin.Log.LogWarning((object)("Equipment catalog check failed: " + ex));
			}
		}

		private static void BindBaseTier(ConfigFile config, ItemTier tier, string key, string name)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<bool> value = config.Bind<bool>("2. Item Tiers", key, true, "Inherit " + name + " items.");
			TierConfigs[tier] = value;
			TierDefNameConfigs[key] = value;
		}

		private static void OnItemTierCatalogAvailable()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			if (configFile == null)
			{
				return;
			}
			try
			{
				Enumerator<ItemTierDef> enumerator = ItemTierCatalog.allItemTierDefs.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						ItemTierDef current = enumerator.Current;
						if ((Object)(object)current == (Object)null)
						{
							continue;
						}
						string name = ((Object)current).name;
						if (string.IsNullOrEmpty(name))
						{
							continue;
						}
						string text = name.Replace("Def", "").Trim();
						string text2 = "InheritTier_" + text;
						ConfigEntry<bool> value;
						if (!TierDefNameConfigs.ContainsKey(name) && !TierDefNameConfigs.ContainsKey(text2))
						{
							ConfigEntry<bool> val = configFile.Bind<bool>("2. Item Tiers", text2, true, "Dynamically discovered tier: Inherit " + text + " items.");
							TierConfigs[current.tier] = val;
							TierDefNameConfigs[name] = val;
							TierDefNameConfigs[text2] = val;
							if (riskOfOptionsInstalled)
							{
								TryRegisterOption((BaseOption)new CheckBoxOption(val));
							}
							Debug.Log((object)$"[SummonInheritance] Dynamically registered tier: {text} ({current.tier})");
						}
						else if (TierConfigs.TryGetValue(current.tier, out value))
						{
							TierDefNameConfigs[name] = value;
						}
					}
				}
				finally
				{
					((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
				}
			}
			catch (Exception arg)
			{
				Debug.LogWarning((object)$"[SummonInheritance] Error scanning ItemTierCatalog: {arg}");
			}
		}

		public static bool IsTierAllowed(ItemDef itemDef)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)itemDef == (Object)null)
			{
				return false;
			}
			if ((int)itemDef.tier == 5)
			{
				return false;
			}
			try
			{
				ItemTierDef itemTierDef = ItemTierCatalog.GetItemTierDef(itemDef.tier);
				if ((Object)(object)itemTierDef != (Object)null && !string.IsNullOrEmpty(((Object)itemTierDef).name) && TierDefNameConfigs.TryGetValue(((Object)itemTierDef).name, out var value))
				{
					return value.Value;
				}
			}
			catch
			{
			}
			if (TierConfigs.TryGetValue(itemDef.tier, out var value2))
			{
				return value2.Value;
			}
			return InheritModdedOrUnknownTiers.Value;
		}

		private static void UpdateBlacklistCache()
		{
			parsedBlacklist.Clear();
			if (!string.IsNullOrWhiteSpace(BlacklistedItems.Value))
			{
				string[] array = BlacklistedItems.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text in array)
				{
					parsedBlacklist.Add(text.Trim());
				}
			}
		}

		public static bool IsItemBlacklisted(string itemName)
		{
			return parsedBlacklist.Contains(itemName);
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void TryRegisterBaseRiskOfOptions()
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Expected O, but got Unknown
			//IL_012e: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Expected O, but got Unknown
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Expected O, but got Unknown
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Expected O, but got Unknown
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Expected O, but got Unknown
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Expected O, but got Unknown
			//IL_0269: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Expected O, but got Unknown
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Expected O, but got Unknown
			try
			{
				ModSettingsManager.SetModDescription("Allows all summoned minions, drones, turrets, and allied creatures in your team to inherit your items and equipment.", "com.SummonInheritanceFix.Fork", "SummonInheritanceFix");
				try
				{
					using Stream stream = typeof(ModConfig).Assembly.GetManifestResourceStream("SummonInheritanceFix.icon.png");
					if (stream != null)
					{
						byte[] array = new byte[stream.Length];
						stream.Read(array, 0, array.Length);
						Texture2D val = new Texture2D(256, 256, (TextureFormat)4, false);
						if (ImageConversion.LoadImage(val, array))
						{
							ModSettingsManager.SetModIcon(Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)), "com.SummonInheritanceFix.Fork", "SummonInheritanceFix");
						}
					}
				}
				catch (Exception arg)
				{
					Debug.LogWarning((object)$"[SummonInheritance] Failed to load embedded icon: {arg}");
				}
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ModEnabled));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(LiveSync));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritEquipment));
				ModSettingsManager.AddOption((BaseOption)new StepSliderOption(ItemStackMultiplier, new StepSliderConfig
				{
					min = 0.1f,
					max = 2f,
					increment = 0.1f
				}));
				ModSettingsManager.AddOption((BaseOption)new IntSliderOption(ItemCountCap, new IntSliderConfig
				{
					min = 0,
					max = 50
				}));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritModdedOrUnknownTiers));
				foreach (KeyValuePair<ItemTier, ConfigEntry<bool>> tierConfig in TierConfigs)
				{
					ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(tierConfig.Value));
				}
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritDronesAndTurrets));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritBeetleGuards));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritAurelionite));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritSolusProbes));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritSquidTurrets));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritGhosts));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritBackupDrones));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritDevoted));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritOtherMinions));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(InheritDios));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(BlockSummonItems));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(BlockSummonEquipment));
				ModSettingsManager.AddOption((BaseOption)new IntSliderOption(MaxInheritingMinionsPerOwner, new IntSliderConfig
				{
					min = 0,
					max = 100
				}));
				ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(VerboseLogging));
			}
			catch (Exception arg2)
			{
				Debug.LogWarning((object)$"[SummonInheritance] Failed to register base RiskOfOptions: {arg2}");
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
		private static void TryRegisterOption(BaseOption option)
		{
			try
			{
				ModSettingsManager.AddOption(option);
			}
			catch (Exception arg)
			{
				Debug.LogWarning((object)$"[SummonInheritance] Failed to register dynamic option: {arg}");
			}
		}
	}
	[BepInPlugin("com.SummonInheritanceFix.Fork", "SummonInheritanceFix", "1.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInIncompatibility("com.Antigravity.SummonInheritance")]
	public class SummonInheritancePlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.SummonInheritanceFix.Fork";

		public const string PluginName = "SummonInheritanceFix";

		public const string PluginVersion = "1.3.0";

		internal static ManualLogSource Log;

		private static readonly List<MinionInheritanceSync> ActiveMinions = new List<MinionInheritanceSync>();

		private static float nextCapWarningTime;

		public static SummonInheritancePlugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			SummonWatcher.Install();
			MinionOwnership.onMinionOwnerChangedGlobal += OnMinionOwnerChanged;
			CharacterMaster.onStartGlobal += OnMasterStart;
			Inventory.onInventoryChangedGlobal += OnInventoryChanged;
			Stage.onStageStartGlobal += OnStageStart;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SummonInheritance v1.3.0 initialized (dynamic tiers + summon-loop protection).");
		}

		private void OnDestroy()
		{
			MinionOwnership.onMinionOwnerChangedGlobal -= OnMinionOwnerChanged;
			CharacterMaster.onStartGlobal -= OnMasterStart;
			Inventory.onInventoryChangedGlobal -= OnInventoryChanged;
			Stage.onStageStartGlobal -= OnStageStart;
		}

		private void OnMasterStart(CharacterMaster master)
		{
			if (NetworkServer.active && ModConfig.ModEnabled.Value && (Object)(object)master != (Object)null)
			{
				((MonoBehaviour)this).StartCoroutine(CheckAndAttachSync(master));
			}
		}

		private void OnMinionOwnerChanged(MinionOwnership minionOwnership)
		{
			if (NetworkServer.active && ModConfig.ModEnabled.Value && (Object)(object)minionOwnership != (Object)null)
			{
				CharacterMaster component = ((Component)minionOwnership).GetComponent<CharacterMaster>();
				if ((Object)(object)component != (Object)null)
				{
					((MonoBehaviour)this).StartCoroutine(CheckAndAttachSync(component));
				}
			}
		}

		private IEnumerator CheckAndAttachSync(CharacterMaster master)
		{
			yield return null;
			if ((Object)(object)master == (Object)null || (Object)(object)master.inventory == (Object)null || (Object)(object)((Component)master).GetComponent<MinionInheritanceSync>() != (Object)null || (Object)(object)((Component)master).GetComponent<NoInheritMarker>() != (Object)null || !ShouldInherit(master, out var ownerMaster) || (Object)(object)ownerMaster == (Object)null)
			{
				yield break;
			}
			int value = ModConfig.MaxInheritingMinionsPerOwner.Value;
			if (value > 0 && CountInheritingMinions(ownerMaster) >= value)
			{
				if (Time.unscaledTime >= nextCapWarningTime)
				{
					nextCapWarningTime = Time.unscaledTime + 10f;
					Log.LogWarning((object)("Inheriting-minion cap (" + value + ") reached for one player; new minions will not inherit items until some die. If this keeps happening, a modded item may be spawning allies: add its codename to ExtraSummonItems."));
				}
			}
			else
			{
				((Component)master).gameObject.AddComponent<MinionInheritanceSync>().Initialize(master, ownerMaster);
			}
		}

		public static void RequestSyncAll()
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(SyncAllNextFrame());
			}
		}

		private static IEnumerator SyncAllNextFrame()
		{
			yield return null;
			ActiveMinions.RemoveAll((MinionInheritanceSync m) => (Object)(object)m == (Object)null);
			MinionInheritanceSync[] array = ActiveMinions.ToArray();
			foreach (MinionInheritanceSync minionInheritanceSync in array)
			{
				if ((Object)(object)minionInheritanceSync != (Object)null)
				{
					minionInheritanceSync.Sync();
				}
			}
		}

		private static int CountInheritingMinions(CharacterMaster owner)
		{
			int num = 0;
			for (int i = 0; i < ActiveMinions.Count; i++)
			{
				MinionInheritanceSync minionInheritanceSync = ActiveMinions[i];
				if ((Object)(object)minionInheritanceSync != (Object)null && (Object)(object)minionInheritanceSync.OwnerMaster == (Object)(object)owner)
				{
					num++;
				}
			}
			return num;
		}

		private static void OnStageStart(Stage stage)
		{
			if (!NetworkServer.active || !ModConfig.ModEnabled.Value)
			{
				return;
			}
			ActiveMinions.RemoveAll((MinionInheritanceSync m) => (Object)(object)m == (Object)null);
			MinionInheritanceSync[] array = ActiveMinions.ToArray();
			foreach (MinionInheritanceSync minionInheritanceSync in array)
			{
				if ((Object)(object)minionInheritanceSync != (Object)null)
				{
					minionInheritanceSync.Sync();
				}
			}
		}

		private static void OnInventoryChanged(Inventory inventory)
		{
			if (!NetworkServer.active || !ModConfig.ModEnabled.Value || !ModConfig.LiveSync.Value || (Object)(object)inventory == (Object)null)
			{
				return;
			}
			ActiveMinions.RemoveAll((MinionInheritanceSync m) => (Object)(object)m == (Object)null);
			MinionInheritanceSync[] array = ActiveMinions.ToArray();
			foreach (MinionInheritanceSync minionInheritanceSync in array)
			{
				if ((Object)(object)minionInheritanceSync != (Object)null && (Object)(object)minionInheritanceSync.OwnerMaster != (Object)null && (Object)(object)minionInheritanceSync.OwnerMaster.inventory == (Object)(object)inventory)
				{
					minionInheritanceSync.Sync();
				}
			}
		}

		public static void RegisterMinion(MinionInheritanceSync sync)
		{
			if (!ActiveMinions.Contains(sync))
			{
				ActiveMinions.Add(sync);
			}
		}

		public static void UnregisterMinion(MinionInheritanceSync sync)
		{
			ActiveMinions.Remove(sync);
		}

		private static bool HasBodyFlag(CharacterBody body, long mask)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)body != (Object)null)
			{
				return ((ulong)body.bodyFlags & (ulong)mask) != 0;
			}
			return false;
		}

		private static bool HasItemByName(Inventory inventory, string codename)
		{
			//IL_000c: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)inventory == (Object)null)
			{
				return false;
			}
			ItemIndex val = ItemCatalog.FindItemIndex(codename);
			if ((int)val != -1)
			{
				return inventory.GetItemCountPermanent(val) > 0;
			}
			return false;
		}

		public static bool ShouldInherit(CharacterMaster minionMaster, out CharacterMaster ownerMaster)
		{
			ownerMaster = null;
			if (!ModConfig.ModEnabled.Value || (Object)(object)minionMaster == (Object)null || (Object)(object)minionMaster.inventory == (Object)null)
			{
				return false;
			}
			MinionOwnership minionOwnership = minionMaster.minionOwnership;
			if ((Object)(object)minionOwnership == (Object)null || (Object)(object)minionOwnership.ownerMaster == (Object)null)
			{
				return false;
			}
			ownerMaster = minionOwnership.ownerMaster;
			if ((Object)(object)ownerMaster == (Object)(object)minionMaster)
			{
				return false;
			}
			if ((Object)(object)ownerMaster.playerCharacterMasterController == (Object)null)
			{
				return false;
			}
			string text = (((Object)(object)minionMaster.bodyPrefab != (Object)null) ? ((Object)minionMaster.bodyPrefab).name : "");
			CharacterBody body = minionMaster.GetBody();
			if (string.IsNullOrEmpty(text) && (Object)(object)body != (Object)null)
			{
				text = ((Object)body).name;
			}
			string text2 = ((Object)minionMaster).name ?? "";
			if (text.Contains("EngiTurret") || text.Contains("EngiWalkerTurret") || text2.Contains("EngiTurret") || text2.Contains("EngiWalkerTurret"))
			{
				return false;
			}
			if (text.Contains("DroneBackup") || text2.Contains("DroneBackup"))
			{
				return ModConfig.InheritBackupDrones.Value;
			}
			if (((Object)(object)body != (Object)null && (HasBodyFlag(body, 4194304L) || HasBodyFlag(body, 33554432L))) || text.Contains("Drone") || text.Contains("Turret") || text2.Contains("Drone") || text2.Contains("Turret"))
			{
				return ModConfig.InheritDronesAndTurrets.Value;
			}
			if (text.Contains("BeetleGuard") || text2.Contains("BeetleGuard"))
			{
				return ModConfig.InheritBeetleGuards.Value;
			}
			if (text.Contains("TitanGold") || text2.Contains("TitanGold"))
			{
				return ModConfig.InheritAurelionite.Value;
			}
			if (text.Contains("RoboBall") || text.Contains("Solus") || text2.Contains("RoboBall") || text2.Contains("Solus"))
			{
				return ModConfig.InheritSolusProbes.Value;
			}
			if (text.Contains("SquidTurret") || text2.Contains("SquidTurret"))
			{
				return ModConfig.InheritSquidTurrets.Value;
			}
			if (HasItemByName(minionMaster.inventory, "Ghost") || text.Contains("Ghost") || text2.Contains("Ghost"))
			{
				return ModConfig.InheritGhosts.Value;
			}
			if (((Object)(object)body != (Object)null && HasBodyFlag(body, 8192L)) || text.Contains("Devotion") || text2.Contains("Devotion") || text.Contains("LemurianBruiser"))
			{
				return ModConfig.InheritDevoted.Value;
			}
			return ModConfig.InheritOtherMinions.Value;
		}
	}
	public class MinionInheritanceSync : MonoBehaviour
	{
		private bool syncing;

		private readonly Dictionary<ItemIndex, int> given = new Dictionary<ItemIndex, int>();

		public CharacterMaster MinionMaster { get; private set; }

		public CharacterMaster OwnerMaster { get; private set; }

		public HashSet<string> GetInheritedItemNames()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (KeyValuePair<ItemIndex, int> item in given)
			{
				if (item.Value > 0)
				{
					ItemDef itemDef = ItemCatalog.GetItemDef(item.Key);
					if ((Object)(object)itemDef != (Object)null)
					{
						hashSet.Add(((Object)itemDef).name);
					}
				}
			}
			return hashSet;
		}

		public void Initialize(CharacterMaster minion, CharacterMaster owner)
		{
			MinionMaster = minion;
			OwnerMaster = owner;
			SummonInheritancePlugin.RegisterMinion(this);
			Sync();
		}

		private void OnDestroy()
		{
			SummonInheritancePlugin.UnregisterMinion(this);
		}

		public unsafe void Sync()
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Invalid comparison between Unknown and I4
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Invalid comparison between Unknown and I4
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Invalid comparison between Unknown and I4
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			if (syncing || !NetworkServer.active || !ModConfig.ModEnabled.Value || (Object)(object)MinionMaster == (Object)null || (Object)(object)MinionMaster.inventory == (Object)null || (Object)(object)OwnerMaster == (Object)null || (Object)(object)OwnerMaster.inventory == (Object)null)
			{
				return;
			}
			syncing = true;
			try
			{
				Inventory inventory = OwnerMaster.inventory;
				Inventory inventory2 = MinionMaster.inventory;
				float num = Mathf.Clamp(ModConfig.ItemStackMultiplier.Value, 0.05f, 5f);
				int value = ModConfig.ItemCountCap.Value;
				GenericStaticEnumerable<ItemIndex, AllItemsEnumerator> allItems = ItemCatalog.allItems;
				AllItemsEnumerator enumerator = allItems.GetEnumerator();
				try
				{
					while (((AllItemsEnumerator)(ref enumerator)).MoveNext())
					{
						ItemIndex current = ((AllItemsEnumerator)(ref enumerator)).Current;
						ItemDef itemDef = ItemCatalog.GetItemDef(current);
						if ((Object)(object)itemDef == (Object)null)
						{
							continue;
						}
						if (IsBlacklisted(itemDef))
						{
							if (given.TryGetValue(current, out var value2) && value2 > 0)
							{
								int itemCountPermanent = inventory2.GetItemCountPermanent(current);
								int num2 = Mathf.Min(value2, itemCountPermanent);
								if (num2 > 0)
								{
									inventory2.RemoveItemPermanent(current, num2);
								}
								given.Remove(current);
							}
						}
						else
						{
							if (!ModConfig.IsTierAllowed(itemDef))
							{
								continue;
							}
							int itemCountPermanent2 = inventory.GetItemCountPermanent(current);
							int num3 = 0;
							if (itemCountPermanent2 > 0)
							{
								num3 = Mathf.Max(1, Mathf.FloorToInt((float)itemCountPermanent2 * num));
								if (value > 0)
								{
									num3 = Mathf.Min(num3, value);
								}
							}
							int itemCountPermanent3 = inventory2.GetItemCountPermanent(current);
							if (itemCountPermanent3 < num3)
							{
								inventory2.GiveItemPermanent(current, num3 - itemCountPermanent3);
								given.TryGetValue(current, out var value3);
								given[current] = value3 + (num3 - itemCountPermanent3);
							}
							else if (itemCountPermanent3 > num3)
							{
								inventory2.RemoveItemPermanent(current, itemCountPermanent3 - num3);
								given.TryGetValue(current, out var value4);
								given[current] = Mathf.Max(0, value4 - (itemCountPermanent3 - num3));
							}
						}
					}
				}
				finally
				{
					((IDisposable)(*(AllItemsEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose();
				}
				if (!ModConfig.InheritEquipment.Value)
				{
					return;
				}
				EquipmentIndex currentEquipmentIndex = inventory.currentEquipmentIndex;
				if ((int)currentEquipmentIndex != -1 && ModConfig.IsSummonEquipment(currentEquipmentIndex))
				{
					if (ModConfig.VerboseLogging.Value)
					{
						SummonInheritancePlugin.Log.LogInfo((object)("Blocked summon equipment from inheritance: " + ((Object)EquipmentCatalog.GetEquipmentDef(currentEquipmentIndex)).name));
					}
				}
				else if ((int)currentEquipmentIndex != -1 && (((!((Object)(object)MinionMaster.bodyPrefab != (Object)null) || !((Object)MinionMaster.bodyPrefab).name.Contains("EquipmentDrone")) && !((Object)MinionMaster).name.Contains("EquipmentDrone")) || (int)inventory2.currentEquipmentIndex == -1) && inventory2.currentEquipmentIndex != currentEquipmentIndex)
				{
					inventory2.SetEquipmentIndex(currentEquipmentIndex);
				}
			}
			finally
			{
				syncing = false;
			}
		}

		private static bool IsBlacklisted(ItemDef itemDef)
		{
			if (itemDef.ContainsTag((ItemTag)13))
			{
				return true;
			}
			if (ModConfig.IsSummonItem(itemDef))
			{
				if (ModConfig.VerboseLogging.Value)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("Blocked summon item from inheritance: " + ((Object)itemDef).name));
				}
				return true;
			}
			if (((Object)itemDef).name == "LunarPrimaryReplacement" || ((Object)itemDef).name == "LunarSecondaryReplacement" || ((Object)itemDef).name == "LunarUtilityReplacement" || ((Object)itemDef).name == "LunarSpecialReplacement")
			{
				return true;
			}
			if ((((Object)itemDef).name == "ExtraLife" || ((Object)itemDef).name == "ExtraLifeVoid") && !ModConfig.InheritDios.Value)
			{
				return true;
			}
			if (((Object)itemDef).name == "Ghost")
			{
				return true;
			}
			if (ModConfig.IsItemBlacklisted(((Object)itemDef).name))
			{
				return true;
			}
			return false;
		}
	}
	public class NoInheritMarker : MonoBehaviour
	{
	}
	public static class SummonWatcher
	{
		private static FieldInfo summonerBodyField;

		private const int MaxCulpritsToLearn = 4;

		private static float nextDiagTime;

		public static void Install()
		{
			//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_0080: Expected O, but got Unknown
			try
			{
				MethodBase methodBase = AccessTools.Method(typeof(MasterSummon), "Perform", (Type[])null, (Type[])null);
				summonerBodyField = AccessTools.Field(typeof(MasterSummon), "summonerBodyObject");
				if (methodBase == null || summonerBodyField == null)
				{
					SummonInheritancePlugin.Log.LogWarning((object)"SummonWatcher: MasterSummon.Perform / summonerBodyObject not found in this game version. Auto-detection disabled (name-based protection still active).");
					return;
				}
				new Harmony("com.SummonInheritanceFix.Fork.watcher").Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(typeof(SummonWatcher), "PerformPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				SummonInheritancePlugin.Log.LogInfo((object)"SummonWatcher: patched MasterSummon.Perform.");
			}
			catch (Exception ex)
			{
				SummonInheritancePlugin.Log.LogWarning((object)("SummonWatcher install failed: " + ex));
			}
		}

		private static void PerformPostfix(object __instance, CharacterMaster __result)
		{
			try
			{
				if (!ModConfig.ModEnabled.Value || !ModConfig.AutoDetectSummoners.Value || (Object)(object)__result == (Object)null || __instance == null)
				{
					return;
				}
				object? value = summonerBodyField.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				CharacterBody component = val.GetComponent<CharacterBody>();
				CharacterMaster val2 = (((Object)(object)component != (Object)null) ? component.master : null);
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				MinionInheritanceSync component2 = ((Component)val2).GetComponent<MinionInheritanceSync>();
				if ((Object)(object)component2 == (Object)null)
				{
					return;
				}
				if ((Object)(object)((Component)__result).GetComponent<NoInheritMarker>() == (Object)null)
				{
					((Component)__result).gameObject.AddComponent<NoInheritMarker>();
				}
				MinionInheritanceSync component3 = ((Component)__result).GetComponent<MinionInheritanceSync>();
				if ((Object)(object)component3 != (Object)null)
				{
					Object.Destroy((Object)(object)component3);
				}
				HashSet<string> inheritedItemNames = component2.GetInheritedItemNames();
				if (inheritedItemNames.Count == 0)
				{
					return;
				}
				List<string> list = new List<string>();
				HashSet<string> hashSet = FindItemsReferencedByCaller(list);
				List<string> list2 = new List<string>();
				foreach (string item in hashSet)
				{
					if (inheritedItemNames.Contains(item) && !ModConfig.IsSummonItemName(item))
					{
						list2.Add(item);
					}
				}
				if (list2.Count == 0)
				{
					SummonInheritancePlugin.Log.LogInfo((object)"SummonWatcher: an inheriting minion summoned an ally, but no inherited item could be attributed. The new ally was blocked from inheriting.");
					if (!(Time.unscaledTime >= nextDiagTime))
					{
						return;
					}
					nextDiagTime = Time.unscaledTime + 15f;
					SummonInheritancePlugin.Log.LogInfo((object)("SummonWatcher DIAG: spawned master = " + ((Object)__result).name + "; summoner master = " + ((Object)val2).name + "; inherited items = " + inheritedItemNames.Count + "; ItemDefs found in caller IL = [" + string.Join(", ", hashSet) + "]"));
					{
						foreach (string item2 in list)
						{
							SummonInheritancePlugin.Log.LogInfo((object)("SummonWatcher DIAG: frame " + item2));
						}
						return;
					}
				}
				if (list2.Count > 4)
				{
					SummonInheritancePlugin.Log.LogInfo((object)("SummonWatcher: summon attribution ambiguous (" + list2.Count + " candidates), not learning. New ally was blocked from inheriting. Candidates: " + string.Join(", ", list2)));
					return;
				}
				foreach (string item3 in list2)
				{
					ModConfig.LearnSummonItem(item3);
					SummonInheritancePlugin.Log.LogInfo((object)("SummonWatcher: learned summon item '" + item3 + "' (it will no longer be inherited)."));
				}
				SummonInheritancePlugin.RequestSyncAll();
			}
			catch (Exception ex)
			{
				SummonInheritancePlugin.Log.LogWarning((object)("SummonWatcher postfix error: " + ex));
			}
		}

		private static HashSet<string> FindItemsReferencedByCaller(List<string> diag)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			StackTrace stackTrace = new StackTrace(fNeedFileInfo: false);
			int num = 0;
			for (int i = 0; i < stackTrace.FrameCount && i < 20; i++)
			{
				if (num >= 8)
				{
					break;
				}
				MethodBase method = stackTrace.GetFrame(i).GetMethod();
				if (method == null || method.DeclaringType == null)
				{
					diag.Add("#" + i + " <unresolved>");
					continue;
				}
				Assembly assembly = method.DeclaringType.Assembly;
				string name = assembly.GetName().Name;
				if (assembly == typeof(SummonWatcher).Assembly)
				{
					continue;
				}
				switch (name)
				{
				case "mscorlib":
				case "System":
				case "System.Core":
				case "0Harmony":
				case "MonoMod.Utils":
				case "MonoMod.RuntimeDetour":
					continue;
				}
				if (!name.StartsWith("UnityEngine") && !name.StartsWith("Unity.") && !name.StartsWith("DMDASM") && !name.StartsWith("DMD<") && !(method.DeclaringType == typeof(MasterSummon)))
				{
					num++;
					int count = hashSet.Count;
					CollectItemFields(method, hashSet);
					diag.Add("#" + i + " " + method.DeclaringType.FullName + "." + method.Name + " [" + name + "] new ItemDefs: " + (hashSet.Count - count));
				}
			}
			Type itemBehaviorType = ItemBehaviorScanner.ItemBehaviorType;
			if (itemBehaviorType != null)
			{
				for (int j = 0; j < stackTrace.FrameCount && j < 40; j++)
				{
					MethodBase method2 = stackTrace.GetFrame(j).GetMethod();
					Type type = ((method2 != null) ? method2.DeclaringType : null);
					while (type != null)
					{
						if (type != itemBehaviorType && itemBehaviorType.IsAssignableFrom(type))
						{
							ItemDef val = ItemBehaviorScanner.ResolveItemDef(type);
							diag.Add("#" + j + " ItemBehavior " + type.FullName + " -> " + (((Object)(object)val != (Object)null) ? ((Object)val).name : "unresolved"));
							if ((Object)(object)val != (Object)null)
							{
								hashSet.Add(((Object)val).name);
							}
							break;
						}
						type = type.DeclaringType;
					}
				}
			}
			return hashSet;
		}

		private static void CollectItemFields(MethodBase method, HashSet<string> into)
		{
			try
			{
				MethodBody methodBody = method.GetMethodBody();
				if (methodBody == null)
				{
					return;
				}
				byte[] iLAsByteArray = methodBody.GetILAsByteArray();
				if (iLAsByteArray == null)
				{
					return;
				}
				Module module = method.Module;
				Type[] genericTypeArguments = ((method.DeclaringType != null && method.DeclaringType.IsGenericType) ? method.DeclaringType.GetGenericArguments() : null);
				Type[] genericMethodArguments = (method.IsGenericMethod ? method.GetGenericArguments() : null);
				for (int i = 0; i < iLAsByteArray.Length - 4; i++)
				{
					if (iLAsByteArray[i] != 126)
					{
						continue;
					}
					int num = BitConverter.ToInt32(iLAsByteArray, i + 1);
					if (num >> 24 != 4)
					{
						continue;
					}
					try
					{
						FieldInfo fieldInfo = module.ResolveField(num, genericTypeArguments, genericMethodArguments);
						if (fieldInfo != null && fieldInfo.IsStatic && typeof(ItemDef).IsAssignableFrom(fieldInfo.FieldType))
						{
							object? value = fieldInfo.GetValue(null);
							ItemDef val = (ItemDef)((value is ItemDef) ? value : null);
							if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name))
							{
								into.Add(((Object)val).name);
							}
						}
					}
					catch
					{
					}
				}
			}
			catch
			{
			}
		}
	}
}