Decompiled source of TrinketFortune v1.0.0

TrinketFortune.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using HavenDevTools;
using HavenDevTools.API;
using HavenDevTools.Services;
using Microsoft.CodeAnalysis;
using TrinketFortune.DevTools;
using TrinketFortune.Patches;
using UnityEngine;
using Wish;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("TrinketFortune")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+592de27566bf17cfeeb38c12364cfc59146ab5e6")]
[assembly: AssemblyProduct("TrinketFortune")]
[assembly: AssemblyTitle("TrinketFortune")]
[assembly: AssemblyVersion("1.0.0.0")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TrinketFortune
{
	public static class Config
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> MuseumProgressBonusPercent;

		public static ConfigEntry<float> MinimumMuseumProgress;

		public static void Bind(ConfigFile config)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			Enabled = config.Bind<bool>("General", "Enabled", true, "Enable Trinket Fortune. When enabled, odds of unowned fishing trinkets increase as you complete the aquarium.");
			MuseumProgressBonusPercent = config.Bind<float>("General", "MuseumProgressBonusPercent", 5f, "Bonus to unowned trinket odds per 10% aquarium completion (e.g. 5 = +5% per 10%). Applied on top of base drop chance.");
			MinimumMuseumProgress = config.Bind<float>("General", "MinimumMuseumProgress", 0.2f, new ConfigDescription("Museum progress below this has no bonus (0.2 = 20% donated). Prevents bonus at very low completion.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}
	}
	public static class DonationHelper
	{
		private const string SmutGuid = "com.azraelgodking.sunhavenmuseumutilitytracker";

		private static object _donationManager;

		private static MethodInfo _hasDonatedByGameId;

		public static bool IsAvailable => _donationManager != null && _hasDonatedByGameId != null;

		static DonationHelper()
		{
			if (Chainloader.PluginInfos == null || !Chainloader.PluginInfos.TryGetValue("com.azraelgodking.sunhavenmuseumutilitytracker", out var _))
			{
				return;
			}
			try
			{
				Type type = Type.GetType("SunHavenMuseumUtilityTracker.Plugin, SunHavenMuseumUtilityTracker");
				if (type == null)
				{
					return;
				}
				MethodInfo method = type.GetMethod("GetDonationManager", BindingFlags.Static | BindingFlags.Public);
				if (!(method == null))
				{
					_donationManager = method.Invoke(null, null);
					if (_donationManager != null)
					{
						_hasDonatedByGameId = _donationManager.GetType().GetMethod("HasDonatedByGameId", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(int) }, null);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogDebug((object)("DonationHelper: SMUT not available: " + ex.Message));
				}
			}
		}

		public static bool HasDonatedByGameId(int gameItemId)
		{
			if (_donationManager == null || _hasDonatedByGameId == null)
			{
				return false;
			}
			try
			{
				return (bool)_hasDonatedByGameId.Invoke(_donationManager, new object[1] { gameItemId });
			}
			catch
			{
				return false;
			}
		}

		public static int PickBiasedFishingMuseumItem()
		{
			if (!Config.Enabled.Value)
			{
				return 0;
			}
			List<int> fishingMuseumItems = FishingRod.fishingMuseumItems;
			if (fishingMuseumItems == null || fishingMuseumItems.Count == 0)
			{
				return 0;
			}
			if (!IsAvailable)
			{
				return 0;
			}
			List<int> list = fishingMuseumItems.Where((int id) => !HasDonatedByGameId(id)).ToList();
			if (list.Count == 0)
			{
				return fishingMuseumItems[Random.Range(0, fishingMuseumItems.Count)];
			}
			float aquariumProgress = GetAquariumProgress();
			if (aquariumProgress < Config.MinimumMuseumProgress.Value * 100f)
			{
				return fishingMuseumItems[Random.Range(0, fishingMuseumItems.Count)];
			}
			float num = Config.MuseumProgressBonusPercent.Value * (aquariumProgress / 10f);
			float num2 = Random.Range(0f, 100f);
			if (num2 < num)
			{
				return list[Random.Range(0, list.Count)];
			}
			return fishingMuseumItems[Random.Range(0, fishingMuseumItems.Count)];
		}

		private static float GetAquariumProgress()
		{
			try
			{
				int num = 0;
				int num2 = 0;
				Type type = Type.GetType("Wish.GameSave, SunHaven.Core");
				if (type == null)
				{
					return 0f;
				}
				PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
				if (property == null)
				{
					return 0f;
				}
				object value = property.GetValue(null);
				if (value == null)
				{
					return 0f;
				}
				MethodInfo method = type.GetMethod("GetProgressIntWorld", new Type[1] { typeof(string) });
				if (method == null)
				{
					return 0f;
				}
				foreach (var item2 in MuseumCurator.aquaticMuseumProgress)
				{
					string text = item2.Item1 + "complete";
					int item = item2.Item2;
					int num3 = (int)method.Invoke(value, new object[1] { text });
					num += item;
					num2 += num3;
				}
				return (num > 0) ? ((float)num2 / (float)num * 100f) : 0f;
			}
			catch
			{
				return 0f;
			}
		}

		public static FishData PickBiasedFish(RandomFishArray array, float level)
		{
			if (!Config.Enabled.Value || array == null || array.Length == 0)
			{
				return null;
			}
			if (!IsAvailable)
			{
				return null;
			}
			List<FishData> list = new List<FishData>();
			for (int i = 0; i < array.Length; i++)
			{
				FishLoot val = array.drops[i];
				if (!((Object)(object)val?.fish == (Object)null))
				{
					int id = ((ItemData)val.fish).id;
					if (!HasDonatedByGameId(id))
					{
						list.Add(val.fish);
					}
				}
			}
			if (list.Count == 0)
			{
				return null;
			}
			float aquariumProgress = GetAquariumProgress();
			if (aquariumProgress < Config.MinimumMuseumProgress.Value * 100f)
			{
				return null;
			}
			float num = Config.MuseumProgressBonusPercent.Value * (aquariumProgress / 10f);
			if (Random.Range(0f, 100f) >= num)
			{
				return null;
			}
			return list[Random.Range(0, list.Count)];
		}
	}
	[BepInPlugin("com.azraelgodking.trinketfortune", "Trinket Fortune", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static class PluginInfo
		{
			public const string PLUGIN_GUID = "com.azraelgodking.trinketfortune";

			public const string PLUGIN_NAME = "Trinket Fortune";

			public const string PLUGIN_VERSION = "1.0.0";
		}

		private Harmony _harmony;

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Config.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.azraelgodking.trinketfortune");
			FishingTrinketPatches.ApplyPatches(_harmony);
			if (Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("com.azraelgodking.havendevtools"))
			{
				DevToolsRegistry.Register((IDevToolsPanel)(object)new TrinketFortunePanel());
				Log.LogInfo((object)"Registered Trinket Fortune panel with HavenDevTools");
			}
			Log.LogInfo((object)"Trinket Fortune v1.0.0 loaded. Fishing loot bias active when S.M.U.T. is installed.");
		}
	}
}
namespace TrinketFortune.Patches
{
	public static class FishingTrinketPatches
	{
		public static void ApplyPatches(Harmony harmony)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Utilities), "RandomItem", new Type[1] { typeof(IList<int>) }, (Type[])null);
			if (methodInfo != null)
			{
				HarmonyMethod val = new HarmonyMethod(typeof(FishingTrinketPatches), "RandomItem_Prefix", (Type[])null);
				harmony.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Patched Utilities.RandomItem<int> for fishing museum items");
			}
			else
			{
				Plugin.Log.LogWarning((object)"Could not find Utilities.RandomItem for museum item bias");
			}
			MethodInfo method = typeof(RandomFishArray).GetMethod("RandomItem", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(float) }, null);
			if (method != null)
			{
				harmony.Patch((MethodBase)method, (HarmonyMethod)null, new HarmonyMethod(typeof(FishingTrinketPatches), "RandomFishArray_RandomItem_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"Patched RandomFishArray.RandomItem for fish bias");
			}
			else
			{
				Plugin.Log.LogWarning((object)"Could not find RandomFishArray.RandomItem");
			}
		}

		private static bool RandomItem_Prefix<T>(IList<T> list, ref T __result)
		{
			if (!Config.Enabled.Value)
			{
				return true;
			}
			if (typeof(T) != typeof(int))
			{
				return true;
			}
			if (list == null || list != FishingRod.fishingMuseumItems)
			{
				return true;
			}
			int num = DonationHelper.PickBiasedFishingMuseumItem();
			if (num == 0)
			{
				return true;
			}
			__result = (T)(object)num;
			return false;
		}

		private static void RandomFishArray_RandomItem_Postfix(RandomFishArray __instance, float level, ref FishData __result)
		{
			FishData val = DonationHelper.PickBiasedFish(__instance, level);
			if ((Object)(object)val != (Object)null)
			{
				__result = val;
			}
		}
	}
}
namespace TrinketFortune.DevTools
{
	public class TrinketFortunePanel : IDevToolsPanel
	{
		public string ModGuid => "com.azraelgodking.trinketfortune";

		public string DisplayName => "Trinket Fortune";

		public void Draw(GUIStyle boxStyle, GUIStyle buttonStyle, GUIStyle labelStyle)
		{
			GUILayout.BeginVertical(boxStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label("Trinket Fortune - Fishing Trinket Bias", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label($"Enabled: {Config.Enabled.Value}", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Bonus: +{Config.MuseumProgressBonusPercent.Value}% per 10% aquarium", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			BundleInspector bundleInspector = Plugin.GetBundleInspector();
			if (bundleInspector == null)
			{
				GUILayout.Label("S.M.U.T. not loaded - install Sun Haven Museum Utility Tracker for aquarium data.", labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				return;
			}
			MuseumSectionInfo val = bundleInspector.GetAllSections()?.FirstOrDefault((Func<MuseumSectionInfo, bool>)((MuseumSectionInfo s) => (s.Name?.IndexOf("aquarium", StringComparison.OrdinalIgnoreCase) ?? (-1)) >= 0));
			if (val == null || val.Bundles == null || val.Bundles.Count == 0)
			{
				GUILayout.Label("Aquarium data not available. Ensure S.M.U.T. is installed and loaded.", labelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				return;
			}
			List<(string, int)> list = new List<(string, int)>();
			int num = 0;
			foreach (MuseumBundleInfo bundle in val.Bundles)
			{
				if (((bundle != null) ? bundle.Items : null) == null)
				{
					continue;
				}
				foreach (MuseumItemInfo item3 in bundle.Items)
				{
					num++;
					if (!bundleInspector.HasDonated(item3.Id))
					{
						list.Add((item3.Name, item3.GameItemId));
					}
				}
			}
			DonationStats donationStats = bundleInspector.GetDonationStats();
			if (donationStats.IsLoaded)
			{
				GUILayout.Label("Character: " + donationStats.CharacterName, labelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Label($"Aquarium: {num - list.Count}/{num} donated", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Missing trinkets: {list.Count}", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			if (list.Count > 0)
			{
				GUILayout.Label("Missing items (bias applied when fishing):", labelStyle, Array.Empty<GUILayoutOption>());
				foreach (var item4 in list)
				{
					string item = item4.Item1;
					int item2 = item4.Item2;
					string text = ((item2 > 0) ? $" (ID: {item2})" : " (in-game only)");
					GUILayout.Label("  • " + item + text, labelStyle, Array.Empty<GUILayoutOption>());
				}
			}
			else
			{
				GUILayout.Label("All aquarium trinkets donated!", labelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(6f);
			GUILayout.Label("Note: Main fish and 5% bonus museum items biased toward missing trinkets when S.M.U.T. loaded.", labelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.EndVertical();
		}
	}
}