using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [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("REPOJP")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("zabuMod")] [assembly: AssemblyTitle("zabuMod")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace REPOJP.CosmeticCompleteCashConfig { [BepInPlugin("REPOJP.CosmeticCompleteCashConfig", "CosmeticCompleteCashConfig", "4.0.0")] public class CosmeticCompleteCashConfigPlugin : BaseUnityPlugin { public enum RewardMode { Fixed, RandomRange, Multiplier, Disabled } private enum RarityKey { Common, Uncommon, Rare, UltraRare, Unknown } [HarmonyPatch] private static class CosmeticShopMachineRewardCurrencyPatch { private static Type cosmeticShopMachineType; private static FieldInfo stateImpulseField; private static FieldInfo stateTimerField; private static FieldInfo interactingRewardField; private static FieldInfo interactingRarityField; private static FieldInfo screenCurrencyParticlesField; private static FieldInfo animatorField; private static MethodInfo rewardSetMethod; private static MethodInfo updateStateMethod; private static Type stateType; private static object rewardCurrencyOutroState; private static bool reflectionReady; private static bool reflectionInitialized; private static bool reflectionErrorLogged; private static MethodBase TargetMethod() { InitializeReflection(); if (cosmeticShopMachineType == null) { return null; } return AccessTools.Method(cosmeticShopMachineType, "StateRewardCurrency", (Type[])null, (Type[])null); } private static void InitializeReflection() { if (reflectionInitialized) { return; } reflectionInitialized = true; cosmeticShopMachineType = AccessTools.TypeByName("CosmeticShopMachine"); if (cosmeticShopMachineType == null) { return; } stateImpulseField = AccessTools.Field(cosmeticShopMachineType, "stateImpulse"); stateTimerField = AccessTools.Field(cosmeticShopMachineType, "stateTimer"); interactingRewardField = AccessTools.Field(cosmeticShopMachineType, "interactingReward"); interactingRarityField = AccessTools.Field(cosmeticShopMachineType, "interactingRarity"); screenCurrencyParticlesField = AccessTools.Field(cosmeticShopMachineType, "screenCurrencyParticles"); animatorField = AccessTools.Field(cosmeticShopMachineType, "animator"); rewardSetMethod = AccessTools.Method(cosmeticShopMachineType, "RewardSet", (Type[])null, (Type[])null); updateStateMethod = AccessTools.Method(cosmeticShopMachineType, "UpdateState", (Type[])null, (Type[])null); stateType = AccessTools.Inner(cosmeticShopMachineType, "State"); if (stateType != null) { try { rewardCurrencyOutroState = Enum.Parse(stateType, "RewardCurrencyOutro"); } catch { rewardCurrencyOutroState = null; } } reflectionReady = stateImpulseField != null && stateTimerField != null && interactingRewardField != null && interactingRarityField != null && rewardSetMethod != null && updateStateMethod != null && stateType != null && rewardCurrencyOutroState != null; } private static bool Prefix(object __instance) { if (!IsEnabled()) { return true; } if (__instance == null) { return true; } InitializeReflection(); if (!reflectionReady) { LogReflectionErrorOnce(); return true; } if (!ReflectionGameApi.IsMasterClientOrSingleplayer()) { return true; } try { if (GetStateImpulse(__instance)) { int interactingReward = GetInteractingReward(__instance); if (interactingReward >= 0) { LogDebug("Skipped custom currency reward because interactingReward is not negative. interactingReward=" + interactingReward); return true; } SetStateImpulse(__instance, value: false); object interactingRarity = GetInteractingRarity(__instance); RarityKey rarityKey = GetRarityKey(interactingRarity); int rewardCashK = GetRewardCashK(rarityKey); SetScreenCurrencyParticlesActive(__instance, active: true); InvokeAnimatorCurrencyReward(__instance); InvokeRewardSet(__instance); if (rewardMode.Value != RewardMode.Disabled && rewardCashK > 0) { int runCurrency = ReflectionGameApi.GetRunCurrency(); ReflectionGameApi.SetRunCurrency(runCurrency + rewardCashK); ReflectionGameApi.FetchCurrencyUI(); ReflectionGameApi.ShowShopIncrease(rewardCashK, 3f); } else { ReflectionGameApi.FetchCurrencyUI(); } SetStateTimer(__instance, 1f); LogDebug("Complete cosmetic currency reward. Mode=" + rewardMode.Value.ToString() + " Rarity=" + rarityKey.ToString() + " AmountK=" + rewardCashK); } float stateTimer = GetStateTimer(__instance); stateTimer -= Time.deltaTime; SetStateTimer(__instance, stateTimer); if (stateTimer <= 0f) { InvokeUpdateState(__instance, rewardCurrencyOutroState); } return false; } catch (Exception ex) { LogError("Failure: Cosmetic complete currency patch failed\n" + ex); return true; } } private static void LogReflectionErrorOnce() { if (!reflectionErrorLogged) { reflectionErrorLogged = true; LogError("Failure: CosmeticShopMachine reflection target not found. Vanilla currency reward will be used."); } } private static bool GetStateImpulse(object instance) { if (!(stateImpulseField.GetValue(instance) is bool result)) { return false; } return result; } private static void SetStateImpulse(object instance, bool value) { stateImpulseField.SetValue(instance, value); } private static float GetStateTimer(object instance) { if (!(stateTimerField.GetValue(instance) is float result)) { return 0f; } return result; } private static void SetStateTimer(object instance, float value) { stateTimerField.SetValue(instance, value); } private static int GetInteractingReward(object instance) { if (!(interactingRewardField.GetValue(instance) is int result)) { return -1; } return result; } private static object GetInteractingRarity(object instance) { return interactingRarityField.GetValue(instance); } private static void SetScreenCurrencyParticlesActive(object instance, bool active) { if (!(screenCurrencyParticlesField == null)) { object value = screenCurrencyParticlesField.GetValue(instance); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val != (Object)null) { val.SetActive(active); } } } private static void InvokeAnimatorCurrencyReward(object instance) { if (animatorField == null) { return; } object value = animatorField.GetValue(instance); if (value != null) { MethodInfo methodInfo = AccessTools.Method(value.GetType(), "EventScreenCurrencyReward", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(value, null); } } } private static void InvokeRewardSet(object instance) { rewardSetMethod.Invoke(instance, null); } private static void InvokeUpdateState(object instance, object state) { updateStateMethod.Invoke(instance, new object[1] { state }); } } private static class ReflectionGameApi { private static Type semiFuncType; private static MethodInfo isMasterClientOrSingleplayerMethod; private static MethodInfo statGetRunCurrencyMethod; private static MethodInfo statSetRunCurrencyMethod; private static Type currencyUiType; private static FieldInfo currencyUiInstanceField; private static MethodInfo currencyUiFetchCurrencyMethod; private static Type shopIncreaseUiType; private static FieldInfo shopIncreaseUiInstanceField; private static MethodInfo shopIncreaseUiShowIncreaseMethod; private static bool initialized; private static void Initialize() { if (!initialized) { initialized = true; semiFuncType = AccessTools.TypeByName("SemiFunc"); if (semiFuncType != null) { isMasterClientOrSingleplayerMethod = AccessTools.Method(semiFuncType, "IsMasterClientOrSingleplayer", (Type[])null, (Type[])null); statGetRunCurrencyMethod = AccessTools.Method(semiFuncType, "StatGetRunCurrency", (Type[])null, (Type[])null); statSetRunCurrencyMethod = AccessTools.Method(semiFuncType, "StatSetRunCurrency", new Type[1] { typeof(int) }, (Type[])null); } currencyUiType = AccessTools.TypeByName("CurrencyUI"); if (currencyUiType != null) { currencyUiInstanceField = AccessTools.Field(currencyUiType, "instance"); currencyUiFetchCurrencyMethod = AccessTools.Method(currencyUiType, "FetchCurrency", (Type[])null, (Type[])null); } shopIncreaseUiType = AccessTools.TypeByName("ShopIncreaseUI"); if (shopIncreaseUiType != null) { shopIncreaseUiInstanceField = AccessTools.Field(shopIncreaseUiType, "instance"); shopIncreaseUiShowIncreaseMethod = AccessTools.Method(shopIncreaseUiType, "ShowIncrease", new Type[2] { typeof(int), typeof(float) }, (Type[])null); } } } public static bool IsMasterClientOrSingleplayer() { Initialize(); if (isMasterClientOrSingleplayerMethod == null) { return false; } if (!(isMasterClientOrSingleplayerMethod.Invoke(null, null) is bool result)) { return false; } return result; } public static int GetRunCurrency() { Initialize(); if (statGetRunCurrencyMethod == null) { return 0; } if (!(statGetRunCurrencyMethod.Invoke(null, null) is int result)) { return 0; } return result; } public static void SetRunCurrency(int value) { Initialize(); if (statSetRunCurrencyMethod != null) { statSetRunCurrencyMethod.Invoke(null, new object[1] { value }); } } public static void FetchCurrencyUI() { Initialize(); if (!(currencyUiInstanceField == null) && !(currencyUiFetchCurrencyMethod == null)) { object value = currencyUiInstanceField.GetValue(null); if (value != null) { currencyUiFetchCurrencyMethod.Invoke(value, null); } } } public static void ShowShopIncrease(int amountK, float duration) { Initialize(); if (!(shopIncreaseUiInstanceField == null) && !(shopIncreaseUiShowIncreaseMethod == null)) { object value = shopIncreaseUiInstanceField.GetValue(null); if (value != null) { shopIncreaseUiShowIncreaseMethod.Invoke(value, new object[2] { amountK, duration }); } } } } public const string PluginGuid = "REPOJP.CosmeticCompleteCashConfig"; public const string PluginName = "CosmeticCompleteCashConfig"; public const string PluginVersion = "4.0.0"; private static ManualLogSource logger; private Harmony harmony; private static ConfigEntry enable; private static ConfigEntry showDebugLog; private static ConfigEntry rewardMode; private static ConfigEntry commonCash; private static ConfigEntry uncommonCash; private static ConfigEntry rareCash; private static ConfigEntry ultraRareCash; private static ConfigEntry commonMinCash; private static ConfigEntry commonMaxCash; private static ConfigEntry uncommonMinCash; private static ConfigEntry uncommonMaxCash; private static ConfigEntry rareMinCash; private static ConfigEntry rareMaxCash; private static ConfigEntry ultraRareMinCash; private static ConfigEntry ultraRareMaxCash; private static ConfigEntry commonMultiplier; private static ConfigEntry uncommonMultiplier; private static ConfigEntry rareMultiplier; private static ConfigEntry ultraRareMultiplier; private void Awake() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown try { ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); logger = ((BaseUnityPlugin)this).Logger; BindConfig(); harmony = new Harmony("REPOJP.CosmeticCompleteCashConfig"); harmony.PatchAll(); logger.LogInfo((object)"CosmeticCompleteCashConfig v4.0.0 loaded."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Failed to load CosmeticCompleteCashConfig\n" + ex)); } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Failed to unload CosmeticCompleteCashConfig\n" + ex)); } } private void BindConfig() { enable = ((BaseUnityPlugin)this).Config.Bind("General", "Enable", true, "Enable this mod.このMODを有効化"); showDebugLog = ((BaseUnityPlugin)this).Config.Bind("General", "ShowDebugLog", false, "Show debug logs.デバッグログを表示"); rewardMode = ((BaseUnityPlugin)this).Config.Bind("Mode", "RewardMode", RewardMode.Fixed, "Currency reward mode after all cosmetics are owned.全コスメ取得後の通貨変換モード"); commonCash = ((BaseUnityPlugin)this).Config.Bind("Fixed", "CommonCash", 2000, "Common complete duplicate cash reward.コモン全取得後重複報酬額"); uncommonCash = ((BaseUnityPlugin)this).Config.Bind("Fixed", "UncommonCash", 4000, "Uncommon complete duplicate cash reward.アンコモン全取得後重複報酬額"); rareCash = ((BaseUnityPlugin)this).Config.Bind("Fixed", "RareCash", 8000, "Rare complete duplicate cash reward.レア全取得後重複報酬額"); ultraRareCash = ((BaseUnityPlugin)this).Config.Bind("Fixed", "UltraRareCash", 15000, "Ultra Rare complete duplicate cash reward.ウルトラレア全取得後重複報酬額"); commonMinCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "CommonMinCash", 0, "Common minimum complete duplicate cash reward.コモン全取得後最小重複報酬額"); commonMaxCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "CommonMaxCash", 2000, "Common maximum complete duplicate cash reward.コモン全取得後最大重複報酬額"); uncommonMinCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "UncommonMinCash", 1000, "Uncommon minimum complete duplicate cash reward.アンコモン全取得後最小重複報酬額"); uncommonMaxCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "UncommonMaxCash", 4000, "Uncommon maximum complete duplicate cash reward.アンコモン全取得後最大重複報酬額"); rareMinCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "RareMinCash", 2000, "Rare minimum complete duplicate cash reward.レア全取得後最小重複報酬額"); rareMaxCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "RareMaxCash", 8000, "Rare maximum complete duplicate cash reward.レア全取得後最大重複報酬額"); ultraRareMinCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "UltraRareMinCash", 4000, "Ultra Rare minimum complete duplicate cash reward.ウルトラレア全取得後最小重複報酬額"); ultraRareMaxCash = ((BaseUnityPlugin)this).Config.Bind("RandomRange", "UltraRareMaxCash", 20000, "Ultra Rare maximum complete duplicate cash reward.ウルトラレア全取得後最大重複報酬額"); commonMultiplier = ((BaseUnityPlugin)this).Config.Bind("Multiplier", "CommonMultiplier", 0.8f, "Common complete duplicate cash multiplier.コモン全取得後重複報酬倍率"); uncommonMultiplier = ((BaseUnityPlugin)this).Config.Bind("Multiplier", "UncommonMultiplier", 0.8f, "Uncommon complete duplicate cash multiplier.アンコモン全取得後重複報酬倍率"); rareMultiplier = ((BaseUnityPlugin)this).Config.Bind("Multiplier", "RareMultiplier", 0.8f, "Rare complete duplicate cash multiplier.レア全取得後重複報酬倍率"); ultraRareMultiplier = ((BaseUnityPlugin)this).Config.Bind("Multiplier", "UltraRareMultiplier", 1.5f, "Ultra Rare complete duplicate cash multiplier.ウルトラレア全取得後重複報酬倍率"); } private static bool IsEnabled() { return enable != null && enable.Value; } private static void LogDebug(string message) { if (showDebugLog != null && showDebugLog.Value && logger != null) { logger.LogInfo((object)message); } } private static void LogError(string message) { if (logger != null) { logger.LogError((object)message); } } private static int GetRewardCashK(RarityKey rarity) { if (rewardMode.Value == RewardMode.Disabled) { return 0; } return CashToInternalCurrency(rewardMode.Value switch { RewardMode.RandomRange => GetRandomRangeCash(rarity), RewardMode.Multiplier => GetMultiplierCash(rarity), _ => GetFixedCash(rarity), }); } private static int GetFixedCash(RarityKey rarity) { return rarity switch { RarityKey.Common => Mathf.Max(0, commonCash.Value), RarityKey.Uncommon => Mathf.Max(0, uncommonCash.Value), RarityKey.Rare => Mathf.Max(0, rareCash.Value), RarityKey.UltraRare => Mathf.Max(0, ultraRareCash.Value), _ => 0, }; } private static int GetRandomRangeCash(RarityKey rarity) { GetRangeCash(rarity, out var minCash, out var maxCash); minCash = Mathf.Max(0, minCash); maxCash = Mathf.Max(0, maxCash); if (minCash > maxCash) { int num = minCash; minCash = maxCash; maxCash = num; LogDebug("RandomRange swapped. Rarity=" + rarity.ToString() + " Min=" + minCash + " Max=" + maxCash); } if (minCash == maxCash) { return minCash; } if (maxCash == int.MaxValue) { return Random.Range(minCash, maxCash); } return Random.Range(minCash, maxCash + 1); } private static void GetRangeCash(RarityKey rarity, out int minCash, out int maxCash) { switch (rarity) { case RarityKey.Common: minCash = commonMinCash.Value; maxCash = commonMaxCash.Value; break; case RarityKey.Uncommon: minCash = uncommonMinCash.Value; maxCash = uncommonMaxCash.Value; break; case RarityKey.Rare: minCash = rareMinCash.Value; maxCash = rareMaxCash.Value; break; case RarityKey.UltraRare: minCash = ultraRareMinCash.Value; maxCash = ultraRareMaxCash.Value; break; default: minCash = 0; maxCash = 0; break; } } private static int GetMultiplierCash(RarityKey rarity) { int vanillaCash = GetVanillaCash(rarity); float multiplier = GetMultiplier(rarity); multiplier = Mathf.Max(0f, multiplier); return Mathf.Max(0, Mathf.RoundToInt((float)vanillaCash * multiplier)); } private static float GetMultiplier(RarityKey rarity) { return rarity switch { RarityKey.Common => commonMultiplier.Value, RarityKey.Uncommon => uncommonMultiplier.Value, RarityKey.Rare => rareMultiplier.Value, RarityKey.UltraRare => ultraRareMultiplier.Value, _ => 0f, }; } private static int GetVanillaCash(RarityKey rarity) { return rarity switch { RarityKey.Common => 2000, RarityKey.Uncommon => 4000, RarityKey.Rare => 8000, RarityKey.UltraRare => 15000, _ => 0, }; } private static int CashToInternalCurrency(int cash) { cash = Mathf.Max(0, cash); if (cash <= 0) { return 0; } return Mathf.Max(0, Mathf.RoundToInt((float)cash / 1000f)); } private static RarityKey GetRarityKey(object rarityValue) { if (rarityValue == null) { return RarityKey.Unknown; } string a = rarityValue.ToString(); if (string.Equals(a, "Common", StringComparison.OrdinalIgnoreCase)) { return RarityKey.Common; } if (string.Equals(a, "Uncommon", StringComparison.OrdinalIgnoreCase)) { return RarityKey.Uncommon; } if (string.Equals(a, "Rare", StringComparison.OrdinalIgnoreCase)) { return RarityKey.Rare; } if (string.Equals(a, "UltraRare", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Ultra Rare", StringComparison.OrdinalIgnoreCase)) { return RarityKey.UltraRare; } return RarityKey.Unknown; } } }