Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CosmeticTokenPriorityUse v4.0.0
CosmeticTokenPriorityUse.dll
Decompiled a day agousing 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<bool> enabledConfig; private static ConfigEntry<CompletedFallbackOrder> allCosmeticsUnlockedOrderConfig; private static ConfigEntry<bool> refreshTokenUiAfterReorderConfig; private static ConfigEntry<bool> 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<bool>("General", "Enabled", true, "Enables this mod.このMODを有効化します。"); allCosmeticsUnlockedOrderConfig = ((BaseUnityPlugin)this).Config.Bind<CompletedFallbackOrder>("General", "AllCosmeticsUnlockedOrder", CompletedFallbackOrder.Descending, "Token order used when all cosmetics are already unlocked.全コスメ所持済み時のトークン使用順です。"); refreshTokenUiAfterReorderConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RefreshTokenUIAfterReorder", true, "Updates token UI after internally moving the selected token.選択トークンを内部移動した後にトークンUIを更新します。"); debugLogSelectedTokenConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("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<int> cosmeticTokens = GetCosmeticTokens(instance); if (cosmeticTokens == null || cosmeticTokens.Count <= 0) { return; } List<CosmeticAsset> cosmeticAssets = instance.cosmeticAssets; if (cosmeticAssets == null || cosmeticAssets.Count <= 0) { return; } List<int> cosmeticUnlocks = GetCosmeticUnlocks(instance); if (cosmeticUnlocks == null) { return; } HashSet<int> unlockedSet = new HashSet<int>(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<int> GetCosmeticTokens(MetaManager metaManager) { object value = cosmeticTokensField.GetValue(metaManager); return value as List<int>; } private static List<int> GetCosmeticUnlocks(MetaManager metaManager) { object value = cosmeticUnlocksField.GetValue(metaManager); return value as List<int>; } private static int SelectTokenIndex(List<int> tokens, List<CosmeticAsset> assets, HashSet<int> 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<int> tokens, List<CosmeticAsset> assets, HashSet<int> 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<int> 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<int> 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<CosmeticAsset> assets, HashSet<int> 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<CosmeticAsset> assets, HashSet<int> 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<int> tokens, int selectedIndex) { int item = tokens[selectedIndex]; tokens.RemoveAt(selectedIndex); tokens.Add(item); } private static void RefreshTokenUIAfterReorder(int movedIndex, List<int> 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<CosmeticTokenUIElement> 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; } } }