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 Empress Achievements v2.0.1
BepInEx\plugins\Empress_Achievements\RepoAchievements.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.UI; [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("Empress")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+79ae26948f15ddd0825c08f9c67eab7df2c0586c")] [assembly: AssemblyProduct("RepoAchievements")] [assembly: AssemblyTitle("RepoAchievements")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 Empress.REPO.Achievements { [HarmonyPatch] internal static class EmpressAchievementsPlus { private readonly struct ThresholdAchievement { public readonly string Id; public readonly long Threshold; public readonly string Title; public readonly string Description; public ThresholdAchievement(string id, long threshold, string title, string description) { Id = id; Threshold = threshold; Title = title; Description = description; } } private readonly struct SpreeAchievement { public readonly string Id; public readonly int Count; public readonly float WindowSeconds; public readonly string Title; public readonly string Description; public SpreeAchievement(string id, int count, float windowSeconds, string title, string description) { Id = id; Count = count; WindowSeconds = windowSeconds; Title = title; Description = description; } } private readonly struct EnemyTypeInfo { public readonly string Id; public readonly string Label; public readonly string HundredTitle; public EnemyTypeInfo(string id, string label, string hundredTitle) { Id = id; Label = label; HundredTitle = hundredTitle; } } private static readonly Queue<float> KillTimestamps = new Queue<float>(); private static bool Defined; private static readonly ThresholdAchievement[] MetaAchievements = new ThresholdAchievement[10] { new ThresholdAchievement("ach_meta_10", 10L, "Warmed Up", "Unlock 10 achievements."), new ThresholdAchievement("ach_meta_25", 25L, "On Your Way", "Unlock 25 achievements."), new ThresholdAchievement("ach_meta_50", 50L, "Certified Collector", "Unlock 50 achievements."), new ThresholdAchievement("ach_meta_75", 75L, "Overachiever", "Unlock 75 achievements."), new ThresholdAchievement("ach_meta_90", 90L, "No Brakes", "Unlock 90 achievements."), new ThresholdAchievement("ach_meta_100", 100L, "Triple Digits", "Unlock 100 achievements."), new ThresholdAchievement("ach_meta_125", 125L, "Badge Buffet", "Unlock 125 achievements."), new ThresholdAchievement("ach_meta_150", 150L, "Archive Monster", "Unlock 150 achievements."), new ThresholdAchievement("ach_meta_175", 175L, "Cabinet Crusher", "Unlock 175 achievements."), new ThresholdAchievement("ach_meta_200", 200L, "Empress Certified", "Unlock 200 achievements.") }; private static readonly ThresholdAchievement[] ExtractionAchievements = new ThresholdAchievement[5] { new ThresholdAchievement("extract_300", 300L, "Night Shift", "Complete 300 extractions (lifetime)."), new ThresholdAchievement("extract_500", 500L, "Route Owned", "Complete 500 extractions (lifetime)."), new ThresholdAchievement("extract_750", 750L, "Platform Ghost", "Complete 750 extractions (lifetime)."), new ThresholdAchievement("extract_1000", 1000L, "Timetable Tyrant", "Complete 1,000 extractions (lifetime)."), new ThresholdAchievement("extract_2000", 2000L, "Terminal Deity", "Complete 2,000 extractions (lifetime).") }; private static readonly ThresholdAchievement[] DiscoveryAchievements = new ThresholdAchievement[10] { new ThresholdAchievement("discover_5", 5L, "Shiny Thing", "Discover 5 valuables."), new ThresholdAchievement("discover_10", 10L, "Curio Finder", "Discover 10 valuables."), new ThresholdAchievement("discover_25", 25L, "Antiquarian", "Discover 25 valuables."), new ThresholdAchievement("discover_50", 50L, "Treasure Sleuth", "Discover 50 valuables."), new ThresholdAchievement("discover_75", 75L, "Display Case", "Discover 75 valuables."), new ThresholdAchievement("discover_100", 100L, "Museum Curator", "Discover 100 valuables."), new ThresholdAchievement("discover_150", 150L, "Treasure Map Brain", "Discover 150 valuables."), new ThresholdAchievement("discover_250", 250L, "Vault Tourist", "Discover 250 valuables."), new ThresholdAchievement("discover_500", 500L, "Curation Problem", "Discover 500 valuables."), new ThresholdAchievement("discover_1000", 1000L, "Relic Census", "Discover 1,000 valuables.") }; private static readonly ThresholdAchievement[] LifetimePurchaseAchievements = new ThresholdAchievement[6] { new ThresholdAchievement("big_spender_5", 5L, "Browsing No More", "Purchase 5 items (lifetime)."), new ThresholdAchievement("big_spender_75", 75L, "Impulse Engine", "Purchase 75 items (lifetime)."), new ThresholdAchievement("big_spender_150", 150L, "Receipt Collector", "Purchase 150 items (lifetime)."), new ThresholdAchievement("big_spender_250", 250L, "Bag Secured", "Purchase 250 items (lifetime)."), new ThresholdAchievement("big_spender_500", 500L, "Market Mover", "Purchase 500 items (lifetime)."), new ThresholdAchievement("big_spender_1000", 1000L, "Checkout Monarch", "Purchase 1,000 items (lifetime).") }; private static readonly ThresholdAchievement[] LifetimeDeathAchievements = new ThresholdAchievement[6] { new ThresholdAchievement("death_75", 75L, "Bruise Budget", "Die 75 times."), new ThresholdAchievement("death_150", 150L, "Frequent Flyer Home", "Die 150 times."), new ThresholdAchievement("death_250", 250L, "Ragdoll Royalty", "Die 250 times."), new ThresholdAchievement("death_750", 750L, "Pain Dividend", "Die 750 times."), new ThresholdAchievement("death_1000", 1000L, "Afterlife Residency", "Die 1,000 times."), new ThresholdAchievement("death_2500", 2500L, "Professional Corpse", "Die 2,500 times.") }; private static readonly ThresholdAchievement[] LifetimeReviveAchievements = new ThresholdAchievement[6] { new ThresholdAchievement("revived_5", 5L, "Still Standing", "Be revived 5 times."), new ThresholdAchievement("revived_25", 25L, "Miracle Mileage", "Be revived 25 times."), new ThresholdAchievement("revived_100", 100L, "Defibrillator Darling", "Be revived 100 times."), new ThresholdAchievement("revived_250", 250L, "Return Policy", "Be revived 250 times."), new ThresholdAchievement("revived_500", 500L, "Unfinished Business", "Be revived 500 times."), new ThresholdAchievement("revived_1000", 1000L, "Too Stubborn To Die", "Be revived 1,000 times.") }; private static readonly ThresholdAchievement[] LifetimeHaulAchievements = new ThresholdAchievement[12] { new ThresholdAchievement("life_haul_75k", 75000L, "Coin Pile", "Accumulate 75,000 haul (lifetime)."), new ThresholdAchievement("life_haul_150k", 150000L, "Payroll Problem", "Accumulate 150,000 haul (lifetime)."), new ThresholdAchievement("life_haul_300k", 300000L, "Treasure Warehouse", "Accumulate 300,000 haul (lifetime)."), new ThresholdAchievement("life_haul_750k", 750000L, "Bag Mountain", "Accumulate 750,000 haul (lifetime)."), new ThresholdAchievement("life_haul_1p5m", 1500000L, "Capital Gain", "Accumulate 1,500,000 haul (lifetime)."), new ThresholdAchievement("life_haul_3m", 3000000L, "Fortune Engine", "Accumulate 3,000,000 haul (lifetime)."), new ThresholdAchievement("life_haul_7p5m", 7500000L, "Vault Fever", "Accumulate 7,500,000 haul (lifetime)."), new ThresholdAchievement("life_haul_15m", 15000000L, "Estate Sale", "Accumulate 15,000,000 haul (lifetime)."), new ThresholdAchievement("life_haul_30m", 30000000L, "Treasure State", "Accumulate 30,000,000 haul (lifetime)."), new ThresholdAchievement("life_haul_75m", 75000000L, "Museum Theft", "Accumulate 75,000,000 haul (lifetime)."), new ThresholdAchievement("life_haul_100m", 100000000L, "Nine Digits", "Accumulate 100,000,000 haul (lifetime)."), new ThresholdAchievement("life_haul_250m", 250000000L, "Economic Event", "Accumulate 250,000,000 haul (lifetime).") }; private static readonly ThresholdAchievement[] RunPurchaseAchievements = new ThresholdAchievement[9] { new ThresholdAchievement("run_purchases_5", 5L, "Bag Starter", "Buy 5 items in a single run."), new ThresholdAchievement("run_purchases_10", 10L, "Shopaholic (Run)", "Buy 10 items in a single run."), new ThresholdAchievement("run_purchases_15", 15L, "Basket Case", "Buy 15 items in a single run."), new ThresholdAchievement("run_purchases_20", 20L, "Receipt Storm", "Buy 20 items in a single run."), new ThresholdAchievement("run_purchases_25", 25L, "Retail Bender", "Buy 25 items in a single run."), new ThresholdAchievement("run_purchases_30", 30L, "Checkout Sprint", "Buy 30 items in a single run."), new ThresholdAchievement("run_purchases_40", 40L, "Mall Marathon", "Buy 40 items in a single run."), new ThresholdAchievement("run_purchases_50", 50L, "Store Sweep", "Buy 50 items in a single run."), new ThresholdAchievement("run_purchases_75", 75L, "Inventory Collapse", "Buy 75 items in a single run.") }; private static readonly ThresholdAchievement[] RunDeathAchievements = new ThresholdAchievement[8] { new ThresholdAchievement("deaths_run_3", 3L, "Trip Hazard", "Die 3 times in a single run."), new ThresholdAchievement("deaths_run_5", 5L, "Learning Hurts", "Die 5 times in a single run."), new ThresholdAchievement("deaths_run_7", 7L, "Bruise Loop", "Die 7 times in a single run."), new ThresholdAchievement("deaths_run_10", 10L, "Pain Enthusiast", "Die 10 times in a single run."), new ThresholdAchievement("deaths_run_15", 15L, "Red Screen Residency", "Die 15 times in a single run."), new ThresholdAchievement("deaths_run_20", 20L, "Certified Masochist", "Die 20 times in a single run."), new ThresholdAchievement("deaths_run_25", 25L, "Spawn Tax", "Die 25 times in a single run."), new ThresholdAchievement("deaths_run_50", 50L, "Hazard Magnet", "Die 50 times in a single run.") }; private static readonly ThresholdAchievement[] RunKillAchievements = new ThresholdAchievement[10] { new ThresholdAchievement("run_kills_5", 5L, "Warmup Violence", "Eliminate 5 enemies in a single run."), new ThresholdAchievement("run_kills_10", 10L, "Cleanup Crew", "Eliminate 10 enemies in a single run."), new ThresholdAchievement("run_kills_15", 15L, "Run Riot", "Eliminate 15 enemies in a single run."), new ThresholdAchievement("run_kills_25", 25L, "Bloody Hands", "Eliminate 25 enemies in a single run."), new ThresholdAchievement("run_kills_50", 50L, "Crowd Control", "Eliminate 50 enemies in a single run."), new ThresholdAchievement("run_kills_75", 75L, "Corridor Clearer", "Eliminate 75 enemies in a single run."), new ThresholdAchievement("run_kills_100", 100L, "Neighborhood Watch", "Eliminate 100 enemies in a single run."), new ThresholdAchievement("run_kills_150", 150L, "Run Terminator", "Eliminate 150 enemies in a single run."), new ThresholdAchievement("run_kills_250", 250L, "Room Zero", "Eliminate 250 enemies in a single run."), new ThresholdAchievement("run_kills_500", 500L, "Extinction Event", "Eliminate 500 enemies in a single run.") }; private static readonly ThresholdAchievement[] LifetimeKillAchievements = new ThresholdAchievement[7] { new ThresholdAchievement("kills_750", 750L, "Bad Neighborhood", "Eliminate 750 enemies."), new ThresholdAchievement("kills_7500", 7500L, "Hazard Department", "Eliminate 7,500 enemies."), new ThresholdAchievement("kills_10000", 10000L, "Bureau of Population", "Eliminate 10,000 enemies."), new ThresholdAchievement("kills_15000", 15000L, "Local Legend", "Eliminate 15,000 enemies."), new ThresholdAchievement("kills_25000", 25000L, "Body Count Clerk", "Eliminate 25,000 enemies."), new ThresholdAchievement("kills_50000", 50000L, "Extinction Budget", "Eliminate 50,000 enemies."), new ThresholdAchievement("kills_100000", 100000L, "Disaster Economist", "Eliminate 100,000 enemies.") }; private static readonly ThresholdAchievement[] ChargeSessionAchievements = new ThresholdAchievement[8] { new ThresholdAchievement("charge_session_1", 1L, "Juiced", "Start charging at a station."), new ThresholdAchievement("charge_session_5", 5L, "Outlet Friend", "Start charging at stations 5 times."), new ThresholdAchievement("charge_session_10", 10L, "Power User", "Start charging at stations 10 times."), new ThresholdAchievement("charge_session_25", 25L, "Grid Hog", "Start charging at stations 25 times."), new ThresholdAchievement("charge_session_50", 50L, "Socket Specialist", "Start charging at stations 50 times."), new ThresholdAchievement("charge_session_100", 100L, "Grid Romantic", "Start charging at stations 100 times."), new ThresholdAchievement("charge_session_250", 250L, "Transformer Whisperer", "Start charging at stations 250 times."), new ThresholdAchievement("charge_session_500", 500L, "Power Parasite", "Start charging at stations 500 times.") }; private static readonly ThresholdAchievement[] ChargeTotalAchievements = new ThresholdAchievement[10] { new ThresholdAchievement("charge_total_50", 50L, "Spark Touched", "Accumulate 50 total station charge in a run."), new ThresholdAchievement("charge_total_100", 100L, "Watt About It", "Accumulate 100 total station charge in a run."), new ThresholdAchievement("charge_total_250", 250L, "Static Drinker", "Accumulate 250 total station charge in a run."), new ThresholdAchievement("charge_total_500", 500L, "Peak Demand", "Accumulate 500 total station charge in a run."), new ThresholdAchievement("charge_total_750", 750L, "Amp Appetite", "Accumulate 750 total station charge in a run."), new ThresholdAchievement("charge_total_1000", 1000L, "Brownout", "Accumulate 1,000 total station charge in a run."), new ThresholdAchievement("charge_total_1500", 1500L, "Voltage Appetite", "Accumulate 1,500 total station charge in a run."), new ThresholdAchievement("charge_total_2500", 2500L, "Overclocked Soul", "Accumulate 2,500 total station charge in a run."), new ThresholdAchievement("charge_total_5000", 5000L, "Grid Collapse", "Accumulate 5,000 total station charge in a run."), new ThresholdAchievement("charge_total_10000", 10000L, "Citywide Brownout", "Accumulate 10,000 total station charge in a run.") }; private static readonly ThresholdAchievement[] RunMoneyAchievements = new ThresholdAchievement[10] { new ThresholdAchievement("run_money_125000", 125000L, "Loaded", "Reach 125,000 run currency."), new ThresholdAchievement("run_money_150000", 150000L, "High Roller", "Reach 150,000 run currency."), new ThresholdAchievement("run_money_200000", 200000L, "Cash Current", "Reach 200,000 run currency."), new ThresholdAchievement("run_money_250000", 250000L, "Mega Whale", "Reach 250,000 run currency."), new ThresholdAchievement("run_money_300000", 300000L, "Money Pit Boss", "Reach 300,000 run currency."), new ThresholdAchievement("run_money_400000", 400000L, "Wall of Bills", "Reach 400,000 run currency."), new ThresholdAchievement("run_money_500000", 500000L, "Infinite Wallet", "Reach 500,000 run currency."), new ThresholdAchievement("run_money_750000", 750000L, "Private Bank", "Reach 750,000 run currency."), new ThresholdAchievement("run_money_1000000", 1000000L, "Seven Digits", "Reach 1,000,000 run currency."), new ThresholdAchievement("run_money_2000000", 2000000L, "Money Printer", "Reach 2,000,000 run currency.") }; private static readonly ThresholdAchievement[] RunHaulAchievements = new ThresholdAchievement[7] { new ThresholdAchievement("run_haul_75000", 75000L, "Packed Tight", "Reach 75,000 haul value in a run."), new ThresholdAchievement("run_haul_100000", 100000L, "Full Truck", "Reach 100,000 haul value in a run."), new ThresholdAchievement("run_haul_150000", 150000L, "Heavy Freight", "Reach 150,000 haul value in a run."), new ThresholdAchievement("run_haul_250000", 250000L, "Haul Beast", "Reach 250,000 haul value in a run."), new ThresholdAchievement("run_haul_500000", 500000L, "Warehouse On Legs", "Reach 500,000 haul value in a run."), new ThresholdAchievement("run_haul_750000", 750000L, "Museum Eviction", "Reach 750,000 haul value in a run."), new ThresholdAchievement("run_haul_1000000", 1000000L, "Everything Must Go", "Reach 1,000,000 haul value in a run.") }; private static readonly ThresholdAchievement[] RunLevelAchievements = new ThresholdAchievement[11] { new ThresholdAchievement("run_level_2", 2L, "Second Stop", "Reach level 2 in a run."), new ThresholdAchievement("run_level_3", 3L, "Third Shift", "Reach level 3 in a run."), new ThresholdAchievement("run_level_4", 4L, "Fourth Wind", "Reach level 4 in a run."), new ThresholdAchievement("run_level_5", 5L, "Warm Depths", "Reach level 5 in a run."), new ThresholdAchievement("run_level_6", 6L, "Below Comfortable", "Reach level 6 in a run."), new ThresholdAchievement("run_level_7", 7L, "Further Down", "Reach level 7 in a run."), new ThresholdAchievement("run_level_8", 8L, "Depth Charge", "Reach level 8 in a run."), new ThresholdAchievement("run_level_10", 10L, "Deep Delver", "Reach level 10 in a run."), new ThresholdAchievement("run_level_12", 12L, "Dark Mileage", "Reach level 12 in a run."), new ThresholdAchievement("run_level_15", 15L, "Abyss Dweller", "Reach level 15 in a run."), new ThresholdAchievement("run_level_20", 20L, "No Sun Left", "Reach level 20 in a run.") }; private static readonly ThresholdAchievement[] NoDeathStreakAchievements = new ThresholdAchievement[9] { new ThresholdAchievement("nodeath_streak_2", 2L, "Back-to-Back", "Extract deathless twice in a row."), new ThresholdAchievement("nodeath_streak_3", 3L, "Clean Hands", "Extract deathless 3 times in a row."), new ThresholdAchievement("nodeath_streak_5", 5L, "On Fire", "Extract deathless 5 times in a row."), new ThresholdAchievement("nodeath_streak_7", 7L, "Never Touched", "Extract deathless 7 times in a row."), new ThresholdAchievement("nodeath_streak_10", 10L, "Untouchable++", "Extract deathless 10 times in a row."), new ThresholdAchievement("nodeath_streak_15", 15L, "Ghost Route", "Extract deathless 15 times in a row."), new ThresholdAchievement("nodeath_streak_25", 25L, "Perfect Habit", "Extract deathless 25 times in a row."), new ThresholdAchievement("nodeath_streak_50", 50L, "Deathless Religion", "Extract deathless 50 times in a row."), new ThresholdAchievement("nodeath_streak_100", 100L, "Myth Of Safety", "Extract deathless 100 times in a row.") }; private static readonly SpreeAchievement[] KillSpreeAchievements = new SpreeAchievement[5] { new SpreeAchievement("kill_spree_3_5s", 3, 5f, "Opening Flurry", "Eliminate 3 enemies within 5 seconds."), new SpreeAchievement("kill_spree_5_10s", 5, 10f, "Quick Hands", "Eliminate 5 enemies within 10 seconds."), new SpreeAchievement("kill_spree_7_10s", 7, 10f, "Chain Reaction", "Eliminate 7 enemies within 10 seconds."), new SpreeAchievement("kill_spree_10_15s", 10, 15f, "No Survivors Nearby", "Eliminate 10 enemies within 15 seconds."), new SpreeAchievement("kill_spree_15_20s", 15, 20f, "Screen Wipe", "Eliminate 15 enemies within 20 seconds.") }; private static readonly EnemyTypeInfo[] EnemyTypes = new EnemyTypeInfo[5] { new EnemyTypeInfo("VeryLight", "Very Light", "Snack Extinction"), new EnemyTypeInfo("Light", "Light", "Light's Out"), new EnemyTypeInfo("Medium", "Medium", "Middle Management Axed"), new EnemyTypeInfo("Heavy", "Heavy", "Heavy Industry"), new EnemyTypeInfo("VeryHeavy", "Very Heavy", "Gravitational Collapse") }; [HarmonyPostfix] [HarmonyPatch(typeof(AchievementBook), "DefineDefaults")] private static void PostDefineDefaults() { if (!Defined) { Defined = true; DefineMany(MetaAchievements); DefineMany(ExtractionAchievements); DefineMany(DiscoveryAchievements); DefineMany(LifetimePurchaseAchievements); DefineMany(LifetimeDeathAchievements); DefineMany(LifetimeReviveAchievements); DefineMany(LifetimeHaulAchievements); DefineMany(RunPurchaseAchievements); DefineMany(RunDeathAchievements); DefineMany(RunKillAchievements); DefineMany(LifetimeKillAchievements); DefineMany(ChargeSessionAchievements); DefineMany(ChargeTotalAchievements); DefineMany(RunMoneyAchievements); DefineMany(RunHaulAchievements); DefineMany(RunLevelAchievements); DefineMany(NoDeathStreakAchievements); Define("no_purchase_run", "Barebones", "Extract without buying anything that run."); DefineSpreeAchievements(); DefineEnemyTypeAchievements(); ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogInfo((object)("[ACH+] Extra definitions loaded: " + AchievementBook.All.Count)); } } } [HarmonyPostfix] [HarmonyPatch(typeof(RoundDirector), "StartRoundRPC")] private static void PostRoundStart() { ResetRunCounter("kills_run"); ResetRunCounter("run_purchases"); KillTimestamps.Clear(); } [HarmonyPostfix] [HarmonyPatch(typeof(ValuableObject), "DiscoverRPC")] private static void PostDiscover() { EmpressAchievementsPlugin.Store.AddToCounter("discoveries", 1L); } [HarmonyPostfix] [HarmonyPatch(typeof(StatsManager), "ItemPurchase")] private static void PostItemPurchase() { EmpressAchievementsPlugin.Store.AddToCounter("run_purchases", 1L); } [HarmonyPostfix] [HarmonyPatch(typeof(ChargingStation), "StartChargeRPC")] private static void PostChargeStart() { EmpressAchievementsPlugin.Store.AddToCounter("charge_sessions", 1L); } [HarmonyPostfix] [HarmonyPatch(typeof(PunManager), "SetRunStatSet")] private static void PostRunStatSet(string statName, int value) { if (string.Equals(statName, "currency", StringComparison.OrdinalIgnoreCase)) { UnlockThresholds(value, RunMoneyAchievements); } else if (string.Equals(statName, "level", StringComparison.OrdinalIgnoreCase)) { UnlockThresholds(value, RunLevelAchievements); } else if (string.Equals(statName, "chargingStationChargeTotal", StringComparison.OrdinalIgnoreCase)) { UnlockThresholds(value, ChargeTotalAchievements); } else if (string.Equals(statName, "totalHaul", StringComparison.OrdinalIgnoreCase)) { UnlockThresholds(value, RunHaulAchievements); } } [HarmonyPostfix] [HarmonyPatch(typeof(RoundDirector), "ExtractionCompleted")] private static void PostExtractionCompleted() { if (EmpressAchievementsPlugin.Store.GetCounter("run_purchases") == 0) { EmpressAchievementsPlugin.Unlock("no_purchase_run"); } if (EmpressAchievementsPlugin.GetStat("run_deaths") == 0) { long value = EmpressAchievementsPlugin.Store.GetCounter("nodeath_streak") + 1; EmpressAchievementsPlugin.Store.SetCounter("nodeath_streak", value); UnlockThresholds(value, NoDeathStreakAchievements); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")] private static void PostPlayerDeath(PlayerAvatar __instance) { PhotonView val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<PhotonView>() : null); if (!((Object)(object)val != (Object)null) || val.IsMine) { EmpressAchievementsPlugin.Store.SetCounter("nodeath_streak", 0L); } } [HarmonyPostfix] [HarmonyPatch(typeof(AchievementStore), "AddToCounter")] private static void PostAddToCounter(AchievementStore __instance, string key, long delta) { switch (key) { case "extractions": UnlockThresholds(__instance.GetCounter(key), ExtractionAchievements); break; case "discoveries": UnlockThresholds(__instance.GetCounter(key), DiscoveryAchievements); break; case "purchases": UnlockThresholds(__instance.GetCounter(key), LifetimePurchaseAchievements); break; case "deaths": UnlockThresholds(__instance.GetCounter(key), LifetimeDeathAchievements); break; case "revives": UnlockThresholds(__instance.GetCounter(key), LifetimeReviveAchievements); break; case "life_haul": UnlockThresholds(__instance.GetCounter(key), LifetimeHaulAchievements); break; case "run_purchases": UnlockThresholds(__instance.GetCounter(key), RunPurchaseAchievements); break; case "run_deaths": UnlockThresholds(__instance.GetCounter(key), RunDeathAchievements); break; case "kills_run": UnlockThresholds(__instance.GetCounter(key), RunKillAchievements); break; case "kills_total": if (delta > 0) { __instance.AddToCounter("kills_run", delta); RegisterKillTime(Time.unscaledTime); } UnlockThresholds(__instance.GetCounter(key), LifetimeKillAchievements); break; case "charge_sessions": UnlockThresholds(__instance.GetCounter(key), ChargeSessionAchievements); break; default: if (key.StartsWith("kills_type_", StringComparison.OrdinalIgnoreCase)) { UnlockEnemyTypeThresholds(key.Substring("kills_type_".Length), __instance.GetCounter(key)); } break; } } [HarmonyPostfix] [HarmonyPatch(typeof(AchievementStore), "Unlock")] private static void PostUnlock(AchievementStore __instance, string id) { AchievementStore __instance2 = __instance; try { int num = AchievementBook.All.Keys.Count((string k) => __instance2.IsUnlocked(k)); UnlockThresholds(num, MetaAchievements); } catch (Exception ex) { ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogWarning((object)("[ACH+] Meta unlock check failed: " + ex)); } } } private static void ResetRunCounter(string key) { long counter = EmpressAchievementsPlugin.Store.GetCounter(key); if (counter != 0) { EmpressAchievementsPlugin.Store.AddToCounter(key, -counter); } } private static void RegisterKillTime(float now) { KillTimestamps.Enqueue(now); float num = 0f; SpreeAchievement[] killSpreeAchievements = KillSpreeAchievements; for (int i = 0; i < killSpreeAchievements.Length; i++) { SpreeAchievement spreeAchievement = killSpreeAchievements[i]; if (spreeAchievement.WindowSeconds > num) { num = spreeAchievement.WindowSeconds; } } while (KillTimestamps.Count > 0 && now - KillTimestamps.Peek() > num) { KillTimestamps.Dequeue(); } float[] array = KillTimestamps.ToArray(); SpreeAchievement[] killSpreeAchievements2 = KillSpreeAchievements; for (int j = 0; j < killSpreeAchievements2.Length; j++) { SpreeAchievement spreeAchievement2 = killSpreeAchievements2[j]; int num2 = 0; int num3 = array.Length - 1; while (num3 >= 0 && !(now - array[num3] > spreeAchievement2.WindowSeconds)) { num2++; num3--; } if (num2 >= spreeAchievement2.Count) { EmpressAchievementsPlugin.Unlock(spreeAchievement2.Id); } } } private static void DefineMany(IEnumerable<ThresholdAchievement> achievements) { foreach (ThresholdAchievement achievement in achievements) { Define(achievement.Id, achievement.Title, achievement.Description); } } private static void DefineSpreeAchievements() { SpreeAchievement[] killSpreeAchievements = KillSpreeAchievements; for (int i = 0; i < killSpreeAchievements.Length; i++) { SpreeAchievement spreeAchievement = killSpreeAchievements[i]; Define(spreeAchievement.Id, spreeAchievement.Title, spreeAchievement.Description); } } private static void DefineEnemyTypeAchievements() { EnemyTypeInfo[] enemyTypes = EnemyTypes; for (int i = 0; i < enemyTypes.Length; i++) { EnemyTypeInfo enemyTypeInfo = enemyTypes[i]; Define("kill_type_" + enemyTypeInfo.Id + "_10", enemyTypeInfo.Label + " Hunter I", "Eliminate 10 " + enemyTypeInfo.Label + " enemies."); Define("kill_type_" + enemyTypeInfo.Id + "_50", enemyTypeInfo.Label + " Hunter II", "Eliminate 50 " + enemyTypeInfo.Label + " enemies."); Define("kill_type_" + enemyTypeInfo.Id + "_100", enemyTypeInfo.HundredTitle, "Eliminate 100 " + enemyTypeInfo.Label + " enemies."); Define("kill_type_" + enemyTypeInfo.Id + "_250", enemyTypeInfo.Label + " Hunter III", "Eliminate 250 " + enemyTypeInfo.Label + " enemies."); Define("kill_type_" + enemyTypeInfo.Id + "_500", enemyTypeInfo.Label + " Hunter IV", "Eliminate 500 " + enemyTypeInfo.Label + " enemies."); } } private static void UnlockEnemyTypeThresholds(string typeId, long value) { if (value >= 10) { EmpressAchievementsPlugin.Unlock("kill_type_" + typeId + "_10"); } if (value >= 50) { EmpressAchievementsPlugin.Unlock("kill_type_" + typeId + "_50"); } if (value >= 100) { EmpressAchievementsPlugin.Unlock("kill_type_" + typeId + "_100"); } if (value >= 250) { EmpressAchievementsPlugin.Unlock("kill_type_" + typeId + "_250"); } if (value >= 500) { EmpressAchievementsPlugin.Unlock("kill_type_" + typeId + "_500"); } } private static void UnlockThresholds(long value, IEnumerable<ThresholdAchievement> achievements) { foreach (ThresholdAchievement achievement in achievements) { if (value >= achievement.Threshold) { EmpressAchievementsPlugin.Unlock(achievement.Id); } } } private static void Define(string id, string title, string description) { AchievementBook.All[id] = new AchievementDef(id, title, description); } } [BepInPlugin("empress.repo.achievements", "Empress Achievements", "1.3.8")] public class EmpressAchievementsPlugin : BaseUnityPlugin { public const string PluginGuid = "empress.repo.achievements"; public const string PluginName = "Empress Achievements"; public const string PluginVersion = "1.3.8"; private Harmony _harmony; internal static ConfigEntry<KeyCode> ToggleUiKey; internal static ConfigEntry<bool> EnableSound; internal static ConfigEntry<string> SoundFileName; internal static ConfigEntry<float> SoundVolume; internal static ConfigEntry<float> floatToastSeconds; internal static ConfigEntry<int> UiScalePercent; internal static ConfigEntry<bool> DebugLogJsonPreview; internal static ManualLogSource Log; internal static EmpressAchievementsPlugin Instance; internal static EmpressAchievementsRuntime Runtime; internal static ToastUi Toast; internal static AchievementsUi AchievementsPanel; internal static AchievementStore Store; internal static bool TalliedExtractionThisRound = false; internal static float LastLocalDeathTime = -999f; internal static float LastPurchaseTime = -999f; internal static HashSet<int> ProcessedKillHashes = new HashSet<int>(); private static int LastUiUpdateFrame = -1; private void Awake() { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ToggleUiKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("UI", "ToggleKey", (KeyCode)289, "Key to open/close achievements panel"); UiScalePercent = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "UiScalePercent", 100, "UI scale percentage (100=default)"); floatToastSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "ToastSeconds", 4f, "Seconds a toast stays visible"); DebugLogJsonPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogJsonPreview", false, "Log first ~300 chars of JSON after save."); EnableSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "EnableSound", true, "Play a sound when an achievement pops"); SoundFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Sound", "SoundFileName", "empress_achievement.ogg", "Audio file placed next to the DLL (wav/ogg/mp3)"); SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "Volume", 70f, new ConfigDescription("Toast sound volume percent (0-100). Older 0-1 values are auto-converted.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); SoundVolume.SettingChanged += delegate { ClampSoundVolumeConfig(); }; ClampSoundVolumeConfig(); string pluginFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath; Store = new AchievementStore(pluginFolder, "empress_achievements.json"); Log.LogInfo((object)("[ACH] Canonical save => " + Store.CanonicalFile)); Store.Load(); DumpFileMap("Boot"); _harmony = new Harmony("empress.repo.achievements"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); EnsureRuntimeHost(); BootstrapUi(); AchievementBook.DefineDefaults(); Log.LogInfo((object)("Empress Achievements v1.3.8 loaded. Achievements: " + AchievementBook.All.Count)); } private static void EnsureRuntimeHost() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if ((Object)(object)Runtime != (Object)null) { Runtime.EmpressBoot(); return; } Runtime = Object.FindObjectOfType<EmpressAchievementsRuntime>(); if ((Object)(object)Runtime != (Object)null) { Runtime.EmpressBoot(); return; } GameObject val = new GameObject("Empress_AchievementsRuntime"); val.transform.SetParent((Transform)null); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); Runtime = val.AddComponent<EmpressAchievementsRuntime>(); Runtime.EmpressBoot(); } private static bool InitializeUIComponents() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) try { EnsureRuntimeHost(); GameObject val = (GameObject)(((Object)(object)Runtime != (Object)null) ? ((object)((Component)Runtime).gameObject) : ((object)new GameObject("Empress_AchievementUI_Root"))); if ((Object)(object)Runtime == (Object)null) { Object.DontDestroyOnLoad((Object)(object)val); } Toast = val.GetComponent<ToastUi>(); if ((Object)(object)Toast == (Object)null) { Toast = val.AddComponent<ToastUi>(); } Toast.Duration = floatToastSeconds.Value; Toast.Volume = GetSoundVolume01(); Toast.EnableSound = EnableSound.Value; string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath; Toast.SoundFilePath = (Path.IsPathRooted(SoundFileName.Value) ? SoundFileName.Value : Path.Combine(path, SoundFileName.Value)); Toast.UiScale = (float)UiScalePercent.Value / 100f; AchievementsPanel = val.GetComponent<AchievementsUi>(); if ((Object)(object)AchievementsPanel == (Object)null) { AchievementsPanel = val.AddComponent<AchievementsUi>(); } AchievementsPanel.UiScale = Toast.UiScale; return true; } catch (Exception ex) { Log.LogError((object)("[ACH] UI init failed: " + ex)); return false; } } private static bool EnsureUiReady() { EnsureRuntimeHost(); bool flag = (Object)(object)Toast != (Object)null && Object.op_Implicit((Object)(object)Toast); bool flag2 = (Object)(object)AchievementsPanel != (Object)null && Object.op_Implicit((Object)(object)AchievementsPanel); if (!flag || !flag2) { Toast = null; AchievementsPanel = null; if (!InitializeUIComponents()) { return false; } } Toast.Duration = floatToastSeconds.Value; Toast.Volume = GetSoundVolume01(); Toast.EnableSound = EnableSound.Value; Toast.UiScale = (float)UiScalePercent.Value / 100f; string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath; Toast.SoundFilePath = (Path.IsPathRooted(SoundFileName.Value) ? SoundFileName.Value : Path.Combine(path, SoundFileName.Value)); AchievementsPanel.UiScale = Toast.UiScale; RequestToastSoundLoad(); return true; } private static void RequestToastSoundLoad() { if (!((Object)(object)Toast == (Object)null) && Toast.NeedsSoundLoad()) { if ((Object)(object)Instance != (Object)null && Object.op_Implicit((Object)(object)Instance)) { ((MonoBehaviour)Instance).StartCoroutine(Toast.LoadSoundCoroutine()); } else if ((Object)(object)Runtime != (Object)null && Object.op_Implicit((Object)(object)Runtime)) { Runtime.StartManagedCoroutine(Toast.LoadSoundCoroutine()); } } } private void OnDestroy() { if (Instance == this) { Instance = null; } try { Store?.Save(); } catch { } } private void OnApplicationQuit() { try { Store?.Save(); } catch { } } private void Update() { RuntimeUpdate(); } internal static void RuntimeUpdate() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) int frameCount = Time.frameCount; if (LastUiUpdateFrame == frameCount) { return; } LastUiUpdateFrame = frameCount; if (EnsureUiReady()) { RequestToastSoundLoad(); if (Input.GetKeyDown(ToggleUiKey.Value) || Input.GetKeyDown((KeyCode)289)) { AchievementsPanel.Toggle(); } float num = (float)UiScalePercent.Value / 100f; if (Mathf.Abs(num - Toast.UiScale) > 0.001f) { Toast.UiScale = num; AchievementsPanel.UiScale = num; Toast.RefreshScale(); AchievementsPanel.RefreshScale(); } } } private static void BootstrapUi() { if (EnsureUiReady()) { AchievementsPanel.Prime(); RequestToastSoundLoad(); } } private static float GetSoundVolume01() { ClampSoundVolumeConfig(); return Mathf.Clamp(SoundVolume.Value, 0f, 100f) / 100f; } private static void ClampSoundVolumeConfig() { if (SoundVolume != null) { float num = SoundVolume.Value; if (num > 0f && num <= 1.01f) { num *= 100f; } float num2 = Mathf.Clamp(num, 0f, 100f); if (Math.Abs(SoundVolume.Value - num2) > 0.001f) { SoundVolume.Value = num2; } } } internal static void DumpFileMap(string tag) { try { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Paths.PluginPath; string[] source = new string[3] { Path.Combine(Paths.ConfigPath, "EmpressAchievements", "empress_achievements.json"), Path.Combine(path, "empress_achievements.json"), Path.Combine(Paths.ConfigPath, "empress.repo.achievements.json") }; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[ACH][FileMap/" + tag + "] Scanning known locations:")); } foreach (string item in source.Distinct()) { if (File.Exists(item)) { FileInfo fileInfo = new FileInfo(item); ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)$"[ACH][FileMap/{tag}] {item} | size={fileInfo.Length} | modified={fileInfo.LastWriteTimeUtc:O}"); } } else { ManualLogSource log3 = Log; if (log3 != null) { log3.LogInfo((object)("[ACH][FileMap/" + tag + "] (missing) " + item)); } } } } catch (Exception ex) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogWarning((object)("[ACH][FileMap] " + ex)); } } } public static void Pop(string title, string body) { if (EnsureUiReady()) { Toast.Pop(title, body); } } public static void Unlock(string id) { AchievementDef achievementDef = AchievementBook.Get(id); if (achievementDef != null && !Store.IsUnlocked(id)) { Store.Unlock(id); Pop(achievementDef.Title, achievementDef.Description); if ((Object)(object)AchievementsPanel != (Object)null && Object.op_Implicit((Object)(object)AchievementsPanel)) { AchievementsPanel.RefreshAllIfOpen(); } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("[ACH] Unlocked: " + achievementDef.Id + " - " + achievementDef.Title)); } Store.Save(); } } public static void BumpStat(string key, int delta = 1) { Store.AddToCounter(key, delta); if ((Object)(object)AchievementsPanel != (Object)null && Object.op_Implicit((Object)(object)AchievementsPanel)) { AchievementsPanel.RefreshStatsIfOpen(); } } public static int GetStat(string key) { return (int)Store.GetCounter(key); } internal static string FormatK(long value) { long num = Math.Abs(value); if (num >= 1000) { float num2 = (float)value / 1000f; string text = ((Mathf.Abs(num2 - Mathf.Round(num2)) < 0.05f) ? num2.ToString("0") : num2.ToString("0.#")); return text + "K"; } return value.ToString("N0"); } } internal sealed class EmpressAchievementsRuntime : MonoBehaviour { private bool _booted; internal void EmpressBoot() { if (!_booted) { _booted = true; EmpressAchievementsPlugin.RuntimeUpdate(); } } internal Coroutine StartManagedCoroutine(IEnumerator routine) { return ((MonoBehaviour)this).StartCoroutine(routine); } private void Update() { EmpressAchievementsPlugin.RuntimeUpdate(); } } [Serializable] public class AchievementState { public string Id; public bool Unlocked; public int UnlockedAtUnix; } [Serializable] public class CounterKV { public string Key; public int Value; } [Serializable] public class AchievementsSave { public List<AchievementState> Achievements = new List<AchievementState>(); public List<CounterKV> Counters = new List<CounterKV>(); public int SchemaVersion = 2; } internal static class SaveJson { private static string Esc(string s) { if (s == null) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length + 8); foreach (char c in s) { switch (c) { case '"': stringBuilder.Append("\\\""); continue; case '\\': stringBuilder.Append("\\\\"); continue; case '\b': stringBuilder.Append("\\b"); continue; case '\f': stringBuilder.Append("\\f"); continue; case '\n': stringBuilder.Append("\\n"); continue; case '\r': stringBuilder.Append("\\r"); continue; case '\t': stringBuilder.Append("\\t"); continue; } if (c < ' ') { StringBuilder stringBuilder2 = stringBuilder.Append("\\u"); int num = c; stringBuilder2.Append(num.ToString("x4")); } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } public static string Serialize(AchievementsSave data) { StringBuilder stringBuilder = new StringBuilder(Mathf.Max(1024, (data.Achievements.Count + data.Counters.Count) * 64)); stringBuilder.Append("{\n \"Achievements\": ["); for (int i = 0; i < data.Achievements.Count; i++) { AchievementState achievementState = data.Achievements[i]; if (i > 0) { stringBuilder.Append(','); } stringBuilder.Append("\n {").Append("\"Id\":\"").Append(Esc(achievementState.Id ?? "")) .Append("\",") .Append("\"Unlocked\":") .Append(achievementState.Unlocked ? "true" : "false") .Append(',') .Append("\"UnlockedAtUnix\":") .Append(achievementState.UnlockedAtUnix) .Append('}'); } stringBuilder.Append("\n ],\n \"Counters\": ["); for (int j = 0; j < data.Counters.Count; j++) { CounterKV counterKV = data.Counters[j]; if (j > 0) { stringBuilder.Append(','); } stringBuilder.Append("\n {").Append("\"Key\":\"").Append(Esc(counterKV.Key ?? "")) .Append("\",") .Append("\"Value\":") .Append(counterKV.Value) .Append('}'); } stringBuilder.Append("\n ],\n \"SchemaVersion\": ").Append(data.SchemaVersion).Append("\n}"); return stringBuilder.ToString(); } } internal static class LoadJsonFallback { private static bool ArrayLooksPopulated(string json, string key) { Regex regex = new Regex("\"" + Regex.Escape(key) + "\"\\s*:\\s*\\[\\s*\\{", RegexOptions.Singleline); return regex.IsMatch(json); } private static string ExtractArray(string json, string key) { int num = json.IndexOf("\"" + key + "\"", StringComparison.Ordinal); if (num < 0) { return null; } int num2 = json.IndexOf('[', num); if (num2 < 0) { return null; } int num3 = 0; for (int i = num2; i < json.Length; i++) { switch (json[i]) { case '[': num3++; break; case ']': num3--; if (num3 == 0) { return json.Substring(num2, i - num2 + 1); } break; } } return null; } public static bool JsonIndicatesItems(string json, out bool hasA, out bool hasC) { hasA = ArrayLooksPopulated(json, "Achievements"); hasC = ArrayLooksPopulated(json, "Counters"); return hasA | hasC; } public static bool TryParse(string json, out AchievementsSave save) { save = new AchievementsSave(); try { string text = ExtractArray(json, "Achievements"); string text2 = ExtractArray(json, "Counters"); if (!string.IsNullOrEmpty(text)) { Regex regex = new Regex("\\{\\s*\"Id\"\\s*:\\s*\"(?<id>.*?)\"\\s*,\\s*\"Unlocked\"\\s*:\\s*(?<u>true|false)\\s*,\\s*\"UnlockedAtUnix\"\\s*:\\s*(?<t>-?\\d+)\\s*\\}", RegexOptions.Singleline); foreach (Match item in regex.Matches(text)) { int result; AchievementState achievementState = new AchievementState { Id = item.Groups["id"].Value, Unlocked = (item.Groups["u"].Value == "true"), UnlockedAtUnix = (int.TryParse(item.Groups["t"].Value, out result) ? result : 0) }; if (!string.IsNullOrEmpty(achievementState.Id)) { save.Achievements.Add(achievementState); } } } if (!string.IsNullOrEmpty(text2)) { Regex regex2 = new Regex("\\{\\s*\"Key\"\\s*:\\s*\"(?<k>.*?)\"\\s*,\\s*\"Value\"\\s*:\\s*(?<v>-?\\d+)\\s*\\}", RegexOptions.Singleline); foreach (Match item2 in regex2.Matches(text2)) { int result2; CounterKV counterKV = new CounterKV { Key = item2.Groups["k"].Value, Value = (int.TryParse(item2.Groups["v"].Value, out result2) ? result2 : 0) }; if (!string.IsNullOrEmpty(counterKV.Key)) { save.Counters.Add(counterKV); } } } Regex regex3 = new Regex("\"SchemaVersion\"\\s*:\\s*(?<s>\\d+)"); Match match3 = regex3.Match(json); if (match3.Success && int.TryParse(match3.Groups["s"].Value, out var result3)) { save.SchemaVersion = result3; } return true; } catch { save = new AchievementsSave(); return false; } } } public class AchievementStore { private readonly string _pluginFolder; private readonly string _pluginFile; private AchievementsSave _data = new AchievementsSave(); private readonly Dictionary<string, long> _counters = new Dictionary<string, long>(); public string CanonicalFolder => Path.Combine(Paths.ConfigPath, "EmpressAchievements"); public string CanonicalFile => Path.Combine(CanonicalFolder, "empress_achievements.json"); private string PluginOldFile => _pluginFile; private string LegacyConfigFile => Path.Combine(Paths.ConfigPath, "empress.repo.achievements.json"); public AchievementStore(string pluginFolder, string filename) { _pluginFolder = pluginFolder; _pluginFile = Path.Combine(pluginFolder, filename); } public bool IsUnlocked(string id) { string id2 = id; return _data.Achievements.Any((AchievementState a) => a.Id == id2 && a.Unlocked); } public long GetCounter(string key) { long value; return _counters.TryGetValue(key, out value) ? value : 0; } public void AddToCounter(string key, long delta) { if (!_counters.ContainsKey(key)) { _counters[key] = 0L; } _counters[key] += delta; Save(); } public void SetCounter(string key, long value) { _counters[key] = value; Save(); } public void Unlock(string id) { string id2 = id; AchievementState achievementState = _data.Achievements.FirstOrDefault((AchievementState a) => a.Id == id2); if (achievementState == null) { achievementState = new AchievementState { Id = id2 }; _data.Achievements.Add(achievementState); } achievementState.Unlocked = true; long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); achievementState.UnlockedAtUnix = (int)((num > int.MaxValue) ? int.MaxValue : num); Save(); } public void Load() { try { EnsureCanonicalDir(); List<string> list = new List<string>(); if (File.Exists(CanonicalFile)) { list.Add(CanonicalFile); } if (File.Exists(PluginOldFile)) { list.Add(PluginOldFile); } if (File.Exists(LegacyConfigFile)) { list.Add(LegacyConfigFile); } string text = ((list.Count > 0) ? list.OrderByDescending(SafeGetWriteTimeUtc).First() : null); if (text == null) { PersistCanonical(SaveJson.Serialize(_data), verify: true, "Fresh"); ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogInfo((object)"[ACH] Created fresh save."); } return; } string text2 = File.ReadAllText(text, Encoding.UTF8); AchievementsSave achievementsSave = null; bool flag = false; try { if (!string.IsNullOrWhiteSpace(text2)) { achievementsSave = JsonUtility.FromJson<AchievementsSave>(text2); } } catch { achievementsSave = null; } LoadJsonFallback.JsonIndicatesItems(text2, out var hasA, out var hasC); if ((achievementsSave == null || achievementsSave.Achievements == null || achievementsSave.Counters == null || (achievementsSave.Achievements != null && achievementsSave.Achievements.Count == 0 && hasA) || (achievementsSave.Counters != null && achievementsSave.Counters.Count == 0 && hasC)) && LoadJsonFallback.TryParse(text2, out AchievementsSave save)) { achievementsSave = save; flag = true; } if (achievementsSave != null) { _data = achievementsSave; AchievementsSave data = _data; if (data.Achievements == null) { data.Achievements = new List<AchievementState>(); } data = _data; if (data.Counters == null) { data.Counters = new List<CounterKV>(); } _counters.Clear(); foreach (CounterKV counter in _data.Counters) { if (counter != null && !string.IsNullOrEmpty(counter.Key)) { _counters[counter.Key] = counter.Value; } } bool flag2 = text != CanonicalFile; if (flag2 || flag) { PersistCanonical(SaveJson.Serialize(_data), verify: true, flag2 ? "Migrate" : "Normalize"); } if (text != CanonicalFile) { TryDelete(text); } ManualLogSource log2 = EmpressAchievementsPlugin.Log; if (log2 != null) { log2.LogInfo((object)("[ACH] Loaded save from: " + text)); } } else { _data = new AchievementsSave(); _counters.Clear(); ManualLogSource log3 = EmpressAchievementsPlugin.Log; if (log3 != null) { log3.LogWarning((object)("[ACH] Load parse failed for " + text + ". Keeping file on disk unchanged; in-memory starts fresh.")); } } } catch (Exception ex) { ManualLogSource log4 = EmpressAchievementsPlugin.Log; if (log4 != null) { log4.LogWarning((object)("[ACH] Load exception: " + ex)); } _data = new AchievementsSave(); _counters.Clear(); } } public void Save() { try { AchievementsSave data = _data; if (data.Achievements == null) { data.Achievements = new List<AchievementState>(); } _data.Counters = _counters.Select<KeyValuePair<string, long>, CounterKV>((KeyValuePair<string, long> kv) => new CounterKV { Key = kv.Key, Value = (int)((kv.Value > int.MaxValue) ? int.MaxValue : ((kv.Value < int.MinValue) ? int.MinValue : kv.Value)) }).ToList(); if (_data.Achievements.Count == 0 && _data.Counters.Count == 0 && OnDiskLooksPopulated()) { ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogWarning((object)"[ACH] Save skipped to avoid clobber: memory is empty but disk has items."); } return; } string text = SaveJson.Serialize(_data); PersistCanonical(text, verify: true, "Save"); long num = _data.Achievements.Count; long num2 = _data.Counters.Count; long num3 = SafeGetLength(CanonicalFile); if ((Object)(object)EmpressAchievementsPlugin.Instance != (Object)null && EmpressAchievementsPlugin.DebugLogJsonPreview.Value) { string text2 = ((text.Length > 300) ? (text.Substring(0, 300) + "...") : text); ManualLogSource log2 = EmpressAchievementsPlugin.Log; if (log2 != null) { log2.LogInfo((object)("[ACH] JSON preview: " + text2.Replace("\n", "\\n"))); } } ManualLogSource log3 = EmpressAchievementsPlugin.Log; if (log3 != null) { log3.LogInfo((object)$"[ACH] Saved {num} achievements, {num2} counters -> {CanonicalFile} ({num3} bytes) [verify OK]"); } EmpressAchievementsPlugin.DumpFileMap("AfterSave"); } catch (Exception ex) { ManualLogSource log4 = EmpressAchievementsPlugin.Log; if (log4 != null) { log4.LogWarning((object)("[ACH] Save failed: " + ex)); } } } private bool OnDiskLooksPopulated() { try { if (!File.Exists(CanonicalFile)) { return false; } string json = File.ReadAllText(CanonicalFile, Encoding.UTF8); bool hasA; bool hasC; return LoadJsonFallback.JsonIndicatesItems(json, out hasA, out hasC) && (hasA || hasC); } catch { return false; } } private void EnsureCanonicalDir() { try { Directory.CreateDirectory(CanonicalFolder); } catch { } } private void PersistCanonical(string json, bool verify, string context) { EnsureCanonicalDir(); string text = CanonicalFile + ".tmp"; try { using FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.WriteThrough); using StreamWriter streamWriter = new StreamWriter(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); streamWriter.Write(json); streamWriter.Flush(); fileStream.Flush(flushToDisk: true); } catch (Exception arg) { ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogWarning((object)$"[ACH] {context} tmp write failed: {arg}"); } throw; } try { if (File.Exists(CanonicalFile)) { try { File.Replace(text, CanonicalFile, CanonicalFile + ".bak"); } catch { try { File.Delete(CanonicalFile); } catch { } File.Move(text, CanonicalFile); } } else { File.Move(text, CanonicalFile); } } catch (Exception arg2) { ManualLogSource log2 = EmpressAchievementsPlugin.Log; if (log2 != null) { log2.LogWarning((object)$"[ACH] {context} replace failed: {arg2}"); } throw; } if (!verify) { return; } try { string text2 = File.ReadAllText(CanonicalFile, Encoding.UTF8); if (!string.Equals(text2, json, StringComparison.Ordinal)) { string text3 = ((text2.Length > 300) ? (text2.Substring(0, 300) + "...") : text2); ManualLogSource log3 = EmpressAchievementsPlugin.Log; if (log3 != null) { log3.LogWarning((object)$"[ACH] VERIFY STRING MISMATCH after {context}: lenWritten={json.Length}, lenRead={text2.Length}"); } ManualLogSource log4 = EmpressAchievementsPlugin.Log; if (log4 != null) { log4.LogWarning((object)("[ACH] On-disk head: " + text3.Replace("\n", "\\n"))); } } } catch (Exception arg3) { ManualLogSource log5 = EmpressAchievementsPlugin.Log; if (log5 != null) { log5.LogWarning((object)$"[ACH] Verify read failed after {context}: {arg3}"); } } } private static DateTime SafeGetWriteTimeUtc(string path) { try { return File.GetLastWriteTimeUtc(path); } catch { return DateTime.MinValue; } } private static long SafeGetLength(string path) { try { return new FileInfo(path).Length; } catch { return 0L; } } private static void TryDelete(string path) { try { if (File.Exists(path)) { File.Delete(path); } } catch { } } } public class AchievementDef { public string Id; public string Title; public string Description; public AchievementDef(string id, string title, string description) { Id = id; Title = title; Description = description; } } public static class AchievementBook { public static readonly Dictionary<string, AchievementDef> All = new Dictionary<string, AchievementDef>(); public static AchievementDef Get(string id) { AchievementDef value; return All.TryGetValue(id, out value) ? value : null; } public static IEnumerable<AchievementDef> AllOrdered() { return All.Values.OrderBy((AchievementDef d) => d.Title); } public static void DefineDefaults() { All.Clear(); Add("first_extract", "First Extraction", "Complete any extraction."); Add("extract_5", "Commuter", "Complete 5 extractions (lifetime)."); Add("extract_20", "Frequent Flyer", "Complete 20 extractions (lifetime)."); Add("extract_50", "Shuttle Regular", "Complete 50 extractions (lifetime)."); Add("extract_100", "Season Pass Holder", "Complete 100 extractions (lifetime)."); Add("extract_200", "Lives Here Now", "Complete 200 extractions (lifetime)."); Add("run_money_10000", "Cash Flash", "Reach 10,000 run currency."); Add("run_money_25000", "Bankroller", "Reach 25,000 run currency."); Add("run_money_50000", "Whale", "Reach 50,000 run currency."); Add("run_money_100000", "Making It Rain", "Reach 100,000 run currency."); Add("run_haul_10000", "Hauler", "Reach 10,000 haul value in a run."); Add("run_haul_25000", "Mover", "Reach 25,000 haul value in a run."); Add("run_haul_50000", "Freight Lord", "Reach 50,000 haul value in a run."); Add("life_haul_50k", "Thrifty Tycoon", "Accumulate 50,000 haul (lifetime)."); Add("life_haul_100k", "Millionaire-ish", "Accumulate 100,000 haul (lifetime)."); Add("life_haul_250k", "Quarter Mil", "Accumulate 250,000 haul (lifetime)."); Add("life_haul_500k", "Half Ticket", "Accumulate 500,000 haul (lifetime)."); Add("life_haul_1m", "Seven Figures", "Accumulate 1,000,000 haul (lifetime)."); Add("life_haul_2m", "Eight-ish", "Accumulate 2,000,000 haul (lifetime)."); Add("life_haul_5m", "Big Bags", "Accumulate 5,000,000 haul (lifetime)."); Add("life_haul_10m", "Dragon Hoard", "Accumulate 10,000,000 haul (lifetime)."); Add("life_haul_20m", "Vault Dweller", "Accumulate 20,000,000 haul (lifetime)."); Add("life_haul_50m", "Scrooge McDuck", "Accumulate 50,000,000 haul (lifetime)."); Add("first_purchase", "Window Shopper No More", "Purchase your first item."); Add("big_spender_10", "Bulk Buyer", "Purchase 10 items (lifetime)."); Add("big_spender_25", "Cart Commander", "Purchase 25 items (lifetime)."); Add("big_spender_50", "Mall Rat", "Purchase 50 items (lifetime)."); Add("big_spender_100", "Retail Therapy", "Purchase 100 items (lifetime)."); Add("first_death", "Oops", "Die for the first time."); Add("death_5", "Oops, I Did It Again", "Die 5 times."); Add("death_10", "Try, Try Again", "Die 10 times."); Add("death_20", "Professional Victim", "Die 20 times."); Add("death_30", "Speedrun to the Afterlife", "Die 30 times."); Add("death_40", "Grave Connoisseur", "Die 40 times."); Add("death_50", "Certified Floor Tester", "Die 50 times."); Add("death_100", "Immortal (In Theory)", "Die 100 times."); Add("death_200", "Groundhog Day", "Die 200 times."); Add("death_500", "The Floor Is My Home", "Die 500 times."); Add("revived", "Back On Your Feet", "Get revived."); Add("revived_10", "Serial Resurrectee", "Be revived 10 times."); Add("revived_50", "Phoenix Program", "Be revived 50 times."); Add("nodeath_run", "Untouchable", "Complete an extraction without dying."); Add("first_discover", "Treasure Hunter", "Discover your first valuable."); Add("kills_10", "First Bloodbath", "Eliminate 10 enemies."); Add("kills_50", "Pest Control", "Eliminate 50 enemies."); Add("kills_100", "Exterminator", "Eliminate 100 enemies."); Add("kills_250", "Reaper Intern", "Eliminate 250 enemies."); Add("kills_500", "Reaper Associate", "Eliminate 500 enemies."); Add("kills_1000", "Full-Time Reaper", "Eliminate 1,000 enemies."); Add("kills_2000", "Warfare Dept.", "Eliminate 2,000 enemies."); Add("kills_5000", "Population Control", "Eliminate 5,000 enemies."); Add("kill_type_VeryLight", "Light Snack", "Eliminate a Very Light enemy."); Add("kill_type_Light", "Featherweight Fighter", "Eliminate a Light enemy."); Add("kill_type_Medium", "Middle Management", "Eliminate a Medium enemy."); Add("kill_type_Heavy", "Heavy Metal", "Eliminate a Heavy enemy."); Add("kill_type_VeryHeavy", "Heaviest Hand", "Eliminate a Very Heavy enemy."); Add("kill_type_VeryLight_25", "Snack Attack", "Eliminate 25 Very Light enemies."); Add("kill_type_Light_25", "Light Work", "Eliminate 25 Light enemies."); Add("kill_type_Medium_25", "Middle Manager", "Eliminate 25 Medium enemies."); Add("kill_type_Heavy_25", "Heavy Lifter", "Eliminate 25 Heavy enemies."); Add("kill_type_VeryHeavy_25", "Atlas", "Eliminate 25 Very Heavy enemies."); } private static void Add(string id, string title, string desc) { All[id] = new AchievementDef(id, title, desc); } } internal class ToastMessage { public string Title; public string Body; public ToastMessage(string t, string b) { Title = t; Body = b; } } public class ToastUi : MonoBehaviour { public float Duration = 3f; public float UiScale = 1f; public bool EnableSound = true; public string SoundFilePath; public float Volume = 0.7f; private Canvas _canvas; private RectTransform _root; private AudioSource _audio; private AudioClip _clip; private readonly Queue<ToastMessage> _queue = new Queue<ToastMessage>(); private bool _busy; private bool _soundLoadRequested; private string _lastSoundFilePath; public void RefreshScale() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_root)) { ((Transform)_root).localScale = Vector3.one * UiScale; } } private void Ensure() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_canvas)) { EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Creating Toast Canvas..."); _canvas = new GameObject("Empress_AchievementToastCanvas").AddComponent<Canvas>(); Object.DontDestroyOnLoad((Object)(object)_canvas); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 32760; CanvasScaler val = ((Component)_canvas).gameObject.AddComponent<CanvasScaler>(); val.uiScaleMode = (ScaleMode)1; val.referenceResolution = new Vector2(1920f, 1080f); val.screenMatchMode = (ScreenMatchMode)0; val.matchWidthOrHeight = 0.5f; ((Component)_canvas).gameObject.AddComponent<GraphicRaycaster>(); _root = new GameObject("ToastRoot").AddComponent<RectTransform>(); ((Transform)_root).SetParent(((Component)_canvas).transform, false); _root.anchorMin = new Vector2(0.5f, 0f); _root.anchorMax = new Vector2(0.5f, 0f); _root.pivot = new Vector2(0.5f, 0f); _root.anchoredPosition = new Vector2(0f, 80f); ((Transform)_root).localScale = Vector3.one * UiScale; _audio = ((Component)_canvas).gameObject.AddComponent<AudioSource>(); _audio.playOnAwake = false; _audio.spatialBlend = 0f; _audio.loop = false; _audio.ignoreListenerPause = true; _audio.volume = 1f; EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Toast Canvas ready"); } } public IEnumerator LoadSoundCoroutine() { Ensure(); _clip = null; _soundLoadRequested = true; _lastSoundFilePath = SoundFilePath; if (!EnableSound) { yield break; } if (string.IsNullOrEmpty(SoundFilePath) || !File.Exists(SoundFilePath)) { EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] No sound file at: " + (SoundFilePath ?? "null"))); _soundLoadRequested = false; yield break; } EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] Loading sound from: " + SoundFilePath)); string uri = "file://" + SoundFilePath.Replace("\\", "/"); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(uri, GetAudioType(SoundFilePath)); yield return req.SendWebRequest(); if (!req.isNetworkError && !req.isHttpError) { _clip = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)_clip != (Object)null && !_clip.preloadAudioData) { _clip.LoadAudioData(); } ManualLogSource log = EmpressAchievementsPlugin.Log; if (log != null) { log.LogInfo((object)"[ACH] Sound ready"); } } else { ManualLogSource log2 = EmpressAchievementsPlugin.Log; if (log2 != null) { log2.LogWarning((object)("[ACH] Audio load failed: " + req.error)); } _soundLoadRequested = false; } req.Dispose(); } public bool NeedsSoundLoad() { if (!EnableSound) { return false; } if ((Object)(object)_clip != (Object)null) { return false; } if (!string.Equals(_lastSoundFilePath, SoundFilePath, StringComparison.OrdinalIgnoreCase)) { _soundLoadRequested = false; } return !_soundLoadRequested; } private static AudioType GetAudioType(string path) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) return (AudioType)(Path.GetExtension(path)?.ToLowerInvariant() switch { ".wav" => 20, ".ogg" => 14, ".mp3" => 13, _ => 20, }); } public void Pop(string title, string body) { EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] Toast: " + title)); Ensure(); _queue.Enqueue(new ToastMessage(title, body)); if (!_busy) { if ((Object)(object)EmpressAchievementsPlugin.Runtime != (Object)null && Object.op_Implicit((Object)(object)EmpressAchievementsPlugin.Runtime)) { EmpressAchievementsPlugin.Runtime.StartManagedCoroutine(Run()); } else { ((MonoBehaviour)this).StartCoroutine(Run()); } } } private IEnumerator Run() { _busy = true; while (_queue.Count > 0) { ToastMessage msg = _queue.Dequeue(); yield return ShowToast(msg.Title, msg.Body); } _busy = false; } private IEnumerator ShowToast(string title, string body) { GameObject go = new GameObject("Toast"); RectTransform rt = go.AddComponent<RectTransform>(); ((Transform)rt).SetParent((Transform)(object)_root, false); rt.sizeDelta = new Vector2(520f, 100f); Image bg = go.AddComponent<Image>(); ((Graphic)bg).color = new Color(0.05f, 0.05f, 0.05f, 0.9f); ((Graphic)bg).raycastTarget = false; Outline outline = go.AddComponent<Outline>(); ((Shadow)outline).effectDistance = new Vector2(2f, -2f); ((Shadow)outline).effectColor = new Color(0.9f, 0.7f, 0.2f, 0.85f); GameObject titleGO = new GameObject("Title"); RectTransform titleRT = titleGO.AddComponent<RectTransform>(); ((Transform)titleRT).SetParent((Transform)(object)rt, false); titleRT.anchorMin = new Vector2(0f, 0.5f); titleRT.anchorMax = new Vector2(1f, 1f); titleRT.offsetMin = new Vector2(15f, -5f); titleRT.offsetMax = new Vector2(-15f, -5f); TextMeshProUGUI titleTMP = titleGO.AddComponent<TextMeshProUGUI>(); ((TMP_Text)titleTMP).text = title; ((TMP_Text)titleTMP).fontSize = 24f; ((Graphic)titleTMP).color = new Color(1f, 0.93f, 0.6f); ((TMP_Text)titleTMP).alignment = (TextAlignmentOptions)4097; ((TMP_Text)titleTMP).enableWordWrapping = true; ((TMP_Text)titleTMP).overflowMode = (TextOverflowModes)1; ((TMP_Text)titleTMP).fontStyle = (FontStyles)1; ((Graphic)titleTMP).raycastTarget = false; GameObject bodyGO = new GameObject("Body"); RectTransform bodyRT = bodyGO.AddComponent<RectTransform>(); ((Transform)bodyRT).SetParent((Transform)(object)rt, false); bodyRT.anchorMin = new Vector2(0f, 0f); bodyRT.anchorMax = new Vector2(1f, 0.5f); bodyRT.offsetMin = new Vector2(15f, 5f); bodyRT.offsetMax = new Vector2(-15f, 5f); TextMeshProUGUI bodyTMP = bodyGO.AddComponent<TextMeshProUGUI>(); ((TMP_Text)bodyTMP).text = body; ((TMP_Text)bodyTMP).fontSize = 16f; ((Graphic)bodyTMP).color = new Color(0.9f, 0.9f, 0.9f); ((TMP_Text)bodyTMP).alignment = (TextAlignmentOptions)4097; ((TMP_Text)bodyTMP).enableWordWrapping = true; ((TMP_Text)bodyTMP).overflowMode = (TextOverflowModes)1; ((Graphic)bodyTMP).raycastTarget = false; float usableWidth = rt.sizeDelta.x - 30f; Vector2 titlePref = ((TMP_Text)titleTMP).GetPreferredValues(((TMP_Text)titleTMP).text, usableWidth, 0f); Vector2 bodyPref = ((TMP_Text)bodyTMP).GetPreferredValues(((TMP_Text)bodyTMP).text, usableWidth, 0f); float newHeight = Mathf.Max(90f, titlePref.y + bodyPref.y + 28f); rt.sizeDelta = new Vector2(rt.sizeDelta.x, newHeight); float t2 = 0f; Vector2 start = new Vector2(0f, -150f); Vector2 mid = new Vector2(0f, 0f); Vector2 end = new Vector2(0f, -150f); rt.anchoredPosition = start; CanvasGroup cg = go.AddComponent<CanvasGroup>(); cg.alpha = 0f; if (EnableSound && (Object)(object)_clip != (Object)null && (Object)(object)_audio != (Object)null) { _audio.Stop(); _audio.PlayOneShot(_clip, Mathf.Clamp01(Volume)); } float inDur = 0.25f; while (t2 < inDur) { t2 += Time.unscaledDeltaTime; float p = t2 / inDur; float e = 1f - (1f - p) * (1f - p); cg.alpha = p; rt.anchoredPosition = Vector2.Lerp(start, mid, e); yield return null; } cg.alpha = 1f; rt.anchoredPosition = mid; yield return (object)new WaitForSecondsRealtime(Mathf.Max(1f, Duration)); t2 = 0f; float outDur = 0.25f; while (t2 < outDur) { t2 += Time.unscaledDeltaTime; float p2 = t2 / outDur; float e2 = p2 * p2; cg.alpha = 1f - p2; rt.anchoredPosition = Vector2.Lerp(mid, end, e2); yield return null; } Object.Destroy((Object)(object)go); } } public class AchievementsUi : MonoBehaviour { private enum AchievementListMode { All, Unlocked, Locked } private sealed class FilterTab { public AchievementListMode Mode { get; } public Image Background { get; } public TextMeshProUGUI Label { get; } public FilterTab(AchievementListMode mode, Image background, TextMeshProUGUI label) { Mode = mode; Background = background; Label = label; } } public float UiScale = 1f; private Canvas _canvas; private RectTransform _root; private GameObject _panel; private RectTransform _listRoot; private ScrollRect _scroll; private RectTransform _scrollRT; private RectTransform _scrollbarRT; private Scrollbar _scrollbar; private TextMeshProUGUI _statsLabel; private RectTransform _statsRT; private RectTransform _headerRT; private RectTransform _tabsRT; private bool _open; private float _nextStatsTick; private readonly List<FilterTab> _tabs = new List<FilterTab>(); private AchievementListMode _listMode = AchievementListMode.All; private bool _cursorCaptured; private bool _previousCursorVisible; private CursorLockMode _previousCursorLockState; private Texture2D _empressCursorTexture; private const float HeaderHeight = 66f; private const float TabsHeight = 44f; public void RefreshScale() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_root)) { ((Transform)_root).localScale = Vector3.one * UiScale; } if ((Object)(object)_panel != (Object)null && _panel.activeSelf) { RefreshList(); RecomputeTopLayout(); Canvas.ForceUpdateCanvases(); } } private void Ensure() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_canvas)) { EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Building Achievements Panel...]"); _canvas = new GameObject("Empress_AchievementPanelCanvas").AddComponent<Canvas>(); Object.DontDestroyOnLoad((Object)(object)_canvas); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 32700; CanvasScaler val = ((Component)_canvas).gameObject.AddComponent<CanvasScaler>(); val.uiScaleMode = (ScaleMode)1; val.referenceResolution = new Vector2(1920f, 1080f); val.screenMatchMode = (ScreenMatchMode)0; val.matchWidthOrHeight = 0.5f; ((Component)_canvas).gameObject.AddComponent<GraphicRaycaster>(); _root = new GameObject("PanelRoot").AddComponent<RectTransform>(); ((Transform)_root).SetParent(((Component)_canvas).transform, false); _root.anchorMin = new Vector2(0.5f, 0.5f); _root.anchorMax = new Vector2(0.5f, 0.5f); _root.pivot = new Vector2(0.5f, 0.5f); _root.sizeDelta = new Vector2(1000f, 700f); ((Transform)_root).localScale = Vector3.one * UiScale; _panel = BuildPanel(_root); _panel.SetActive(false); } } public void Toggle() { Ensure(); _open = !_open; _panel.SetActive(_open); if (_open) { ApplyUiCursor(); RefreshList(resetScroll: true); UpdateStatsLabel(); RecomputeTopLayout(); _nextStatsTick = Time.unscaledTime + 0.5f; Canvas.ForceUpdateCanvases(); } else { RestoreCursorState(); } } public void Prime() { Ensure(); } public void RefreshAllIfOpen() { if ((Object)(object)_panel != (Object)null && _panel.activeSelf) { UpdateStatsLabel(); RecomputeTopLayout(); RefreshList(); } } public void RefreshStatsIfOpen() { if ((Object)(object)_panel != (Object)null && _panel.activeSelf) { UpdateStatsLabel(); RecomputeTopLayout(); } } public void RefreshList(bool resetScroll = false) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Ensure(); if ((Object)(object)_panel == (Object)null) { return; } foreach (Transform item in (Transform)_listRoot) { Transform val = item; Object.Destroy((Object)(object)((Component)val).gameObject); } foreach (AchievementDef item2 in AchievementBook.AllOrdered()) { bool unlocked = EmpressAchievementsPlugin.Store.IsUnlocked(item2.Id); if (ShouldShowAchievement(unlocked)) { BuildEntry(_listRoot, item2, unlocked); } } LayoutRebuilder.ForceRebuildLayoutImmediate(_listRoot); RefreshTabVisuals(); if (resetScroll && (Object)(object)_scroll != (Object)null) { Canvas.ForceUpdateCanvases(); _scroll.verticalNormalizedPosition = 1f; } } private void Update() { if ((Object)(object)_panel == (Object)null || !_panel.activeSelf) { if (_cursorCaptured) { RestoreCursorState(); } return; } ApplyUiCursor(); ApplyUiControlLock(); if (Time.unscaledTime >= _nextStatsTick) { UpdateStatsLabel(); RecomputeTopLayout(); _nextStatsTick = Time.unscaledTime + 0.5f; } } private void UpdateStatsLabel() { if (!((Object)(object)_statsLabel == (Object)null)) { int count = AchievementBook.All.Count; int num = AchievementBook.All.Values.Count((AchievementDef def) => EmpressAchievementsPlugin.Store.IsUnlocked(def.Id)); int num2 = AchievementBook.All.Values.Count((AchievementDef def) => ShouldShowAchievement(EmpressAchievementsPlugin.Store.IsUnlocked(def.Id))); int stat = EmpressAchievementsPlugin.GetStat("extractions"); int stat2 = EmpressAchievementsPlugin.GetStat("purchases"); int stat3 = EmpressAchievementsPlugin.GetStat("deaths"); int stat4 = EmpressAchievementsPlugin.GetStat("revives"); long counter = EmpressAchievementsPlugin.Store.GetCounter("life_haul"); long counter2 = EmpressAchievementsPlugin.Store.GetCounter("kills_total"); string text = "$" + EmpressAchievementsPlugin.FormatK(counter); ((TMP_Text)_statsLabel).text = $"Showing {num2} | Unlocked {num}/{count}\n" + $"Extractions {stat} | Purchases {stat2} | Deaths {stat3} | Revives {stat4} | Lifetime Haul {text} | Kills {counter2}"; } } private GameObject BuildPanel(RectTransform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_008d: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Expected O, but got Unknown //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Expected O, but got Unknown //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_055b: Expected O, but got Unknown //IL_0586: Unknown result type (might be due to invalid IL or missing references) //IL_05a1: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) //IL_05d7: Unknown result type (might be due to invalid IL or missing references) //IL_0601: Unknown result type (might be due to invalid IL or missing references) //IL_0617: Unknown result type (might be due to invalid IL or missing references) //IL_068a: Unknown result type (might be due to invalid IL or missing references) //IL_0691: Expected O, but got Unknown //IL_06c2: Unknown result type (might be due to invalid IL or missing references) //IL_06dd: Unknown result type (might be due to invalid IL or missing references) //IL_06f8: Unknown result type (might be due to invalid IL or missing references) //IL_0709: Unknown result type (might be due to invalid IL or missing references) //IL_071a: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) //IL_077a: Unknown result type (might be due to invalid IL or missing references) //IL_0784: Expected O, but got Unknown //IL_07c0: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Expected O, but got Unknown //IL_07f2: Unknown result type (might be due to invalid IL or missing references) //IL_080d: Unknown result type (might be due to invalid IL or missing references) //IL_0828: Unknown result type (might be due to invalid IL or missing references) //IL_0843: Unknown result type (might be due to invalid IL or missing references) //IL_086d: Unknown result type (might be due to invalid IL or missing references) //IL_0897: Unknown result type (might be due to invalid IL or missing references) //IL_089e: Expected O, but got Unknown //IL_08b8: Unknown result type (might be due to invalid IL or missing references) //IL_08c5: Unknown result type (might be due to invalid IL or missing references) //IL_08dc: Unknown result type (might be due to invalid IL or missing references) //IL_08f3: Unknown result type (might be due to invalid IL or missing references) //IL_0903: Unknown result type (might be due to invalid IL or missing references) //IL_090a: Expected O, but got Unknown //IL_092a: Unknown result type (might be due to invalid IL or missing references) //IL_0941: Unknown result type (might be due to invalid IL or missing references) //IL_094e: Unknown result type (might be due to invalid IL or missing references) //IL_095b: Unknown result type (might be due to invalid IL or missing references) //IL_0985: Unknown result type (might be due to invalid IL or missing references) //IL_09c3: Unknown result type (might be due to invalid IL or missing references) //IL_09ca: Expected O, but got Unknown //IL_09e9: Unknown result type (might be due to invalid IL or missing references) //IL_0a00: Unknown result type (might be due to invalid IL or missing references) //IL_0a17: Unknown result type (might be due to invalid IL or missing references) //IL_0a2e: Unknown result type (might be due to invalid IL or missing references) //IL_0a45: Unknown result type (might be due to invalid IL or missing references) //IL_0a6f: Unknown result type (might be due to invalid IL or missing references) //IL_0a91: Unknown result type (might be due to invalid IL or missing references) //IL_0a9b: Expected O, but got Unknown //IL_0aa1: Unknown result type (might be due to invalid IL or missing references) //IL_0aa8: Expected O, but got Unknown //IL_0ac3: Unknown result type (might be due to invalid IL or missing references) //IL_0ad0: Unknown result type (might be due to invalid IL or missing references) //IL_0add: Unknown result type (might be due to invalid IL or missing references) //IL_0b1a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Panel"); RectTransform val2 = val.AddComponent<RectTransform>(); ((Transform)val2).SetParent((Transform)(object)parent, false); val2.sizeDelta = parent.sizeDelta; Image val3 = val.AddComponent<Image>(); ((Graphic)val3).color = new Color(0.02f, 0.02f, 0.02f, 0.9f); ((Graphic)val3).raycastTarget = true; GameObject val4 = new GameObject("Header"); _headerRT = val4.AddComponent<RectTransform>(); ((Transform)_headerRT).SetParent((Transform)(object)val2, false); _headerRT.anchorMin = new Vector2(0f, 1f); _headerRT.anchorMax = new Vector2(1f, 1f); _headerRT.pivot = new Vector2(0.5f, 1f); _headerRT.anchoredPosition = new Vector2(0f, -10f); _headerRT.sizeDelta = new Vector2(-20f, 66f); Image val5 = val4.AddComponent<Image>(); ((Graphic)val5).color = new Color(0.24f, 0.11f, 0.03f, 0.98f); TextMeshProUGUI val6 = new GameObject("Title").AddComponent<TextMeshProUGUI>(); RectTransform rectTransform = ((TMP_Text)val6).rectTransform; ((Transform)rectTransform).SetParent((Transform)(object)_headerRT, false); rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = new Vector2(20f, 0f); rectTransform.offsetMax = new Vector2(-70f, 0f); ((TMP_Text)val6).text = "EMPRESS Achievements"; ((TMP_Text)val6).fontSize = 36f; ((Graphic)val6).color = new Color(1f, 0.92f, 0.6f); ((TMP_Text)val6).alignment = (TextAlignmentOptions)4097; ((TMP_Text)val6).fontStyle = (FontStyles)1; ((Graphic)val6).raycastTarget = false; GameObject val7 = new GameObject("Stats"); _statsRT = val7.AddComponent<RectTransform>(); ((Transform)_statsRT).SetParent((Transform)(object)val2, false); _statsRT.anchorMin = new Vector2(0f, 1f); _statsRT.anchorMax = new Vector2(1f, 1f); _statsRT.pivot = new Vector2(0.5f, 1f); _statsRT.anchoredPosition = new Vector2(0f, -82f); _statsRT.sizeDelta = new Vector2(-20f, 92f); Image val8 = val7.AddComponent<Image>(); ((Graphic)val8).color = new Color(0.08f, 0.08f, 0.08f, 0.92f); _statsLabel = new GameObject("StatsText").AddComponent<TextMeshProUGUI>(); RectTransform rectTransform2 = ((TMP_Text)_statsLabel).rectTransform; ((Transform)rectTransform2).SetParent((Transform)(object)_statsRT, false); rectTransform2.anchorMin = Vector2.zero; rectTransform2.anchorMax = Vector2.one; rectTransform2.offsetMin = new Vector2(16f, 12f); rectTransform2.offsetMax = new Vector2(-16f, -12f); ((TMP_Text)_statsLabel).fontSize = 18f; ((TMP_Text)_statsLabel).alignment = (TextAlignmentOptions)257; ((TMP_Text)_statsLabel).enableWordWrapping = true; ((TMP_Text)_statsLabel).overflowMode = (TextOverflowModes)0; ((Graphic)_statsLabel).color = new Color(0.85f, 0.85f, 0.85f); ((Graphic)_statsLabel).raycastTarget = false; UpdateStatsLabel(); GameObject val9 = new GameObject("Tabs"); _tabsRT = val9.AddComponent<RectTransform>(); ((Transform)_tabsRT).SetParent((Transform)(object)val2, false); _tabsRT.anchorMin = new Vector2(0f, 1f); _tabsRT.anchorMax = new Vector2(1f, 1f); _tabsRT.pivot = new Vector2(0.5f, 1f); _tabsRT.anchoredPosition = new Vector2(0f, -170f); _tabsRT.sizeDelta = new Vector2(-20f, 44f); Image val10 = val9.AddComponent<Image>(); ((Graphic)val10).color = new Color(0.06f, 0.06f, 0.06f, 0.92f); HorizontalLayoutGroup val11 = val9.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)val11).childAlignment = (TextAnchor)3; ((HorizontalOrVerticalLayoutGroup)val11).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val11).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val11).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val11).childForceExpandHeight = true; ((HorizontalOrVerticalLayoutGroup)val11).spacing = 10f; ((LayoutGroup)val11).padding = new RectOffset(10, 10, 6, 6); _tabs.Clear(); _tabs.Add(BuildTabButton(_tabsRT, "ALL", AchievementListMode.All)); _tabs.Add(BuildTabButton(_tabsRT, "UNLOCKED", AchievementListMode.Unlocked)); _tabs.Add(BuildTabButton(_tabsRT, "LOCKED", AchievementListMode.Locked)); RefreshTabVisuals(); GameObject val12 = new GameObject("ScrollViewport"); _scrollRT = val12.AddComponent<RectTransform>(); ((Transform)_scrollRT).SetParent((Transform)(object)val2, false); _scrollRT.anchorMin = new Vector2(0f, 0f); _scrollRT.anchorMax = new Vector2(1f, 1f); _scrollRT.offsetMin = new Vector2(20f, 20f); _scrollRT.offsetMax = new Vector2(-52f, -220f); Image val13 = val12.AddComponent<Image>(); ((Graphic)val13).color = new Color(0.08f, 0.08f, 0.08f, 0.96f); RectMask2D val14 = val12.AddComponent<RectMask2D>(); val14.padding = Vector4.zero; _scroll = val12.AddComponent<ScrollRect>(); _scroll.horizontal = false; _scroll.vertical = true; _scroll.movementType = (MovementType)2; _scroll.scrollSensitivity = 32f; _scroll.verticalScrollbarSpacing = 10f; _scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0; GameObject val15 = new GameObject("Content"); _listRoot = val15.AddComponent<RectTransform>(); ((Transform)_listRoot).SetParent(val12.transform, false); _listRoot.anchorMin = new Vector2(0f, 1f); _listRoot.anchorMax = new Vector2(1f, 1f); _listRoot.pivot = new Vector2(0.5f, 1f); _listRoot.offsetMin = Vector2.zero; _listRoot.offsetMax = Vector2.zero; _listRoot.anchoredPosition = Vector2.zero; VerticalLayoutGroup val16 = val15.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val16).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val16).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val16).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)val16).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val16).spacing = 8f; ((LayoutGroup)val16).padding = new RectOffset(12, 12, 12, 12); ContentSizeFitter val17 = val15.AddComponent<ContentSizeFitter>(); val17.verticalFit = (FitMode)2; _scroll.content = _listRoot; _scroll.viewport = _scrollRT; GameObject val18 = new GameObject("Scrollbar"); _scrollbarRT = val18.AddComponent<RectTransform>(); ((Transform)_scrollbarRT).SetParent((Transform)(object)val2, false); _scrollbarRT.anchorMin = new Vector2(1f, 0f); _scrollbarRT.anchorMax = new Vector2(1f, 1f); _scrollbarRT.offsetMin = new Vector2(-36f, 20f); _scrollbarRT.offsetMax = new Vector2(-18f, -220f); Image val19 = val18.AddComponent<Image>(); ((Graphic)val19).color = new Color(0.23f, 0.12f, 0.05f, 0.95f); _scrollbar = val18.AddComponent<Scrollbar>(); _scrollbar.direction = (Direction)2; GameObject val20 = new GameObject("SlidingArea"); RectTransform val21 = val20.AddComponent<RectTransform>(); ((Transform)val21).SetParent((Transform)(object)_scrollbarRT, false); val21.anchorMin = Vector2.zero; val21.anchorMax = Vector2.one; val21.offsetMin = new Vector2(3f, 3f); val21.offsetMax = new Vector2(-3f, -3f); GameObject val22 = new GameObject("Handle"); RectTransform val23 = val22.AddComponent<RectTransform>(); ((Transform)val23).SetParent((Transform)(object)val21, false); val23.anchorMin = new Vector2(0f, 0f); val23.anchorMax = new Vector2(1f, 1f); val23.offsetMin = Vector2.zero; val23.offsetMax = Vector2.zero; Image val24 = val22.AddComponent<Image>(); ((Graphic)val24).color = new Color(1f, 0.62f, 0.25f, 0.98f); ((Selectable)_scrollbar).targetGraphic = (Graphic)(object)val24; _scrollbar.handleRect = val23; _scroll.verticalScrollbar = _scrollbar; GameObject val25 = new GameObject("CloseButton"); RectTransform val26 = val25.AddComponent<RectTransform>(); ((Transform)val26).SetParent((Transform)(object)val2, false); val26.anchorMin = new Vector2(1f, 1f); val26.anchorMax = new Vector2(1f, 1f); val26.pivot = new Vector2(1f, 1f); val26.anchoredPosition = new Vector2(-18f, -18f); val26.sizeDelta = new Vector2(42f, 42f); Image val27 = val25.AddComponent<Image>(); ((Graphic)val27).color = new Color(0.75f, 0.18f, 0.14f, 0.95f); Button val28 = val25.AddComponent<Button>(); ((UnityEvent)val28.onClick).AddListener((UnityAction)delegate { Toggle(); }); GameObject val29 = new GameObject("X"); RectTransform val30 = val29.AddComponent<RectTransform>(); ((Transform)val30).SetParent(val25.transform, false); val30.sizeDelta = Vector2.zero; val30.anchorMin = Vector2.zero; val30.anchorMax = Vector2.one; TextMeshProUGUI val31 = val29.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val31).text = "×"; ((TMP_Text)val31).fontSize = 22f; ((TMP_Text)val31).alignment = (TextAlignmentOptions)4098; ((Graphic)val31).color = Color.white; ((TMP_Text)val31).fontStyle = (FontStyles)1; ((Graphic)val31).raycastTarget = false; return val; } private float GetContentWidth() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) float num; Rect rect; if (!((Object)(object)_scrollRT != (Object)null)) { if (!((Object)(object)_root != (Object)null)) { num = 920f; } else { rect = _root.rect; num = ((Rect)(ref rect)).width - 80f; } } else { rect = _scrollRT.rect; num = ((Rect)(ref rect)).width; } float num2 = num; return Mathf.Max(100f, num2 - 30f); } private void RecomputeTopLayout() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_statsLabel == (Object)null) && !((Object)(object)_statsRT == (Object)null) && !((Object)(object)_headerRT == (Object)null) && !((Object)(object)_scrollRT == (Object)null) && !((Object)(object)_tabsRT == (Object)null) && !((Object)(object)_scrollbarRT == (Object)null)) { float num; if (!((Object)(object)_root != (Object)null)) { num = 1000f; } else { Rect rect = _root.rect; num = ((Rect)(ref rect)).width; } float num2 = Mathf.Max(240f, num - 100f); Vector2 preferredValues = ((TMP_Text)_statsLabel).GetPreferredValues(((TMP_Text)_statsLabel).text, num2, 0f); float num3 = Mathf.Clamp(preferredValues.y + 24f, 72f, 150f); _statsRT.sizeDelta = new Vector2(-20f, num3); _statsRT.anchoredPosition = new Vector2(0f, -82f); _tabsRT.anchoredPosition = new Vector2(0f, 0f - (66f + num3 + 22f)); float num4 = 66f + num3 + 44f + 30f; _scrollRT.offsetMax = new Vector2(-52f, 0f - num4); _scrollbarRT.offsetMax = new Vector2(-18f, 0f - num4); } } private void BuildEntry(RectTransform parent, AchievementDef def, bool unlocked) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing