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 _keepRarity; private ConfigEntry _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("Wheel", "KeepRarityFirst", true, (ConfigDescription)null); _allowOtherPrizeItems = ((BaseUnityPlugin)this).Config.Bind("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 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 list = new List(); 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 GetPrizeItemIds() { HashSet ids = new HashSet(); 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}"; } } }