Decompiled source of Fresh Wheel Spins v1.0.0

plugins/FreshWheelSkins/FreshWheelSkins.dll

Decompiled a day 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 FishNet.Object;
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("Estonia")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Prevents duplicate slot machine skin rewards in How to Fish.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FreshWheelSkins")]
[assembly: AssemblyTitle("FreshWheelSkins")]
[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 FreshWheelSkins
{
	[BepInPlugin("estonia.howtofish.freshwheelskins", "Fresh Wheel Skins", "1.0.0")]
	[BepInProcess("How to Fish.exe")]
	public sealed class FreshWheelSkinsPlugin : BaseUnityPlugin
	{
		private readonly struct Reward
		{
			public byte ItemId { get; }

			public byte SkinIndex { get; }

			public Reward(byte itemId, byte skinIndex)
			{
				ItemId = itemId;
				SkinIndex = skinIndex;
			}
		}

		[HarmonyPatch(typeof(SlotMachine), "Roll")]
		private static class SlotMachineRollPatch
		{
			private static void Prefix(Player roller, byte[] itemIDs, byte[] itemSkins, byte rolled)
			{
				try
				{
					_instance?.ReplaceDuplicateReward(roller, itemIDs, itemSkins, rolled);
				}
				catch (Exception arg)
				{
					FreshWheelSkinsPlugin instance = _instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogError((object)$"Failed to replace duplicate wheel skin: {arg}");
					}
				}
			}
		}

		private const string PluginGuid = "estonia.howtofish.freshwheelskins";

		private const string PluginName = "Fresh Wheel Skins";

		private const string PluginVersion = "1.0.0";

		private const string Author = "Estonia";

		private static readonly FieldInfo CurLocalSaveField = AccessTools.Field(typeof(SaveManager), "_curLocalSave");

		private static FreshWheelSkinsPlugin _instance;

		private ConfigEntry<bool> _keepRarity;

		private ConfigEntry<bool> _allowOtherPrizeItems;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			_instance = this;
			_keepRarity = ((BaseUnityPlugin)this).Config.Bind<bool>("Wheel", "KeepRarityFirst", true, (ConfigDescription)null);
			_allowOtherPrizeItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Wheel", "UseOtherPrizeItemsWhenNeeded", true, (ConfigDescription)null);
			_harmony = new Harmony("estonia.howtofish.freshwheelskins");
			_harmony.PatchAll(typeof(FreshWheelSkinsPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Fresh Wheel Skins 1.0.0 loaded. Author: Estonia.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void ReplaceDuplicateReward(Player roller, byte[] itemIDs, byte[] itemSkins, byte rolled)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)roller) || itemIDs == null || itemSkins == null || rolled >= itemIDs.Length || rolled >= itemSkins.Length || !((NetworkBehaviour)roller).Owner.IsLocalClient)
			{
				return;
			}
			object? obj = CurLocalSaveField?.GetValue(null);
			LocalSaveObject val = (LocalSaveObject)((obj is LocalSaveObject) ? obj : null);
			if (val == null)
			{
				return;
			}
			byte b = itemIDs[rolled];
			byte b2 = itemSkins[rolled];
			SkinPreset preset = GetPreset(b);
			if (Object.op_Implicit((Object)(object)preset) && b2 < preset.Skins.Count && IsOwned(val, b, b2))
			{
				ItemSkin val2 = preset.Skins[b2];
				Rarity rarity = ((ItemSkin)(ref val2)).Rarity;
				if ((!_keepRarity.Value || !TryFindUnowned(val, new byte[1] { b }, rarity, out var reward)) && (!_allowOtherPrizeItems.Value || !_keepRarity.Value || !TryFindUnowned(val, GetPrizeItemIds(), rarity, out reward)) && !TryFindUnowned(val, new byte[1] { b }, null, out reward) && (!_allowOtherPrizeItems.Value || !TryFindUnowned(val, GetPrizeItemIds(), null, out reward)))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)"Wheel rolled a duplicate skin, but there are no locked wheel skins left to swap in.");
					return;
				}
				itemIDs[rolled] = reward.ItemId;
				itemSkins[rolled] = reward.SkinIndex;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Replaced duplicate wheel skin " + Describe(b, b2) + " with " + Describe(reward.ItemId, reward.SkinIndex) + "."));
			}
		}

		private static bool TryFindUnowned(LocalSaveObject save, IEnumerable<byte> itemIds, Rarity? rarity, out Reward reward)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			List<Reward> list = new List<Reward>();
			foreach (byte itemId in itemIds)
			{
				SkinPreset preset = GetPreset(itemId);
				if (!Object.op_Implicit((Object)(object)preset))
				{
					continue;
				}
				for (int i = 0; i < preset.Skins.Count && i <= 255; i++)
				{
					ItemSkin val = preset.Skins[i];
					if ((int)((ItemSkin)(ref val)).Rarity != 0 && (!rarity.HasValue || ((ItemSkin)(ref val)).Rarity == rarity.Value))
					{
						byte skinIndex = (byte)i;
						if (!IsOwned(save, itemId, skinIndex))
						{
							list.Add(new Reward(itemId, skinIndex));
						}
					}
				}
			}
			if (list.Count == 0)
			{
				reward = default(Reward);
				return false;
			}
			reward = list[Random.Range(0, list.Count)];
			return true;
		}

		private static IEnumerable<byte> GetPrizeItemIds()
		{
			HashSet<byte> ids = new HashSet<byte>();
			Item[] availableItems = SlotMachine.AvailableItems;
			if (availableItems != null)
			{
				Item[] array = availableItems;
				foreach (Item val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.SkinPreset) && ids.Add(val.ID))
					{
						yield return val.ID;
					}
				}
			}
			if (!SlotMachine.ExcludeBoat)
			{
				yield return byte.MaxValue;
			}
		}

		private static SkinPreset GetPreset(byte itemId)
		{
			if (itemId == byte.MaxValue)
			{
				if (!Object.op_Implicit((Object)(object)BoatManager.Boat))
				{
					return null;
				}
				return BoatManager.Boat.SkinPreset;
			}
			Item val = GameInfo.IDToItem(itemId);
			if (!Object.op_Implicit((Object)(object)val))
			{
				return null;
			}
			return val.SkinPreset;
		}

		private static bool IsOwned(LocalSaveObject save, byte itemId, byte skinIndex)
		{
			if (itemId == byte.MaxValue)
			{
				if (save.UnlockedBoatSkins != null)
				{
					return save.UnlockedBoatSkins.Contains(skinIndex);
				}
				return false;
			}
			if (save.UnlockedItemSkins == null)
			{
				return false;
			}
			foreach (SavedItemSkin unlockedItemSkin in save.UnlockedItemSkins)
			{
				if (unlockedItemSkin != null && unlockedItemSkin.ID == itemId)
				{
					return unlockedItemSkin.SkinsUnlocked != null && unlockedItemSkin.SkinsUnlocked.Contains(skinIndex);
				}
			}
			return false;
		}

		private static string Describe(byte itemId, byte skinIndex)
		{
			if (itemId == byte.MaxValue)
			{
				return $"Boat/{skinIndex}";
			}
			Item val = GameInfo.IDToItem(itemId);
			return $"{(Object.op_Implicit((Object)(object)val) ? ((Object)val).name : itemId.ToString())}/{skinIndex}";
		}
	}
}