Decompiled source of EnemyDrops v1.1.0

EnemyDrops.dll

Decompiled 12 hours ago
using System;
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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EnemyDrops.Configuration;
using EnemyDrops.Providers;
using EnemyDrops.Reflection;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("osmarbriones")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+c458c9b3adc5b4736c659b2d864053766b54a4d2")]
[assembly: AssemblyProduct("EnemyDrops")]
[assembly: AssemblyTitle("EnemyDrops")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace EnemyDrops
{
	internal static class DroppedInstanceTracker
	{
		private static readonly HashSet<string> s_droppedInstances = new HashSet<string>();

		public static void MarkDropped(GameObject go)
		{
			if (Object.op_Implicit((Object)(object)go) && !Object.op_Implicit((Object)(object)go.GetComponent<DroppedItemTag>()))
			{
				go.AddComponent<DroppedItemTag>();
			}
		}

		public static void RegisterInstance(string instanceName)
		{
			if (!string.IsNullOrEmpty(instanceName) && s_droppedInstances.Add(instanceName))
			{
				EnemyDrops.Logger.LogDebug((object)("EnemyDrops: Registered dropped instance '" + instanceName + "'."));
			}
		}

		public static bool IsDropped(string instanceName)
		{
			return !string.IsNullOrEmpty(instanceName) && s_droppedInstances.Contains(instanceName);
		}

		public static void ClearBatteriesForDroppedInstances()
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				EnemyDrops.Logger.LogWarning((object)"EnemyDrops: StatsManager.instance is null; cannot clear dropped instances.");
				return;
			}
			if (instance.item == null || instance.itemStatBattery == null)
			{
				EnemyDrops.Logger.LogWarning((object)"EnemyDrops: StatsManager item tables are null; cannot clear dropped instances.");
				ClearForNewLevel();
				return;
			}
			List<string> list = new List<string>(s_droppedInstances);
			List<string> list2 = new List<string>();
			for (int i = 0; i < list.Count; i++)
			{
				string text = list[i];
				if (!string.IsNullOrEmpty(text))
				{
					if (instance.item.ContainsKey(text))
					{
						instance.item.Remove(text);
					}
					if (instance.itemStatBattery.ContainsKey(text))
					{
						instance.itemStatBattery.Remove(text);
					}
					list2.Add(text);
				}
			}
			if (list2.Count > 0)
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("EnemyDrops: Removed dropped instances from item + itemStatBattery:");
				for (int j = 0; j < list2.Count; j++)
				{
					stringBuilder.AppendLine("  " + list2[j]);
				}
				EnemyDrops.Logger.LogInfo((object)stringBuilder.ToString());
			}
			else
			{
				EnemyDrops.Logger.LogDebug((object)"EnemyDrops: No dropped instances found to remove.");
			}
			ClearForNewLevel();
		}

		public static void ClearForNewLevel()
		{
			if (s_droppedInstances.Count > 0)
			{
				EnemyDrops.Logger.LogDebug((object)$"EnemyDrops: Clearing dropped-instance tracker ({s_droppedInstances.Count} entries).");
			}
			s_droppedInstances.Clear();
		}
	}
	public sealed class DroppedItemTag : MonoBehaviour
	{
	}
	[BepInPlugin("osmarbriones.EnemyDrops", "EnemyDrops", "1.1.0")]
	public class EnemyDrops : BaseUnityPlugin
	{
		internal static EnemyDrops Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			ConfigurationController.Initialize(((BaseUnityPlugin)this).Config, Logger);
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}
	}
	public static class ItemDropper
	{
		private static readonly Random s_rng = new Random();

		private static int s_dropsThisLevel;

		private static readonly string[] s_excludedEnemyNames = new string[2] { "Gnome", "Banger" };

		private static FieldInfo? s_enemyParentField;

		private static FieldInfo? s_enemyNameField;

		internal static void ResetForNewLevel()
		{
			s_dropsThisLevel = 0;
			EnemyDrops.Logger.LogInfo((object)$"ItemDropper: Drop counter reset for new level. MaxDropsPerLevel={ConfigurationController.MaxDropsPerLevel}");
		}

		public static bool TrySpawnForEnemy(Enemy enemy, out GameObject? spawned, float upwardOffset = 0.15f)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			spawned = null;
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)enemy))
			{
				EnemyDrops.Logger.LogDebug((object)"ItemDropper: Enemy null.");
				return false;
			}
			if (s_dropsThisLevel >= ConfigurationController.MaxDropsPerLevel)
			{
				EnemyDrops.Logger.LogInfo((object)$"ItemDropper:  Max drops per level reached ({ConfigurationController.MaxDropsPerLevel}).");
				return false;
			}
			Transform val = (Object.op_Implicit((Object)(object)enemy.CustomValuableSpawnTransform) ? enemy.CustomValuableSpawnTransform : (Object.op_Implicit((Object)(object)enemy.CenterTransform) ? enemy.CenterTransform : ((Component)enemy).transform));
			Vector3 position = val.position + Vector3.up * upwardOffset;
			Quaternion rotation = val.rotation;
			int dangerLevel = EnemyDifficultyAccessor.GetDangerLevel(enemy);
			string enemyNameSafe = GetEnemyNameSafe(enemy);
			EnemyDrops.Logger.LogInfo((object)$"ItemDropper: Enemy='{enemyNameSafe}' DangerLevel={dangerLevel}");
			if (IsExcludedEnemy(enemyNameSafe))
			{
				EnemyDrops.Logger.LogInfo((object)("ItemDropper: Excluding enemy '" + enemyNameSafe + "' from drops."));
				return false;
			}
			string text = PickWeightedKey(dangerLevel switch
			{
				1 => ItemDropTables.GetWeightsFor((Difficulty)0), 
				2 => ItemDropTables.GetWeightsFor((Difficulty)1), 
				3 => ItemDropTables.GetWeightsFor((Difficulty)2), 
				_ => ItemDropTables.GetWeightsFor((Difficulty)0), 
			});
			if (string.IsNullOrEmpty(text))
			{
				EnemyDrops.Logger.LogWarning((object)$"ItemDropper: No key picked (dangerLevel={dangerLevel}).");
				return false;
			}
			bool flag = ItemProvider.TrySpawnByKey(text, position, rotation, out spawned, 0f);
			if (flag)
			{
				DroppedInstanceTracker.MarkDropped(spawned);
				s_dropsThisLevel++;
			}
			return flag;
		}

		private static bool IsExcludedEnemy(string enemyName)
		{
			if (string.IsNullOrEmpty(enemyName))
			{
				return false;
			}
			for (int i = 0; i < s_excludedEnemyNames.Length; i++)
			{
				if (string.Equals(enemyName, s_excludedEnemyNames[i], StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static string GetEnemyNameSafe(Enemy enemy)
		{
			try
			{
				if ((object)s_enemyParentField == null)
				{
					s_enemyParentField = typeof(Enemy).GetField("EnemyParent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				object obj = s_enemyParentField?.GetValue(enemy);
				if (obj != null)
				{
					if ((object)s_enemyNameField == null)
					{
						s_enemyNameField = obj.GetType().GetField("enemyName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					}
					if (s_enemyNameField != null)
					{
						string text = s_enemyNameField.GetValue(obj) as string;
						if (!string.IsNullOrEmpty(text))
						{
							return text;
						}
					}
				}
			}
			catch (Exception ex)
			{
				EnemyDrops.Logger.LogDebug((object)("ItemDropper: enemy name reflection failed: " + ex.Message));
			}
			return Object.op_Implicit((Object)(object)enemy) ? ((Object)((Component)enemy).gameObject).name : "Unknown";
		}

		private static string? PickWeightedKey(IReadOnlyList<WeightedKey> weights)
		{
			if (weights == null || weights.Count == 0)
			{
				return null;
			}
			float num = 0f;
			foreach (WeightedKey weight in weights)
			{
				if (weight.Weight > 0f)
				{
					num += weight.Weight;
				}
			}
			if (num <= 0f)
			{
				return null;
			}
			double num2 = s_rng.NextDouble() * (double)num;
			float num3 = 0f;
			for (int i = 0; i < weights.Count; i++)
			{
				WeightedKey weightedKey = weights[i];
				if (!(weightedKey.Weight <= 0f))
				{
					num3 += weightedKey.Weight;
					if (num2 <= (double)num3)
					{
						return weightedKey.Key;
					}
				}
			}
			for (int num4 = weights.Count - 1; num4 >= 0; num4--)
			{
				if (weights[num4].Weight > 0f)
				{
					return weights[num4].Key;
				}
			}
			return null;
		}
	}
	public sealed class WeightedKey
	{
		public string Key { get; }

		public float Weight { get; }

		public WeightedKey(string key, float weight)
		{
			Key = key;
			Weight = weight;
		}
	}
	public static class ItemDropTables
	{
		private static readonly IReadOnlyList<WeightedKey> s_commonItems = new WeightedKey[17]
		{
			new WeightedKey("Item Grenade Stun", 3f),
			new WeightedKey("Item Grenade Shockwave", 3f),
			new WeightedKey("Item Grenade Explosive", 2f),
			new WeightedKey("Item Mine Stun", 3f),
			new WeightedKey("Item Mine Explosive", 2f),
			new WeightedKey("Item Mine Shockwave", 3f),
			new WeightedKey("Item Drone Zero Gravity", 1f),
			new WeightedKey("Item Drone Torque", 1f),
			new WeightedKey("Item Orb Zero Gravity", 1f),
			new WeightedKey("Item Health Pack Small", 3f),
			new WeightedKey("Item Duck Bucket", 1f),
			new WeightedKey("Item Rubber Duck", 1f),
			new WeightedKey("Item Melee Frying Pan", 1f),
			new WeightedKey("Item Melee Inflatable Hammer", 1f),
			new WeightedKey("Item Melee Sword", 1f),
			new WeightedKey("Item Valuable Tracker", 1f),
			new WeightedKey("Item Extraction Tracker", 1f)
		};

		private static readonly IReadOnlyList<WeightedKey> s_mediumItems = new WeightedKey[13]
		{
			new WeightedKey("Item Cart Small", 1f),
			new WeightedKey("Item Grenade Duct Taped", 3f),
			new WeightedKey("Item Grenade Human", 3f),
			new WeightedKey("Item Gun Handgun", 1f),
			new WeightedKey("Item Gun Tranq", 1f),
			new WeightedKey("Item Gun Stun", 1f),
			new WeightedKey("Item Gun Shockwave", 1f),
			new WeightedKey("Item Health Pack Medium", 3f),
			new WeightedKey("Item Melee Baseball Bat", 2f),
			new WeightedKey("Item Melee Stun Baton", 2f),
			new WeightedKey("Item Upgrade Player Tumble Climb", 1f),
			new WeightedKey("Item Upgrade Death Head Battery", 1f),
			new WeightedKey("Item Phase Bridge", 1f)
		};

		private static readonly IReadOnlyList<WeightedKey> s_rareItems = new WeightedKey[21]
		{
			new WeightedKey("Item Cart Medium", 1f),
			new WeightedKey("Item Cart Cannon", 1f),
			new WeightedKey("Item Cart Laser", 1f),
			new WeightedKey("Item Drone Feather", 2f),
			new WeightedKey("Item Drone Indestructible", 2f),
			new WeightedKey("Item Drone Battery", 1f),
			new WeightedKey("Item Gun Shotgun", 1f),
			new WeightedKey("Item Gun Laser", 1f),
			new WeightedKey("Item Health Pack Large", 3f),
			new WeightedKey("Item Melee Sledge Hammer", 1f),
			new WeightedKey("Item Power Crystal", 0f),
			new WeightedKey("Item Upgrade Player Health", 1f),
			new WeightedKey("Item Upgrade Player Energy", 1f),
			new WeightedKey("Item Upgrade Player Sprint Speed", 1f),
			new WeightedKey("Item Upgrade Player Grab Range", 1f),
			new WeightedKey("Item Upgrade Player Grab Strength", 1f),
			new WeightedKey("Item Upgrade Player Extra Jump", 1f),
			new WeightedKey("Item Upgrade Player Tumble Launch", 1f),
			new WeightedKey("Item Upgrade Player Tumble Wings", 1f),
			new WeightedKey("Item Upgrade Player Crouch Rest", 1f),
			new WeightedKey("Item Upgrade Map Player Count", 0f)
		};

		private static DropTableConfigMatrix? s_configMatrix;

		private static IReadOnlyList<WeightedKey>? s_fullDefaults1;

		private static IReadOnlyList<WeightedKey>? s_fullDefaults2;

		private static IReadOnlyList<WeightedKey>? s_fullDefaults3;

		private static bool s_fullDefaultsBuilt;

		public static void InitializeConfig(ConfigFile config, string? header = null, bool saveImmediately = false)
		{
			s_configMatrix = new DropTableConfigMatrix(config, s_commonItems, s_mediumItems, s_rareItems);
		}

		public static IReadOnlyList<WeightedKey> GetWeightsFor(Difficulty difficulty)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			if (s_configMatrix != null)
			{
				return s_configMatrix.Get(difficulty);
			}
			EnsureFullDefaults();
			IReadOnlyList<WeightedKey> readOnlyList = s_fullDefaults1;
			IReadOnlyList<WeightedKey> readOnlyList2 = s_fullDefaults2;
			IReadOnlyList<WeightedKey> readOnlyList3 = s_fullDefaults3;
			if (1 == 0)
			{
			}
			IReadOnlyList<WeightedKey> result = (((int)difficulty == 0) ? readOnlyList : (((int)difficulty != 1) ? readOnlyList3 : readOnlyList2));
			if (1 == 0)
			{
			}
			return result;
		}

		private static void EnsureFullDefaults()
		{
			if (!s_fullDefaultsBuilt)
			{
				s_fullDefaults1 = BuildFullFromDefaults(s_commonItems);
				s_fullDefaults2 = BuildFullFromDefaults(s_mediumItems);
				s_fullDefaults3 = BuildFullFromDefaults(s_rareItems);
				s_fullDefaultsBuilt = true;
			}
		}

		private static IReadOnlyList<WeightedKey> BuildFullFromDefaults(IReadOnlyList<WeightedKey> defaultsForLevel)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < defaultsForLevel.Count; i++)
			{
				dictionary[defaultsForLevel[i].Key] = defaultsForLevel[i].Weight;
			}
			WeightedKey[] array = new WeightedKey[ItemKeys.All.Length];
			for (int j = 0; j < ItemKeys.All.Length; j++)
			{
				string key = ItemKeys.All[j];
				float value;
				float weight = (dictionary.TryGetValue(key, out value) ? value : 0f);
				array[j] = new WeightedKey(key, weight);
			}
			return array;
		}

		public static void LogWeights(ManualLogSource logger)
		{
			ManualLogSource logger2 = logger;
			if (logger2 == null)
			{
				throw new ArgumentNullException("logger");
			}
			LogLevel("Difficulty1", (Difficulty)0);
			LogLevel("Difficulty2", (Difficulty)1);
			LogLevel("Difficulty3", (Difficulty)2);
			void LogLevel(string name, Difficulty diff)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				IReadOnlyList<WeightedKey> weightsFor = GetWeightsFor(diff);
				int num = 0;
				for (int i = 0; i < weightsFor.Count; i++)
				{
					WeightedKey weightedKey = weightsFor[i];
					if (weightedKey.Weight > 0f)
					{
						if (num == 0)
						{
							logger2.LogInfo((object)("DropTable " + name + ":"));
						}
						logger2.LogInfo((object)$"  {weightedKey.Key} = {weightedKey.Weight}");
						num++;
					}
				}
				if (num == 0)
				{
					logger2.LogInfo((object)("DropTable " + name + ": (no non-zero entries)"));
				}
			}
		}
	}
}
namespace EnemyDrops.Reflection
{
	internal static class EnemyDifficultyAccessor
	{
		private static FieldInfo? _enemyParentField;

		private static FieldInfo? _difficultyField;

		private static Type? _enemyType;

		private static Type? _enemyParentType;

		private static bool _initialized;

		private static void Init(Enemy enemy)
		{
			if (_initialized || !Object.op_Implicit((Object)(object)enemy))
			{
				return;
			}
			try
			{
				_enemyType = ((object)enemy).GetType();
				_enemyParentField = _enemyType.GetField("EnemyParent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				object obj = _enemyParentField?.GetValue(enemy);
				if (obj != null)
				{
					_enemyParentType = obj.GetType();
					_difficultyField = _enemyParentType.GetField("difficulty", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			catch (Exception ex)
			{
				EnemyDrops.Logger.LogDebug((object)("EnemyDifficultyAccessor.Init reflection failed: " + ex.Message));
			}
			finally
			{
				_initialized = true;
			}
		}

		private static object? GetDifficultyEnum(Enemy enemy)
		{
			Init(enemy);
			if (!Object.op_Implicit((Object)(object)enemy) || _enemyParentField == null || _difficultyField == null)
			{
				return null;
			}
			try
			{
				object value = _enemyParentField.GetValue(enemy);
				return (value != null) ? _difficultyField.GetValue(value) : null;
			}
			catch (Exception ex)
			{
				EnemyDrops.Logger.LogDebug((object)("EnemyDifficultyAccessor.GetDifficultyEnum failed: " + ex.Message));
				return null;
			}
		}

		public static int GetDangerLevel(Enemy enemy)
		{
			try
			{
				object difficultyEnum = GetDifficultyEnum(enemy);
				if (difficultyEnum == null)
				{
					return 1;
				}
				int num = (int)Convert.ChangeType(difficultyEnum, typeof(int));
				return num + 1;
			}
			catch
			{
				return 1;
			}
		}
	}
}
namespace EnemyDrops.Providers
{
	public static class ItemKeys
	{
		public const string CartCannon = "Item Cart Cannon";

		public const string CartLaser = "Item Cart Laser";

		public const string CartMedium = "Item Cart Medium";

		public const string CartSmall = "Item Cart Small";

		public const string DroneBattery = "Item Drone Battery";

		public const string DroneFeather = "Item Drone Feather";

		public const string DroneIndestructible = "Item Drone Indestructible";

		public const string DroneTorque = "Item Drone Torque";

		public const string DroneZeroGravity = "Item Drone Zero Gravity";

		public const string DuckBucket = "Item Duck Bucket";

		public const string ExtractionTracker = "Item Extraction Tracker";

		public const string GrenadeDuctTaped = "Item Grenade Duct Taped";

		public const string GrenadeExplosive = "Item Grenade Explosive";

		public const string GrenadeHuman = "Item Grenade Human";

		public const string GrenadeShockwave = "Item Grenade Shockwave";

		public const string GrenadeStun = "Item Grenade Stun";

		public const string GunHandgun = "Item Gun Handgun";

		public const string GunLaser = "Item Gun Laser";

		public const string GunShockwave = "Item Gun Shockwave";

		public const string GunShotgun = "Item Gun Shotgun";

		public const string GunStun = "Item Gun Stun";

		public const string GunTranq = "Item Gun Tranq";

		public const string HealthPackLarge = "Item Health Pack Large";

		public const string HealthPackMedium = "Item Health Pack Medium";

		public const string HealthPackSmall = "Item Health Pack Small";

		public const string MeleeBaseballBat = "Item Melee Baseball Bat";

		public const string MeleeFryingPan = "Item Melee Frying Pan";

		public const string MeleeInflatableHammer = "Item Melee Inflatable Hammer";

		public const string MeleeSledgeHammer = "Item Melee Sledge Hammer";

		public const string MeleeStunBaton = "Item Melee Stun Baton";

		public const string MeleeSword = "Item Melee Sword";

		public const string MineExplosive = "Item Mine Explosive";

		public const string MineShockwave = "Item Mine Shockwave";

		public const string MineStun = "Item Mine Stun";

		public const string OrbZeroGravity = "Item Orb Zero Gravity";

		public const string PhaseBridge = "Item Phase Bridge";

		public const string PowerCrystal = "Item Power Crystal";

		public const string RubberDuck = "Item Rubber Duck";

		public const string UpgradeDeathHeadBattery = "Item Upgrade Death Head Battery";

		public const string UpgradeMapPlayerCount = "Item Upgrade Map Player Count";

		public const string UpgradePlayerCrouchRest = "Item Upgrade Player Crouch Rest";

		public const string UpgradePlayerEnergy = "Item Upgrade Player Energy";

		public const string UpgradePlayerExtraJump = "Item Upgrade Player Extra Jump";

		public const string UpgradePlayerGrabRange = "Item Upgrade Player Grab Range";

		public const string UpgradePlayerGrabStrength = "Item Upgrade Player Grab Strength";

		public const string UpgradePlayerHealth = "Item Upgrade Player Health";

		public const string UpgradePlayerSprintSpeed = "Item Upgrade Player Sprint Speed";

		public const string UpgradePlayerTumbleClimb = "Item Upgrade Player Tumble Climb";

		public const string UpgradePlayerTumbleLaunch = "Item Upgrade Player Tumble Launch";

		public const string UpgradePlayerTumbleWings = "Item Upgrade Player Tumble Wings";

		public const string ValuableTracker = "Item Valuable Tracker";

		public static readonly string[] All = new string[51]
		{
			"Item Cart Cannon", "Item Cart Laser", "Item Cart Medium", "Item Cart Small", "Item Drone Battery", "Item Drone Feather", "Item Drone Indestructible", "Item Drone Torque", "Item Drone Zero Gravity", "Item Duck Bucket",
			"Item Extraction Tracker", "Item Grenade Duct Taped", "Item Grenade Explosive", "Item Grenade Human", "Item Grenade Shockwave", "Item Grenade Stun", "Item Gun Handgun", "Item Gun Laser", "Item Gun Shockwave", "Item Gun Shotgun",
			"Item Gun Stun", "Item Gun Tranq", "Item Health Pack Large", "Item Health Pack Medium", "Item Health Pack Small", "Item Melee Baseball Bat", "Item Melee Frying Pan", "Item Melee Inflatable Hammer", "Item Melee Sledge Hammer", "Item Melee Stun Baton",
			"Item Melee Sword", "Item Mine Explosive", "Item Mine Shockwave", "Item Mine Stun", "Item Orb Zero Gravity", "Item Phase Bridge", "Item Power Crystal", "Item Rubber Duck", "Item Upgrade Death Head Battery", "Item Upgrade Map Player Count",
			"Item Upgrade Player Crouch Rest", "Item Upgrade Player Energy", "Item Upgrade Player Extra Jump", "Item Upgrade Player Grab Range", "Item Upgrade Player Grab Strength", "Item Upgrade Player Health", "Item Upgrade Player Sprint Speed", "Item Upgrade Player Tumble Climb", "Item Upgrade Player Tumble Launch", "Item Upgrade Player Tumble Wings",
			"Item Valuable Tracker"
		};
	}
	public static class ItemKeysProvider
	{
		private static readonly string[] s_defaultKeys = ItemKeys.All;

		private static readonly IReadOnlyList<string> s_readOnlyKeys = Array.AsReadOnly(s_defaultKeys);

		private static readonly Random s_rng = new Random();

		public static IReadOnlyList<string> Keys => s_readOnlyKeys;

		public static string? GetRandomKey()
		{
			if (s_defaultKeys.Length == 0)
			{
				return null;
			}
			return s_defaultKeys[s_rng.Next(s_defaultKeys.Length)];
		}
	}
	public static class ItemProvider
	{
		public static bool TrySpawnRandomItem(Vector3 position, Quaternion rotation, out GameObject? spawned, float upwardOffset = 0.15f)
		{
			//IL_002a: 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)
			spawned = null;
			string randomKey = ItemKeysProvider.GetRandomKey();
			if (string.IsNullOrEmpty(randomKey))
			{
				EnemyDrops.Logger.LogWarning((object)"ItemProvider: Random key provider returned null/empty.");
				return false;
			}
			return TrySpawnByKey(randomKey, position, rotation, out spawned, upwardOffset);
		}

		public static bool TrySpawnByKey(string key, Vector3 position, Quaternion rotation, out GameObject? spawned, float upwardOffset = 0.15f)
		{
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			spawned = null;
			bool flag = true;
			try
			{
				flag = SemiFunc.IsMasterClientOrSingleplayer();
			}
			catch
			{
			}
			if (!flag)
			{
				return false;
			}
			Dictionary<string, Item> dictionary = StatsManager.instance?.itemDictionary;
			if (dictionary == null)
			{
				EnemyDrops.Logger.LogWarning((object)"ItemProvider: itemDictionary unavailable.");
				return false;
			}
			if (!dictionary.TryGetValue(key, out var value) || (Object)(object)value == (Object)null || value.prefab == null)
			{
				EnemyDrops.Logger.LogWarning((object)("ItemProvider: Key '" + key + "' not found or invalid."));
				return false;
			}
			Vector3 val = position + Vector3.up * upwardOffset;
			try
			{
				if (SemiFunc.IsMultiplayer())
				{
					spawned = PhotonNetwork.InstantiateRoomObject(value.prefab.ResourcePath, val, rotation, (byte)0, (object[])null);
				}
				else
				{
					spawned = Object.Instantiate<GameObject>(value.prefab.Prefab, val, rotation);
				}
			}
			catch (Exception ex)
			{
				EnemyDrops.Logger.LogError((object)$"ItemProvider: Failed to spawn '{((Object)value).name}' at {val}: {ex.Message}");
				return false;
			}
			ApplySpawnImpulse(spawned);
			EnemyDrops.Logger.LogInfo((object)$"ItemProvider: Spawned '{((Object)spawned).name}' at {val} (key = {key})");
			return true;
		}

		private static void ApplySpawnImpulse(GameObject? go)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody val = default(Rigidbody);
			if (Object.op_Implicit((Object)(object)go) && go.TryGetComponent<Rigidbody>(ref val))
			{
				val.collisionDetectionMode = (CollisionDetectionMode)1;
				val.AddForce(Random.insideUnitSphere * 1.25f + Vector3.up * 2f, (ForceMode)1);
			}
		}
	}
	internal class RandomItemProvider
	{
	}
}
namespace EnemyDrops.Patches
{
	[HarmonyPatch(typeof(SemiFunc), "OnSceneSwitch")]
	internal static class ClearDroppedBatteriesOnSceneSwitch
	{
		private static void Postfix(bool _gameOver, bool _leaveGame)
		{
			try
			{
				DroppedInstanceTracker.ClearBatteriesForDroppedInstances();
			}
			catch (Exception arg)
			{
				EnemyDrops.Logger.LogError((object)$"EnemyDrops: Failed to clear dropped batteries on scene switch: {arg}");
			}
		}
	}
	internal static class EnemyDeathPatch
	{
		[HarmonyPatch(typeof(EnemyHealth), "Awake")]
		private static class EnemyHealth_Awake_Patch
		{
			private static void Postfix(EnemyHealth __instance)
			{
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Expected O, but got Unknown
				EnemyHealth __instance2 = __instance;
				if (!Subscribed.TryGetValue(__instance2, out object _))
				{
					Subscribed.Add(__instance2, new object());
					__instance2.onDeath.AddListener((UnityAction)delegate
					{
						OnEnemyDeath(__instance2);
					});
				}
			}
		}

		private static readonly ConditionalWeakTable<EnemyHealth, object> Subscribed = new ConditionalWeakTable<EnemyHealth, object>();

		private static void OnEnemyDeath(EnemyHealth health)
		{
			try
			{
				bool flag = true;
				try
				{
					flag = SemiFunc.IsMasterClientOrSingleplayer();
				}
				catch
				{
				}
				if (flag)
				{
					Enemy component = ((Component)health).GetComponent<Enemy>();
					GameObject spawned;
					if ((Object)(object)component == (Object)null)
					{
						EnemyDrops.Logger.LogWarning((object)"EnemyDeathPatch: Enemy component not found on dead object.");
					}
					else if (!ItemDropper.TrySpawnForEnemy(component, out spawned))
					{
						EnemyDrops.Logger.LogDebug((object)"EnemyDeathPatch: ItemDropper failed or chose no item to spawn.");
					}
				}
			}
			catch (Exception arg)
			{
				EnemyDrops.Logger.LogError((object)$"EnemyDeathPatch.OnEnemyDeath failed: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(PunManager), "SetItemNameLOGIC")]
	internal static class PunManager_SetItemNameLOGIC_Patch
	{
		private static void Postfix(string name, int photonViewID, ItemAttributes _itemAttributes)
		{
			ItemAttributes val = _itemAttributes;
			if (SemiFunc.IsMultiplayer())
			{
				PhotonView val2 = PhotonView.Find(photonViewID);
				if ((Object)(object)val2 != (Object)null)
				{
					val = ((Component)val2).GetComponent<ItemAttributes>();
				}
			}
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)((Component)val).GetComponent<DroppedItemTag>()))
			{
				DroppedInstanceTracker.RegisterInstance(name);
			}
		}
	}
	[HarmonyPatch(typeof(EnemyDirector), "Start")]
	internal static class ReloadDropTablesOnLevelStart
	{
		private static void Postfix()
		{
			if (!SemiFunc.RunIsLevel())
			{
				return;
			}
			try
			{
				ConfigurationController.Reload(EnemyDrops.Logger);
				ItemDropper.ResetForNewLevel();
				DroppedInstanceTracker.ClearForNewLevel();
			}
			catch (Exception arg)
			{
				EnemyDrops.Logger.LogError((object)$"EnemyDrops: Failed during level-start reload/reset: {arg}");
			}
		}

		private static void LogItemTable()
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				EnemyDrops.Logger.LogWarning((object)"EnemyDrops: StatsManager.instance is null; cannot dump item table.");
				return;
			}
			Dictionary<string, int> item = instance.item;
			if (item == null || item.Count == 0)
			{
				EnemyDrops.Logger.LogInfo((object)"EnemyDrops: item dictionary is empty.");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("EnemyDrops: item dump (instanceName = value):");
			foreach (KeyValuePair<string, int> item2 in item)
			{
				stringBuilder.AppendLine($"  {item2.Key} = {item2.Value}");
			}
			EnemyDrops.Logger.LogInfo((object)stringBuilder.ToString());
		}

		private static void LogBatteryTable()
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				EnemyDrops.Logger.LogWarning((object)"EnemyDrops: StatsManager.instance is null; cannot dump battery table.");
				return;
			}
			Dictionary<string, int> itemStatBattery = instance.itemStatBattery;
			if (itemStatBattery == null || itemStatBattery.Count == 0)
			{
				EnemyDrops.Logger.LogInfo((object)"EnemyDrops: itemStatBattery is empty.");
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("EnemyDrops: itemStatBattery dump (instanceName = battery):");
			foreach (KeyValuePair<string, int> item in itemStatBattery)
			{
				stringBuilder.AppendLine($"  {item.Key} = {item.Value}");
			}
			EnemyDrops.Logger.LogInfo((object)stringBuilder.ToString());
		}
	}
}
namespace EnemyDrops.Configuration
{
	internal static class ConfigurationController
	{
		private static ConfigFile? _config;

		private static ConfigEntry<int>? _maxDropsPerLevel;

		internal static int MaxDropsPerLevel => _maxDropsPerLevel?.Value ?? 200;

		internal static void Initialize(ConfigFile config, ManualLogSource logger)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			if (logger == null)
			{
				throw new ArgumentNullException("logger");
			}
			_config = config;
			_maxDropsPerLevel = _config.Bind<int>("General", "MaxDropsPerLevel", 200, new ConfigDescription("Maximum number of items that can drop each level.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			ItemDropTables.InitializeConfig(_config);
			_config.Save();
			ItemDropTables.LogWeights(logger);
			logger.LogInfo((object)$"EnemyDrops: Configuration initialized. MaxDropsPerLevel={MaxDropsPerLevel}");
		}

		internal static void Reload(ManualLogSource logger)
		{
			if (_config == null)
			{
				logger.LogWarning((object)"EnemyDrops: Configuration reload requested before initialization.");
				return;
			}
			try
			{
				_config.Reload();
				ItemDropTables.InitializeConfig(_config);
				_config.Save();
				ItemDropTables.LogWeights(logger);
				logger.LogInfo((object)$"EnemyDrops: Configuration reloaded. MaxDropsPerLevel={MaxDropsPerLevel}");
			}
			catch (Exception arg)
			{
				logger.LogError((object)$"EnemyDrops: Failed to reload configuration: {arg}");
			}
		}
	}
	internal sealed class DropTableConfigMatrix
	{
		internal const int DropWeightMin = 0;

		internal const int DropWeightMax = 12;

		private readonly Dictionary<string, ConfigEntry<int>> _d1 = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<int>> _d2 = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, ConfigEntry<int>> _d3 = new Dictionary<string, ConfigEntry<int>>(StringComparer.OrdinalIgnoreCase);

		private readonly IReadOnlyList<WeightedKey> _w1;

		private readonly IReadOnlyList<WeightedKey> _w2;

		private readonly IReadOnlyList<WeightedKey> _w3;

		public DropTableConfigMatrix(ConfigFile config, IReadOnlyList<WeightedKey> defaultsDifficulty1, IReadOnlyList<WeightedKey> defaultsDifficulty2, IReadOnlyList<WeightedKey> defaultsDifficulty3)
		{
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			if (defaultsDifficulty1 == null)
			{
				throw new ArgumentNullException("defaultsDifficulty1");
			}
			if (defaultsDifficulty2 == null)
			{
				throw new ArgumentNullException("defaultsDifficulty2");
			}
			if (defaultsDifficulty3 == null)
			{
				throw new ArgumentNullException("defaultsDifficulty3");
			}
			Dictionary<string, float> dictionary = ToMap(defaultsDifficulty1);
			Dictionary<string, float> dictionary2 = ToMap(defaultsDifficulty2);
			Dictionary<string, float> dictionary3 = ToMap(defaultsDifficulty3);
			AcceptableValueRange<int> val = new AcceptableValueRange<int>(0, 12);
			string[] all = ItemKeys.All;
			foreach (string text in all)
			{
				float value;
				int num = Clamp((int)Math.Round(dictionary.TryGetValue(text, out value) ? value : 0f), 0, 12);
				float value2;
				int num2 = Clamp((int)Math.Round(dictionary2.TryGetValue(text, out value2) ? value2 : 0f), 0, 12);
				float value3;
				int num3 = Clamp((int)Math.Round(dictionary3.TryGetValue(text, out value3) ? value3 : 0f), 0, 12);
				_d1[text] = config.Bind<int>("Easy Monsters (Elsa for example)", text, num, new ConfigDescription($"Weight for \"{text}\" on easy monsters. (range {0}..{12})", (AcceptableValueBase)(object)val, Array.Empty<object>()));
				_d2[text] = config.Bind<int>("Med. Monsters (Chef for example)", text, num2, new ConfigDescription($"Weight for \"{text}\" on medium monsters. (range {0}..{12})", (AcceptableValueBase)(object)val, Array.Empty<object>()));
				_d3[text] = config.Bind<int>("Hard Monsters (Robe for example)", text, num3, new ConfigDescription($"Weight for \"{text}\" on hard monsters. (range {0}..{12})", (AcceptableValueBase)(object)val, Array.Empty<object>()));
			}
			_w1 = BuildWeights(_d1);
			_w2 = BuildWeights(_d2);
			_w3 = BuildWeights(_d3);
		}

		public IReadOnlyList<WeightedKey> Get(Difficulty difficulty)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			if (1 == 0)
			{
			}
			IReadOnlyList<WeightedKey> result = (((int)difficulty == 0) ? _w1 : (((int)difficulty != 1) ? _w3 : _w2));
			if (1 == 0)
			{
			}
			return result;
		}

		private static Dictionary<string, float> ToMap(IReadOnlyList<WeightedKey> list)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < list.Count; i++)
			{
				dictionary[list[i].Key] = list[i].Weight;
			}
			return dictionary;
		}

		private static IReadOnlyList<WeightedKey> BuildWeights(Dictionary<string, ConfigEntry<int>> byKey)
		{
			WeightedKey[] array = new WeightedKey[ItemKeys.All.Length];
			for (int i = 0; i < ItemKeys.All.Length; i++)
			{
				string key = ItemKeys.All[i];
				int num = Clamp(byKey[key].Value, 0, 12);
				array[i] = new WeightedKey(key, num);
			}
			return array;
		}

		private static int Clamp(int v, int min, int max)
		{
			return (v < min) ? min : ((v > max) ? max : v);
		}
	}
}