Decompiled source of CreatureTrophyDropRate ExcludeBoss v1.0.0

BepInEx/plugins/CreatureTrophyDropRate_ExcludeBoss/CreatureTrophyDropRate_ExcludeBoss.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("CreatureTrophyDropRate_ExcludeBoss")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CreatureTrophyDropRate_ExcludeBoss")]
[assembly: AssemblyTitle("CreatureTrophyDropRate_ExcludeBoss")]
[assembly: AssemblyVersion("1.0.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 CreatureTrophyDropRate_ExcludeBoss
{
	public enum TrophyChanceMode
	{
		Fixed,
		Multiplier
	}
	internal sealed class ChanceSettings
	{
		internal readonly TrophyChanceMode Mode;

		internal readonly float FixedChance;

		internal readonly float Multiplier;

		internal ChanceSettings(string mode, float fixedChance, float multiplier, Action<string> warn)
		{
			if (string.Equals(mode?.Trim(), "Fixed", StringComparison.OrdinalIgnoreCase))
			{
				Mode = TrophyChanceMode.Fixed;
			}
			else
			{
				Mode = TrophyChanceMode.Multiplier;
				if (!string.Equals(mode?.Trim(), "Multiplier", StringComparison.OrdinalIgnoreCase))
				{
					warn("Invalid Mode; falling back to Multiplier.");
				}
			}
			FixedChance = Validate(fixedChance, 0.5f, 1f, "FixedChance", warn);
			Multiplier = Validate(multiplier, 2f, float.MaxValue, "Multiplier", warn);
		}

		private static float Validate(float value, float fallback, float max, string key, Action<string> warn)
		{
			if (float.IsNaN(value) || float.IsInfinity(value))
			{
				warn(key + " must be finite; using " + fallback + ".");
				return fallback;
			}
			float num = Math.Max(0f, Math.Min(max, value));
			if (num != value)
			{
				warn(key + " is outside its allowed range; clamped to " + num + ".");
			}
			return num;
		}

		internal float Apply(float original)
		{
			if (Mode != TrophyChanceMode.Fixed)
			{
				return (float)Math.Max(0.0, Math.Min(1.0, (double)original * (double)Multiplier));
			}
			return FixedChance;
		}
	}
	internal sealed class DropProcessor
	{
		private sealed class Baseline
		{
			internal readonly float Chance;

			internal Baseline(float chance)
			{
				Chance = chance;
			}
		}

		private readonly ConditionalWeakTable<Drop, Baseline> originals = new ConditionalWeakTable<Drop, Baseline>();

		private static readonly MethodInfo Clone = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);

		internal void Process(IEnumerable<GameObject> prefabs, ChanceSettings settings, Action<string> info, Action<string> debug)
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Invalid comparison between Unknown and I4
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			HashSet<GameObject> hashSet = new HashSet<GameObject>();
			foreach (GameObject prefab in prefabs)
			{
				if (!Object.op_Implicit((Object)(object)prefab) || !hashSet.Add(prefab))
				{
					continue;
				}
				Character component = prefab.GetComponent<Character>();
				CharacterDrop component2 = prefab.GetComponent<CharacterDrop>();
				if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2))
				{
					continue;
				}
				if (component.m_boss)
				{
					num3++;
					debug?.Invoke("Boss skipped: " + ((Object)prefab).name);
				}
				else
				{
					if (component2.m_drops == null)
					{
						continue;
					}
					List<Drop> list = null;
					for (int i = 0; i < component2.m_drops.Count; i++)
					{
						Drop val = component2.m_drops[i];
						if (val == null || !Object.op_Implicit((Object)(object)val.m_prefab))
						{
							continue;
						}
						ItemDrop component3 = val.m_prefab.GetComponent<ItemDrop>();
						if (!Object.op_Implicit((Object)(object)component3) || component3.m_itemData?.m_shared == null || (int)component3.m_itemData.m_shared.m_itemType != 13)
						{
							continue;
						}
						Baseline value = originals.GetValue(val, (Drop d) => new Baseline(d.m_chance));
						if (float.IsNaN(value.Chance) || float.IsInfinity(value.Chance))
						{
							debug?.Invoke("Invalid original chance skipped: " + ((Object)prefab).name + " -> " + ((Object)val.m_prefab).name);
							continue;
						}
						float num4 = settings.Apply(value.Chance);
						if (num4 != val.m_chance)
						{
							if (list == null)
							{
								list = new List<Drop>(component2.m_drops);
							}
							Drop val2 = (Drop)Clone.Invoke(val, null);
							val2.m_chance = num4;
							originals.Add(val2, value);
							list[i] = val2;
							num++;
							debug?.Invoke($"{((Object)prefab).name} -> {((Object)val.m_prefab).name}: {value.Chance:G6} -> {num4:G6}");
						}
					}
					if (list != null)
					{
						component2.m_drops = list;
						num2++;
					}
				}
			}
			info($"Modified {num} trophy drop entries across {num2} non-boss creatures.");
			info($"Skipped {num3} bosses.");
		}
	}
	[BepInPlugin("com.weizhexu.nonbosstrophies", "CreatureTrophyDropRate_ExcludeBoss", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class SceneAwakePatch
		{
			[HarmonyPostfix]
			[HarmonyPriority(0)]
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)instance != (Object)null)
				{
					instance.Apply(__instance);
				}
			}
		}

		public const string Guid = "com.weizhexu.nonbosstrophies";

		private static Plugin instance;

		private Harmony harmony;

		private ChanceSettings settings;

		private bool debugLogging;

		private readonly DropProcessor processor = new DropProcessor();

		private readonly ConditionalWeakTable<ZNetScene, object> scenes = new ConditionalWeakTable<ZNetScene, object>();

		private void Awake()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			instance = this;
			ConfigEntry<string> val = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Mode", "Fixed", "Fixed or Multiplier (case-insensitive). Invalid values use Multiplier. Restart after editing.");
			ConfigEntry<float> val2 = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FixedChance", 0.5f, "Used in Fixed mode. 0 = 0%, 0.5 = 50%, 1 = 100%. Clamped to [0,1].");
			ConfigEntry<float> val3 = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Multiplier", 2f, "Used in Multiplier mode. 2 doubles the existing base trophy chance, capped at 100%. Negative values clamp to zero.");
			debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Log individual changes and skipped bosses.").Value;
			settings = new ChanceSettings(val.Value, val2.Value, val3.Value, delegate(string s)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)s);
			});
			harmony = new Harmony("com.weizhexu.nonbosstrophies");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Initialized.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Mode: {settings.Mode}, FixedChance: {settings.FixedChance}, Multiplier: {settings.Multiplier}");
		}

		private void Apply(ZNetScene scene)
		{
			if (!scenes.TryGetValue(scene, out var _))
			{
				List<GameObject> list = new List<GameObject>(scene.m_prefabs);
				list.AddRange(scene.m_nonNetViewPrefabs);
				processor.Process(list, settings, delegate(string s)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)s);
				}, debugLogging ? ((Action<string>)delegate(string s)
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)s);
				}) : null);
				scenes.Add(scene, new object());
			}
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)instance == (Object)(object)this)
			{
				instance = null;
			}
		}
	}
}