using System; using System.Collections.Generic; 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.CosmeticTokenPriorityUse { [BepInPlugin("REPOJP.CosmeticTokenPriorityUse", "Cosmetic Token Priority Use", "1.0.0")] public sealed class CosmeticTokenPriorityUsePlugin : BaseUnityPlugin { public enum CompletedFallbackOrder { Descending, Ascending } [HarmonyPatch(typeof(CosmeticShopMachine), "Interact")] private static class CosmeticShopMachineInteractPatch { private static bool Prefix() { TryPrepareNextTokenForGacha(); return true; } } public const string PluginGuid = "REPOJP.CosmeticTokenPriorityUse"; public const string PluginName = "Cosmetic Token Priority Use"; public const string PluginVersion = "1.0.0"; private static readonly Rarity[] DescendingRarityOrder; private static readonly Rarity[] AscendingRarityOrder; private static ManualLogSource log; private static ConfigEntry enabledConfig; private static ConfigEntry allCosmeticsUnlockedOrderConfig; private static ConfigEntry refreshTokenUiAfterReorderConfig; private static ConfigEntry debugLogSelectedTokenConfig; private static FieldInfo cosmeticTokensField; private static FieldInfo cosmeticUnlocksField; private static FieldInfo tokenObjectsField; private static FieldInfo tokenElementIndexField; private static FieldInfo tokenElementRarityField; private static FieldInfo tokenElementPositionTargetNextField; private Harmony harmony; private void Awake() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown try { ((Component)this).transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)52; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); log = ((BaseUnityPlugin)this).Logger; BindConfig(); CacheReflectionMembers(); harmony = new Harmony("REPOJP.CosmeticTokenPriorityUse"); harmony.PatchAll(); log.LogInfo((object)"Cosmetic Token Priority Use v1.0.0 loaded."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failure: Failed to load Cosmetic Token Priority Use\n" + ex)); } } private void OnDestroy() { try { if (harmony != null) { harmony.UnpatchSelf(); harmony = null; } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failure: Failed to unload Cosmetic Token Priority Use\n" + ex)); } } private void BindConfig() { enabledConfig = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Enables this mod.このMODを有効化します。"); allCosmeticsUnlockedOrderConfig = ((BaseUnityPlugin)this).Config.Bind("General", "AllCosmeticsUnlockedOrder", CompletedFallbackOrder.Descending, "Token order used when all cosmetics are already unlocked.全コスメ所持済み時のトークン使用順です。"); refreshTokenUiAfterReorderConfig = ((BaseUnityPlugin)this).Config.Bind("General", "RefreshTokenUIAfterReorder", true, "Updates token UI after internally moving the selected token.選択トークンを内部移動した後にトークンUIを更新します。"); debugLogSelectedTokenConfig = ((BaseUnityPlugin)this).Config.Bind("Debug", "DebugLogSelectedToken", false, "Outputs selected token rarity to the BepInEx log.選択されたトークンレアリティをBepInExログに出力します。"); } private static void CacheReflectionMembers() { cosmeticTokensField = AccessTools.Field(typeof(MetaManager), "cosmeticTokens"); cosmeticUnlocksField = AccessTools.Field(typeof(MetaManager), "cosmeticUnlocks"); tokenObjectsField = AccessTools.Field(typeof(CosmeticTokenUI), "tokenObjects"); tokenElementIndexField = AccessTools.Field(typeof(CosmeticTokenUIElement), "index"); tokenElementRarityField = AccessTools.Field(typeof(CosmeticTokenUIElement), "rarity"); tokenElementPositionTargetNextField = AccessTools.Field(typeof(CosmeticTokenUIElement), "positionTargetNext"); } internal static void TryPrepareNextTokenForGacha() { //IL_0104: Unknown result type (might be due to invalid IL or missing references) try { if (enabledConfig == null || !enabledConfig.Value) { return; } if (!HasRequiredReflectionMembers()) { WriteWarning("Failure: Required fields were not found."); return; } MetaManager instance = MetaManager.instance; if ((Object)(object)instance == (Object)null) { return; } List cosmeticTokens = GetCosmeticTokens(instance); if (cosmeticTokens == null || cosmeticTokens.Count <= 0) { return; } List cosmeticAssets = instance.cosmeticAssets; if (cosmeticAssets == null || cosmeticAssets.Count <= 0) { return; } List cosmeticUnlocks = GetCosmeticUnlocks(instance); if (cosmeticUnlocks == null) { return; } HashSet unlockedSet = new HashSet(cosmeticUnlocks); string reason; int num = SelectTokenIndex(cosmeticTokens, cosmeticAssets, unlockedSet, out reason); if (num < 0 || num >= cosmeticTokens.Count) { WriteDebug("No eligible cosmetic token was selected."); return; } Rarity val = (Rarity)cosmeticTokens[num]; if (num != cosmeticTokens.Count - 1) { MoveTokenToEnd(cosmeticTokens, num); RefreshTokenUIAfterReorder(num, cosmeticTokens); } WriteDebug("Selected token: " + ((object)(Rarity)(ref val)).ToString() + " / Reason: " + reason); } catch (Exception ex) { WriteWarning("Failure: Failed to prepare cosmetic token priority.\n" + ex); } } private static bool HasRequiredReflectionMembers() { return cosmeticTokensField != null && cosmeticUnlocksField != null; } private static List GetCosmeticTokens(MetaManager metaManager) { object value = cosmeticTokensField.GetValue(metaManager); return value as List; } private static List GetCosmeticUnlocks(MetaManager metaManager) { object value = cosmeticUnlocksField.GetValue(metaManager); return value as List; } private static int SelectTokenIndex(List tokens, List assets, HashSet unlockedSet, out string reason) { int num = SelectTokenIndexForLockedCosmetic(tokens, assets, unlockedSet, DescendingRarityOrder, out reason); if (num >= 0) { return num; } if (AreAllValidCosmeticsUnlocked(assets, unlockedSet)) { Rarity[] completedFallbackOrder = GetCompletedFallbackOrder(); int num2 = SelectTokenIndexByOwnedTokenOnly(tokens, completedFallbackOrder); if (num2 >= 0) { reason = "All cosmetics unlocked fallback"; return num2; } } reason = "No eligible token"; return -1; } private static int SelectTokenIndexForLockedCosmetic(List tokens, List assets, HashSet unlockedSet, Rarity[] order, out string reason) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) foreach (Rarity rarity in order) { if (HasLockedCosmeticForRarity(assets, unlockedSet, rarity)) { int num = FindLatestTokenIndexForRarity(tokens, rarity); if (num >= 0) { reason = "Locked cosmetic exists"; return num; } } } reason = "No locked cosmetic token match"; return -1; } private static int SelectTokenIndexByOwnedTokenOnly(List tokens, Rarity[] order) { for (int i = 0; i < order.Length; i++) { int num = FindLatestTokenIndexForRarity(tokens, order[i]); if (num >= 0) { return num; } } return -1; } private static Rarity[] GetCompletedFallbackOrder() { if (allCosmeticsUnlockedOrderConfig != null && allCosmeticsUnlockedOrderConfig.Value == CompletedFallbackOrder.Ascending) { return AscendingRarityOrder; } return DescendingRarityOrder; } private static int FindLatestTokenIndexForRarity(List tokens, Rarity rarity) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Expected I4, but got Unknown int num = (int)rarity; for (int num2 = tokens.Count - 1; num2 >= 0; num2--) { if (tokens[num2] == num) { return num2; } } return -1; } private static bool HasLockedCosmeticForRarity(List assets, HashSet unlockedSet, Rarity rarity) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < assets.Count; i++) { CosmeticAsset val = assets[i]; if (IsValidCosmeticAsset(val) && val.rarity == rarity && !unlockedSet.Contains(i)) { return true; } } return false; } private static bool AreAllValidCosmeticsUnlocked(List assets, HashSet unlockedSet) { bool result = false; for (int i = 0; i < assets.Count; i++) { CosmeticAsset asset = assets[i]; if (IsValidCosmeticAsset(asset)) { result = true; if (!unlockedSet.Contains(i)) { return false; } } } return result; } private static bool IsValidCosmeticAsset(CosmeticAsset asset) { try { return (Object)(object)asset != (Object)null && asset.prefab != null && asset.prefab.IsValid(); } catch { return false; } } private static void MoveTokenToEnd(List tokens, int selectedIndex) { int item = tokens[selectedIndex]; tokens.RemoveAt(selectedIndex); tokens.Add(item); } private static void RefreshTokenUIAfterReorder(int movedIndex, List tokens) { try { if (refreshTokenUiAfterReorderConfig == null || !refreshTokenUiAfterReorderConfig.Value) { return; } CosmeticTokenUI instance = CosmeticTokenUI.instance; if ((Object)(object)instance == (Object)null || tokenObjectsField == null) { return; } object value = tokenObjectsField.GetValue(instance); if (!(value is List list) || list.Count != tokens.Count) { instance.Setup(); return; } if (movedIndex >= 0 && movedIndex < list.Count && movedIndex != list.Count - 1) { CosmeticTokenUIElement item = list[movedIndex]; list.RemoveAt(movedIndex); list.Add(item); } for (int i = 0; i < list.Count; i++) { CosmeticTokenUIElement val = list[i]; if (!((Object)(object)val == (Object)null)) { if (tokenElementIndexField != null) { tokenElementIndexField.SetValue(val, i); } if (tokenElementRarityField != null) { tokenElementRarityField.SetValue(val, (object)(Rarity)tokens[i]); } if (tokenElementPositionTargetNextField != null) { tokenElementPositionTargetNextField.SetValue(val, null); } CosmeticTokenUIElement val2 = null; if (i > 0) { val2 = list[i - 1]; } val.Setup(val2); } } if (list.Count > 0) { CosmeticTokenUIElement val3 = list[list.Count - 1]; if ((Object)(object)val3 != (Object)null) { val3.JumpSet(8f); val3.SheenSet(0.05f); } } } catch (Exception ex) { WriteWarning("Failure: Failed to refresh cosmetic token UI after reorder.\n" + ex); } } private static void WriteDebug(string message) { if (debugLogSelectedTokenConfig != null && debugLogSelectedTokenConfig.Value && log != null) { log.LogInfo((object)message); } } private static void WriteWarning(string message) { if (log != null) { log.LogWarning((object)message); } } static CosmeticTokenPriorityUsePlugin() { Rarity[] array = new Rarity[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); DescendingRarityOrder = (Rarity[])(object)array; Rarity[] array2 = new Rarity[4]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); AscendingRarityOrder = (Rarity[])(object)array2; } } }