using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; 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 Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.MessageLog.Messages; using Archipelago.MultiClient.Net.MessageLog.Parts; using Archipelago.MultiClient.Net.Models; using Aube; using Aube.Relays; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GarfieldKartAPMod.Helpers; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TMPro; using UnityEngine; using UnityEngine.Rendering.PostProcessing; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("GarfieldKartAPMod")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+42c06cc2c333864bc50015f2409bd233ae3f6b48")] [assembly: AssemblyProduct("GarfieldKartAPMod")] [assembly: AssemblyTitle("GarfieldKartAPMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GarfieldKartAPMod { public static class ApJsonSaveFile { private class SlotSaveData { public HashSet RaceVictories = new HashSet(); public HashSet CupVictories = new HashSet(); public HashSet TimeTrialVictories = new HashSet(); public List ActiveFiller = new List(); public List CompletedFiller = new List(); } public class SavedActiveFiller { public long Id; public int RemainingRaces; public float TrapSecondsActive; } private static SlotSaveData cached; private static string cachedKey; public static void RecordRaceVictory(string track) { SlotSaveData slotSaveData = Load(); if (slotSaveData != null && slotSaveData.RaceVictories.Add(track)) { Save(slotSaveData); } } public static void RecordCupVictory(int cupId) { SlotSaveData slotSaveData = Load(); if (slotSaveData != null && slotSaveData.CupVictories.Add(cupId)) { Save(slotSaveData); } } public static void RecordTimeTrialVictory(string track) { SlotSaveData slotSaveData = Load(); if (slotSaveData != null && slotSaveData.TimeTrialVictories.Add(track)) { Save(slotSaveData); } } public static int GetRaceVictoryCount() { return Load()?.RaceVictories.Count ?? 0; } public static int GetCupVictoryCount() { return Load()?.CupVictories.Count ?? 0; } public static int GetTimeTrialVictoryCount() { return Load()?.TimeTrialVictories.Count ?? 0; } public static List GetActiveFillerState() { return Load()?.ActiveFiller ?? new List(); } public static List GetCompletedFillerState() { return Load()?.CompletedFiller ?? new List(); } public static void SaveFillerState(List active, List completed) { SlotSaveData slotSaveData = Load(); if (slotSaveData != null) { slotSaveData.ActiveFiller = active; slotSaveData.CompletedFiller = completed; Save(slotSaveData); } } private static SlotSaveData Load() { string fileKey = GetFileKey(); if (fileKey == null) { return null; } if (cached != null && cachedKey == fileKey) { return cached; } SlotSaveData slotSaveData = new SlotSaveData(); string path = GetPath(fileKey); try { if (File.Exists(path)) { slotSaveData = JsonConvert.DeserializeObject(File.ReadAllText(path)) ?? new SlotSaveData(); } } catch (Exception ex) { Log.Error("Failed to read save file " + path + ": " + ex.Message); } MergeLegacyTimeTrialFile(slotSaveData); cached = slotSaveData; cachedKey = fileKey; return slotSaveData; } private static void Save(SlotSaveData data) { string fileKey = GetFileKey(); if (fileKey == null) { return; } string path = GetPath(fileKey); try { File.WriteAllText(path, JsonConvert.SerializeObject((object)data, (Formatting)1)); } catch (Exception ex) { Log.Error("Failed to write save file " + path + ": " + ex.Message); } } private static void MergeLegacyTimeTrialFile(SlotSaveData data) { string seed = GetSeed(); if (seed == null) { return; } string path = Application.persistentDataPath + "/" + seed + "_timetrials.txt"; try { if (!File.Exists(path)) { return; } string[] array = File.ReadAllLines(path); foreach (string text in array) { if (!string.IsNullOrWhiteSpace(text)) { data.TimeTrialVictories.Add(text.Trim()); } } } catch (Exception ex) { Log.Error("Failed to merge legacy time trial file: " + ex.Message); } } private static string GetSeed() { ArchipelagoSession obj = GarfieldKartAPMod.APClient?.GetSession(); object obj2; if (obj == null) { obj2 = null; } else { IRoomStateHelper roomState = obj.RoomState; obj2 = ((roomState != null) ? roomState.Seed : null); } string text = (string)obj2; if (!string.IsNullOrWhiteSpace(text)) { return text; } return null; } private static string GetFileKey() { string seed = GetSeed(); string text = GarfieldKartAPMod.APClient?.SlotName; if (seed == null || string.IsNullOrWhiteSpace(text)) { return null; } return seed + "_" + SanitizeForFileName(text); } private static string GetPath(string fileKey) { return Application.persistentDataPath + "/" + fileKey + ".json"; } private static string SanitizeForFileName(string name) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { name = name.Replace(oldChar, '_'); } return name; } } public class ArchipelagoClient { private ArchipelagoSession session; private readonly Queue pendingNotifications = new Queue(); public bool IsConnected { get { ArchipelagoSession obj = session; if (obj == null) { return false; } return obj.Socket.Connected; } } public string SlotName { get; private set; } public event Action OnConnected; public event Action OnConnectionFailed; public event Action OnDisconnected; public void Connect(string hostname, int port, string slotName, string password = "") { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown try { Log.Message($"Attempting to connect to {hostname}:{port} as {slotName}"); session = ArchipelagoSessionFactory.CreateSession(hostname, port); session.Socket.ErrorReceived += new ErrorReceivedHandler(OnError); session.Socket.SocketClosed += new SocketClosedHandler(OnSocketClosed); LoginResult val = session.TryConnectAndLogin("Garfield Kart - Furious Racing", slotName, (ItemsHandlingFlags)7, new Version(0, 6, 6), (string[])null, (string)null, string.IsNullOrEmpty(password) ? null : password, true); if (val.Successful) { LoginSuccessful val2 = (LoginSuccessful)val; SlotName = slotName; GarfieldKartAPMod.sessionSlotData = val2.SlotData; Log.Message($"Connected successfully! Slot: {val2.Slot}"); foreach (KeyValuePair slotDatum in val2.SlotData) { Log.Message($"Slot Data: {slotDatum.Key} = {slotDatum.Value}"); } session.MessageLog.OnMessageReceived += new MessageReceivedHandler(OnMessageReceived); DeathLinkManager.OnSessionConnected(session); ArchipelagoItemTracker.LoadFromServer(); this.OnConnected?.Invoke(); ArchipelagoItemTracker.LogAllReceivedItems(); ArchipelagoItemTracker.LogAllCheckedLocations(); } else { LoginFailure val3 = (LoginFailure)val; string text = string.Join(", ", val3.Errors); Log.Error("Connection failed: " + text); this.OnConnectionFailed?.Invoke(text); session = null; } } catch (Exception ex) { Log.Error($"Connection exception: {ex}"); this.OnConnectionFailed?.Invoke(ex.Message); session = null; } } public ArchipelagoSession GetSession() { return session; } public void Disconnect() { if (session != null) { session.Socket.DisconnectAsync(); session = null; DeathLinkManager.OnDisconnected(); Log.Message("Disconnected from Archipelago"); } } private void OnMessageReceived(LogMessage message) { ConfigEntry showOnlyRelevantNotifications = GarfieldKartAPMod.showOnlyRelevantNotifications; if (showOnlyRelevantNotifications != null && showOnlyRelevantNotifications.Value) { ItemSendLogMessage val = (ItemSendLogMessage)(object)((message is ItemSendLogMessage) ? message : null); if (val == null || (!val.IsSenderTheActivePlayer && !val.IsReceiverTheActivePlayer)) { return; } } pendingNotifications.Enqueue(FormatLogMessage(message)); } private string FormatLogMessage(LogMessage message) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); MessagePart[] parts = message.Parts; foreach (MessagePart val in parts) { string colorHex = GetColorHex(val.Color); if (colorHex != null) { stringBuilder.Append("" + val.Text + ""); } else { stringBuilder.Append(val.Text); } } return stringBuilder.ToString(); } private string GetColorHex(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00bf: Unknown result type (might be due to invalid IL or missing references) if (color == Color.Black) { return "000000"; } if (color == Color.Red) { return "EE0000"; } if (color == Color.Green) { return "00FF7F"; } if (color == Color.Yellow) { return "FAFAD2"; } if (color == Color.Blue) { return "6495ED"; } if (color == Color.Magenta) { return "EE00EE"; } if (color == Color.Cyan) { return "00EEEE"; } if (color == Color.White) { return "FFFFFF"; } if (color == Color.Plum) { return "DDA0DD"; } if (color == Color.SlateBlue) { return "6A5ACD"; } if (color == Color.Salmon) { return "FA8072"; } return null; } private void OnError(Exception ex, string message) { Log.Error("Socket error: " + message + " - " + ex.Message); } private void OnSocketClosed(string reason) { Log.Warning("Socket closed: " + reason); session = null; DeathLinkManager.OnDisconnected(); this.OnDisconnected?.Invoke(); } public void SendLocation(long locationId) { if (IsConnected) { ArchipelagoItemTracker.AddCheckedLocation(locationId); session.Locations.CompleteLocationChecks(new long[1] { locationId }); Log.Message($"Sent location check: {locationId}"); } } public string GetSlotDataValue(string key) { if (session == null || GarfieldKartAPMod.sessionSlotData == null) { return null; } if (GarfieldKartAPMod.sessionSlotData.TryGetValue("options", out var value)) { Dictionary dictionary2; if (!(value is Dictionary dictionary)) { JObject val = (JObject)((value is JObject) ? value : null); dictionary2 = ((val == null) ? null : ((JToken)val).ToObject>()); } else { dictionary2 = dictionary; } Dictionary dictionary3 = dictionary2; if (dictionary3 != null && dictionary3.TryGetValue(key, out var value2)) { return value2.ToString(); } } if (GarfieldKartAPMod.sessionSlotData.TryGetValue(key, out var value3)) { return value3.ToString(); } throw new SlotDataException("Invalid option requested from apworld: " + key + ". Did you generate on the wrong version?"); } public string GetSeed() { ArchipelagoSession obj = session; if (obj == null) { return null; } IRoomStateHelper roomState = obj.RoomState; if (roomState == null) { return null; } return roomState.Seed; } public void QueueNotification(string message) { pendingNotifications.Enqueue(message); } public bool HasPendingNotifications() { return pendingNotifications.Count > 0; } public string DequeuePendingNotification() { return pendingNotifications.Dequeue(); } } public static class ArchipelagoConstants { public const long LOC_CATZ_IN_THE_HOOD_VICTORY = 1L; public const long LOC_CRAZY_DUNES_VICTORY = 2L; public const long LOC_PALEROCK_LAKE_VICTORY = 3L; public const long LOC_CITY_SLICKER_VICTORY = 4L; public const long LOC_COUNTRY_BUMPKIN_VICTORY = 5L; public const long LOC_SPOOKY_MANOR_VICTORY = 6L; public const long LOC_MALLY_MARKET_VICTORY = 7L; public const long LOC_VALLEY_OF_THE_KINGS_VICTORY = 8L; public const long LOC_MISTY_FOR_ME_VICTORY = 9L; public const long LOC_SNEAK_A_PEAK_VICTORY = 10L; public const long LOC_BLAZING_OASIS_VICTORY = 11L; public const long LOC_PASTACOSI_FACTORY_VICTORY = 12L; public const long LOC_MYSTERIOUS_TEMPLE_VICTORY = 13L; public const long LOC_PROHIBITED_SITE_VICTORY = 14L; public const long LOC_CASKOU_PARK_VICTORY = 15L; public const long LOC_LOOPY_LAGOON_VICTORY = 16L; public const long LOC_CATZ_IN_THE_HOOD_TIME_TRIAL_BRONZE = 21L; public const long LOC_CRAZY_DUNES_TIME_TRIAL_BRONZE = 22L; public const long LOC_PALEROCK_LAKE_TIME_TRIAL_BRONZE = 23L; public const long LOC_CITY_SLICKER_TIME_TRIAL_BRONZE = 24L; public const long LOC_COUNTRY_BUMPKIN_TIME_TRIAL_BRONZE = 25L; public const long LOC_SPOOKY_MANOR_TIME_TRIAL_BRONZE = 26L; public const long LOC_MALLY_MARKET_TIME_TRIAL_BRONZE = 27L; public const long LOC_VALLEY_OF_THE_KINGS_TIME_TRIAL_BRONZE = 28L; public const long LOC_MISTY_FOR_ME_TIME_TRIAL_BRONZE = 29L; public const long LOC_SNEAK_A_PEAK_TIME_TRIAL_BRONZE = 30L; public const long LOC_BLAZING_OASIS_TIME_TRIAL_BRONZE = 31L; public const long LOC_PASTACOSI_FACTORY_TIME_TRIAL_BRONZE = 32L; public const long LOC_MYSTERIOUS_TEMPLE_TIME_TRIAL_BRONZE = 33L; public const long LOC_PROHIBITED_SITE_TIME_TRIAL_BRONZE = 34L; public const long LOC_CASKOU_PARK_TIME_TRIAL_BRONZE = 35L; public const long LOC_LOOPY_LAGOON_TIME_TRIAL_BRONZE = 36L; public const long LOC_CATZ_IN_THE_HOOD_TIME_TRIAL_SILVER = 41L; public const long LOC_CRAZY_DUNES_TIME_TRIAL_SILVER = 42L; public const long LOC_PALEROCK_LAKE_TIME_TRIAL_SILVER = 43L; public const long LOC_CITY_SLICKER_TIME_TRIAL_SILVER = 44L; public const long LOC_COUNTRY_BUMPKIN_TIME_TRIAL_SILVER = 45L; public const long LOC_SPOOKY_MANOR_TIME_TRIAL_SILVER = 46L; public const long LOC_MALLY_MARKET_TIME_TRIAL_SILVER = 47L; public const long LOC_VALLEY_OF_THE_KINGS_TIME_TRIAL_SILVER = 48L; public const long LOC_MISTY_FOR_ME_TIME_TRIAL_SILVER = 49L; public const long LOC_SNEAK_A_PEAK_TIME_TRIAL_SILVER = 50L; public const long LOC_BLAZING_OASIS_TIME_TRIAL_SILVER = 51L; public const long LOC_PASTACOSI_FACTORY_TIME_TRIAL_SILVER = 52L; public const long LOC_MYSTERIOUS_TEMPLE_TIME_TRIAL_SILVER = 53L; public const long LOC_PROHIBITED_SITE_TIME_TRIAL_SILVER = 54L; public const long LOC_CASKOU_PARK_TIME_TRIAL_SILVER = 55L; public const long LOC_LOOPY_LAGOON_TIME_TRIAL_SILVER = 56L; public const long LOC_CATZ_IN_THE_HOOD_TIME_TRIAL_GOLD = 61L; public const long LOC_CRAZY_DUNES_TIME_TRIAL_GOLD = 62L; public const long LOC_PALEROCK_LAKE_TIME_TRIAL_GOLD = 63L; public const long LOC_CITY_SLICKER_TIME_TRIAL_GOLD = 64L; public const long LOC_COUNTRY_BUMPKIN_TIME_TRIAL_GOLD = 65L; public const long LOC_SPOOKY_MANOR_TIME_TRIAL_GOLD = 66L; public const long LOC_MALLY_MARKET_TIME_TRIAL_GOLD = 67L; public const long LOC_VALLEY_OF_THE_KINGS_TIME_TRIAL_GOLD = 68L; public const long LOC_MISTY_FOR_ME_TIME_TRIAL_GOLD = 69L; public const long LOC_SNEAK_A_PEAK_TIME_TRIAL_GOLD = 70L; public const long LOC_BLAZING_OASIS_TIME_TRIAL_GOLD = 71L; public const long LOC_PASTACOSI_FACTORY_TIME_TRIAL_GOLD = 72L; public const long LOC_MYSTERIOUS_TEMPLE_TIME_TRIAL_GOLD = 73L; public const long LOC_PROHIBITED_SITE_TIME_TRIAL_GOLD = 74L; public const long LOC_CASKOU_PARK_TIME_TRIAL_GOLD = 75L; public const long LOC_LOOPY_LAGOON_TIME_TRIAL_GOLD = 76L; public const long LOC_CATZ_IN_THE_HOOD_TIME_TRIAL_PLATINUM = 81L; public const long LOC_CRAZY_DUNES_TIME_TRIAL_PLATINUM = 82L; public const long LOC_PALEROCK_LAKE_TIME_TRIAL_PLATINUM = 83L; public const long LOC_CITY_SLICKER_TIME_TRIAL_PLATINUM = 84L; public const long LOC_COUNTRY_BUMPKIN_TIME_TRIAL_PLATINUM = 85L; public const long LOC_SPOOKY_MANOR_TIME_TRIAL_PLATINUM = 86L; public const long LOC_MALLY_MARKET_TIME_TRIAL_PLATINUM = 87L; public const long LOC_VALLEY_OF_THE_KINGS_TIME_TRIAL_PLATINUM = 88L; public const long LOC_MISTY_FOR_ME_TIME_TRIAL_PLATINUM = 89L; public const long LOC_SNEAK_A_PEAK_TIME_TRIAL_PLATINUM = 90L; public const long LOC_BLAZING_OASIS_TIME_TRIAL_PLATINUM = 91L; public const long LOC_PASTACOSI_FACTORY_TIME_TRIAL_PLATINUM = 92L; public const long LOC_MYSTERIOUS_TEMPLE_TIME_TRIAL_PLATINUM = 93L; public const long LOC_PROHIBITED_SITE_TIME_TRIAL_PLATINUM = 94L; public const long LOC_CASKOU_PARK_TIME_TRIAL_PLATINUM = 95L; public const long LOC_LOOPY_LAGOON_TIME_TRIAL_PLATINUM = 96L; public const long LOC_TIME_TRIAL_MEDAL_GAP = 20L; public const long LOC_LASAGNA_CUP_VICTORY = 101L; public const long LOC_PIZZA_CUP_VICTORY = 102L; public const long LOC_BURGER_CUP_VICTORY = 103L; public const long LOC_ICE_CREAM_CUP_VICTORY = 104L; public const long LOC_RACE_VICTORY_CC_BASE = 700L; public const long LOC_RACE_VICTORY_CC_GAP = 20L; public const long LOC_CUP_VICTORY_CC_BASE = 760L; public const long LOC_CUP_VICTORY_CC_GAP = 10L; public const long LOC_CATZ_IN_THE_HOOD_PUZZLE_PIECE_1 = 201L; public const long LOC_CATZ_IN_THE_HOOD_PUZZLE_PIECE_2 = 202L; public const long LOC_CATZ_IN_THE_HOOD_PUZZLE_PIECE_3 = 203L; public const long LOC_CRAZY_DUNES_PUZZLE_PIECE_1 = 204L; public const long LOC_CRAZY_DUNES_PUZZLE_PIECE_2 = 205L; public const long LOC_CRAZY_DUNES_PUZZLE_PIECE_3 = 206L; public const long LOC_PALEROCK_LAKE_PUZZLE_PIECE_1 = 207L; public const long LOC_PALEROCK_LAKE_PUZZLE_PIECE_2 = 208L; public const long LOC_PALEROCK_LAKE_PUZZLE_PIECE_3 = 209L; public const long LOC_CITY_SLICKER_PUZZLE_PIECE_1 = 210L; public const long LOC_CITY_SLICKER_PUZZLE_PIECE_2 = 211L; public const long LOC_CITY_SLICKER_PUZZLE_PIECE_3 = 212L; public const long LOC_COUNTRY_BUMPKIN_PUZZLE_PIECE_1 = 213L; public const long LOC_COUNTRY_BUMPKIN_PUZZLE_PIECE_2 = 214L; public const long LOC_COUNTRY_BUMPKIN_PUZZLE_PIECE_3 = 215L; public const long LOC_SPOOKY_MANOR_PUZZLE_PIECE_1 = 216L; public const long LOC_SPOOKY_MANOR_PUZZLE_PIECE_2 = 217L; public const long LOC_SPOOKY_MANOR_PUZZLE_PIECE_3 = 218L; public const long LOC_MALLY_MARKET_PUZZLE_PIECE_1 = 219L; public const long LOC_MALLY_MARKET_PUZZLE_PIECE_2 = 220L; public const long LOC_MALLY_MARKET_PUZZLE_PIECE_3 = 221L; public const long LOC_VALLEY_OF_THE_KINGS_PUZZLE_PIECE_1 = 222L; public const long LOC_VALLEY_OF_THE_KINGS_PUZZLE_PIECE_2 = 223L; public const long LOC_VALLEY_OF_THE_KINGS_PUZZLE_PIECE_3 = 224L; public const long LOC_MISTY_FOR_ME_PUZZLE_PIECE_1 = 225L; public const long LOC_MISTY_FOR_ME_PUZZLE_PIECE_2 = 226L; public const long LOC_MISTY_FOR_ME_PUZZLE_PIECE_3 = 227L; public const long LOC_SNEAK_A_PEAK_PUZZLE_PIECE_1 = 228L; public const long LOC_SNEAK_A_PEAK_PUZZLE_PIECE_2 = 229L; public const long LOC_SNEAK_A_PEAK_PUZZLE_PIECE_3 = 230L; public const long LOC_BLAZING_OASIS_PUZZLE_PIECE_1 = 231L; public const long LOC_BLAZING_OASIS_PUZZLE_PIECE_2 = 232L; public const long LOC_BLAZING_OASIS_PUZZLE_PIECE_3 = 233L; public const long LOC_PASTACOSI_FACTORY_PUZZLE_PIECE_1 = 234L; public const long LOC_PASTACOSI_FACTORY_PUZZLE_PIECE_2 = 235L; public const long LOC_PASTACOSI_FACTORY_PUZZLE_PIECE_3 = 236L; public const long LOC_MYSTERIOUS_TEMPLE_PUZZLE_PIECE_1 = 237L; public const long LOC_MYSTERIOUS_TEMPLE_PUZZLE_PIECE_2 = 238L; public const long LOC_MYSTERIOUS_TEMPLE_PUZZLE_PIECE_3 = 239L; public const long LOC_PROHIBITED_SITE_PUZZLE_PIECE_1 = 240L; public const long LOC_PROHIBITED_SITE_PUZZLE_PIECE_2 = 241L; public const long LOC_PROHIBITED_SITE_PUZZLE_PIECE_3 = 242L; public const long LOC_CASKOU_PARK_PUZZLE_PIECE_1 = 243L; public const long LOC_CASKOU_PARK_PUZZLE_PIECE_2 = 244L; public const long LOC_CASKOU_PARK_PUZZLE_PIECE_3 = 245L; public const long LOC_LOOPY_LAGOON_PUZZLE_PIECE_1 = 246L; public const long LOC_LOOPY_LAGOON_PUZZLE_PIECE_2 = 247L; public const long LOC_LOOPY_LAGOON_PUZZLE_PIECE_3 = 248L; public const long LOC_CATZ_IN_THE_HOOD_LAP_SANITY = 500L; public const long LOC_CRAZY_DUNES_LAP_SANITY = 510L; public const long LOC_PALEROCK_LAKE_LAP_SANITY = 520L; public const long LOC_CITY_SLICKER_LAP_SANITY = 530L; public const long LOC_COUNTRY_BUMPKIN_LAP_SANITY = 540L; public const long LOC_SPOOKY_MANOR_LAP_SANITY = 550L; public const long LOC_MALLY_MARKET_LAP_SANITY = 560L; public const long LOC_VALLEY_OF_THE_KINGS_LAP_SANITY = 570L; public const long LOC_MISTY_FOR_ME_LAP_SANITY = 580L; public const long LOC_SNEAK_A_PEAK_LAP_SANITY = 590L; public const long LOC_BLAZING_OASIS_LAP_SANITY = 600L; public const long LOC_PASTACOSI_FACTORY_LAP_SANITY = 610L; public const long LOC_MYSTERIOUS_TEMPLE_LAP_SANITY = 620L; public const long LOC_PROHIBITED_SITE_LAP_SANITY = 630L; public const long LOC_CASKOU_PARK_LAP_SANITY = 640L; public const long LOC_LOOPY_LAGOON_LAP_SANITY = 650L; public const long LOC_LASAGNA_CUP_UNLOCK_SPOILER_1 = 301L; public const long LOC_PIZZA_CUP_UNLOCK_SPOILER_1 = 302L; public const long LOC_BURGER_CUP_UNLOCK_SPOILER_1 = 303L; public const long LOC_ICE_CREAM_CUP_UNLOCK_SPOILER_1 = 304L; public const long LOC_LASAGNA_CUP_UNLOCK_SPOILER_2 = 311L; public const long LOC_PIZZA_CUP_UNLOCK_SPOILER_2 = 312L; public const long LOC_BURGER_CUP_UNLOCK_SPOILER_2 = 313L; public const long LOC_ICE_CREAM_CUP_UNLOCK_SPOILER_2 = 314L; public const long LOC_CATZ_IN_THE_HOOD_HAT_UNLOCK = 401L; public const long LOC_CRAZY_DUNES_HAT_UNLOCK = 402L; public const long LOC_PALEROCK_LAKE_HAT_UNLOCK = 403L; public const long LOC_CITY_SLICKER_HAT_UNLOCK = 404L; public const long LOC_COUNTRY_BUMPKIN_HAT_UNLOCK = 405L; public const long LOC_SPOOKY_MANOR_HAT_UNLOCK = 406L; public const long LOC_MALLY_MARKET_HAT_UNLOCK = 407L; public const long LOC_VALLEY_OF_THE_KINGS_HAT_UNLOCK = 408L; public const long LOC_MISTY_FOR_ME_HAT_UNLOCK = 409L; public const long LOC_SNEAK_A_PEAK_HAT_UNLOCK = 410L; public const long LOC_BLAZING_OASIS_HAT_UNLOCK = 411L; public const long LOC_PASTACOSI_FACTORY_HAT_UNLOCK = 412L; public const long LOC_MYSTERIOUS_TEMPLE_HAT_UNLOCK = 413L; public const long LOC_PROHIBITED_SITE_HAT_UNLOCK = 414L; public const long LOC_CASKOU_PARK_HAT_UNLOCK = 415L; public const long LOC_LOOPY_LAGOON_HAT_UNLOCK = 416L; public const long LOC_WIN_RACE_AS_GARFIELD = 1001L; public const long LOC_WIN_RACE_AS_JON = 1002L; public const long LOC_WIN_RACE_AS_LIZ = 1003L; public const long LOC_WIN_RACE_AS_ODIE = 1004L; public const long LOC_WIN_RACE_AS_ARLENE = 1005L; public const long LOC_WIN_RACE_AS_NERMAL = 1006L; public const long LOC_WIN_RACE_AS_SQUEAK = 1007L; public const long LOC_WIN_RACE_AS_HARRY = 1008L; public const long LOC_WIN_RACE_WITH_FORMULA_ZZZZ = 1051L; public const long LOC_WIN_RACE_WITH_ABSTRACT_KART = 1052L; public const long LOC_WIN_RACE_WITH_MEDI_KART = 1053L; public const long LOC_WIN_RACE_WITH_WOOF_MOBILE = 1054L; public const long LOC_WIN_RACE_WITH_KISSY_KART = 1055L; public const long LOC_WIN_RACE_WITH_CUTIE_PIE_CAT = 1056L; public const long LOC_WIN_RACE_WITH_RAT_RACER = 1057L; public const long LOC_WIN_RACE_WITH_MUCK_MADNESS = 1058L; public const long LOC_FIND_ITEM_PIE = 1101L; public const long LOC_FIND_ITEM_HOMING_PIE = 1102L; public const long LOC_FIND_ITEM_DIAMOND = 1103L; public const long LOC_FIND_ITEM_MAGIC_WAND = 1104L; public const long LOC_FIND_ITEM_PERFUME = 1105L; public const long LOC_FIND_ITEM_LASAGNA = 1106L; public const long LOC_FIND_ITEM_UFO = 1107L; public const long LOC_FIND_ITEM_PILLOW = 1108L; public const long LOC_FIND_ITEM_SPRING = 1109L; public const long ITEM_PUZZLE_PIECE = 49L; public const long ITEM_PROGRESSIVE_COURSE_UNLOCK = 100L; public const long ITEM_COURSE_UNLOCK_CATZ_IN_THE_HOOD = 101L; public const long ITEM_COURSE_UNLOCK_CRAZY_DUNES = 102L; public const long ITEM_COURSE_UNLOCK_PALEROCK_LAKE = 103L; public const long ITEM_COURSE_UNLOCK_CITY_SLICKER = 104L; public const long ITEM_COURSE_UNLOCK_COUNTRY_BUMPKIN = 105L; public const long ITEM_COURSE_UNLOCK_SPOOKY_MANOR = 106L; public const long ITEM_COURSE_UNLOCK_MALLY_MARKET = 107L; public const long ITEM_COURSE_UNLOCK_VALLEY_OF_THE_KINGS = 108L; public const long ITEM_COURSE_UNLOCK_MISTY_FOR_ME = 109L; public const long ITEM_COURSE_UNLOCK_SNEAK_A_PEAK = 110L; public const long ITEM_COURSE_UNLOCK_BLAZING_OASIS = 111L; public const long ITEM_COURSE_UNLOCK_PASTACOSI_FACTORY = 112L; public const long ITEM_COURSE_UNLOCK_MYSTERIOUS_TEMPLE = 113L; public const long ITEM_COURSE_UNLOCK_PROHIBITED_SITE = 114L; public const long ITEM_COURSE_UNLOCK_CASKOU_PARK = 115L; public const long ITEM_COURSE_UNLOCK_LOOPY_LAGOON = 116L; public const long ITEM_PROGRESSIVE_CUP_UNLOCK = 200L; public const long ITEM_CUP_UNLOCK_LASAGNA = 201L; public const long ITEM_CUP_UNLOCK_PIZZA = 202L; public const long ITEM_CUP_UNLOCK_BURGER = 203L; public const long ITEM_CUP_UNLOCK_ICE_CREAM = 204L; public const long ITEM_CHARACTER_GARFIELD = 301L; public const long ITEM_CHARACTER_JON = 302L; public const long ITEM_CHARACTER_LIZ = 303L; public const long ITEM_CHARACTER_ODIE = 304L; public const long ITEM_CHARACTER_ARLENE = 305L; public const long ITEM_CHARACTER_NERMAL = 306L; public const long ITEM_CHARACTER_SQUEAK = 307L; public const long ITEM_CHARACTER_HARRY = 308L; public const long ITEM_KART_FORMULA_ZZZZ = 351L; public const long ITEM_KART_ABSTRACT_KART = 352L; public const long ITEM_KART_MEDI_KART = 353L; public const long ITEM_KART_WOOF_MOBILE = 354L; public const long ITEM_KART_KISSY_KART = 355L; public const long ITEM_KART_CUTIE_PIE_CAT = 356L; public const long ITEM_KART_RAT_RACER = 357L; public const long ITEM_KART_MUCK_MADNESS = 358L; public const long ITEM_UNLOCK_BEDDY_BYE_CAP = 421L; public const long ITEM_UNLOCK_WHIZZY_WIZARD = 422L; public const long ITEM_UNLOCK_TIC_TOQUE = 423L; public const long ITEM_UNLOCK_ELASTO_HAT = 424L; public const long ITEM_UNLOCK_CHEFS_SPECIAL = 425L; public const long ITEM_UNLOCK_CUTIE_PIE_CROWN = 426L; public const long ITEM_UNLOCK_VIKING_HELMET = 427L; public const long ITEM_UNLOCK_STINK_O_RAMA = 428L; public const long ITEM_UNLOCK_SPACE_BUBBLE = 429L; public const long ITEM_UNLOCK_PIZZAIOLO_HAT = 430L; public const long ITEM_UNLOCK_BUNNY_BAND = 431L; public const long ITEM_UNLOCK_JOE_MONTAGNA = 432L; public const long ITEM_UNLOCK_ARISTO_CATIC_BICORN = 433L; public const long ITEM_UNLOCK_TOUTANKHAMEOW = 434L; public const long ITEM_UNLOCK_APPRENTICE_SORCERER = 435L; public const long ITEM_UNLOCK_MULE_HEAD = 436L; public const long ITEM_UNLOCK_BOMBASTIC_SPOILER = 521L; public const long ITEM_UNLOCK_WHACKY_SPOILER = 522L; public const long ITEM_UNLOCK_SUPERFIT_SPOILER = 523L; public const long ITEM_UNLOCK_CYCLOBONE_SPOILER = 524L; public const long ITEM_UNLOCK_FOXY_SPOILER = 525L; public const long ITEM_UNLOCK_SHIMMERING_SPOILER = 526L; public const long ITEM_UNLOCK_HOLEY_MOLEY_SPOILER = 527L; public const long ITEM_UNLOCK_STAINED_SPOILER = 528L; public const long ITEM_PIE = 901L; public const long ITEM_HOMING_PIE = 902L; public const long ITEM_DIAMOND = 903L; public const long ITEM_MAGIC_WAND = 904L; public const long ITEM_PERFUME = 905L; public const long ITEM_LASAGNA = 906L; public const long ITEM_UFO = 907L; public const long ITEM_PILLOW = 908L; public const long ITEM_SPRING = 909L; public const long ITEM_RANDOM_ITEM_BOX_FILLER = 1000L; public const long ITEM_START_BOOST_HELPER_FILLER = 1001L; public const long ITEM_STRONGER_ITEM_BOXES_FILLER = 1002L; public const long ITEM_QUOTE_FILLER = 1003L; public const long ITEM_MIRROR_TRAP = 1500L; public const long ITEM_SLEEP_TRAP = 1501L; public const long ITEM_GRAYSCALE_TRAP = 1502L; public const long ITEM_BROKEN_DRIFT_TRAP = 1503L; public const long ITEM_BOUNCE_TRAP = 1504L; public const long GOAL_GRAND_PRIX = 0L; public const long GOAL_RACES = 1L; public const long GOAL_TIME_TRIALS = 2L; public const long GOAL_PUZZLE_PIECE = 3L; public const long OPTION_RANDOMIZE_RACES_CUPS = 0L; public const long OPTION_RANDOMIZE_RACES_RACES = 1L; public const long OPTION_RANDOMIZE_RACES_BOTH = 2L; public const long OPTION_TRAP_HANDLING_TIME = 0L; public const long OPTION_TRAP_HANDLING_RACE = 1L; public const long OPTION_TRAP_HANDLING_WIN = 2L; public const float TRAP_DISABLE_SECONDS = 60f; public static readonly string[] GARFIELD_QUOTES = new string[42] { "Love me, feed me, never leave me.", "I am hungry. Therefore I am.", "Oh no! I overslept! I’m late! For my nap.", "Eat every meal as though it were your last.", "The most active thing about me is my imagination.", "A little ego goes nowhere.", "I’ll rise, but I won’t shine.", "Once again I’m saved by the miracle of… lasagna!", "So much time, and so little... I need to do.", "I just need a little quality time with man's real best friend, television.", "Sure, Jon. I'll eat all your lasagna for you.", "I'll purr like a Ferrari. Make that a Jaguar.", "A smart cat knows just how far to go without crossing over the line", "Big fat hairy deal.", "I hate Mondays.", "We're bachelors, baby.", "Feed me.", "Eat your heart out.", "I'm not overweight. I'm undertall.", "I'm not known for my compassion.", "I love lasagna.", "Diet is 'die' but with a t.", "Christmas: It's not the giving. It's not the getting. It's the loving.", "It's not that I dislike you, I just don't like you near me.", "Show me a good mouser and I'll show you a cat with bad breath.", "Momma? Umm... I don't know, Penelope...", "Be still my beating heart.", "When I want in, I want in now!", "I hate birthdays.", "Love me, feed me, never leave me.", "Good morning? GOOD MORNING?! Jon, it's Monday! Monday is the armpit of the week! It's like a black hole in the calendar that just sucks all the joy out of your entire being!", "I know where you live!", "Hello, little hot dogs... wow...", "Whup! Um... did you hear something?", "Would you pass the ketchup?", "This game is K-rated. No adults unless accompanied by a kid.", "Hey, what do you know? I guess every cloud DOES have a silver lining.", "Hey Heathcliff, eat your heart out!", "The Real World! That's the change I need!", "You folks have this confused. I'M real, and YOU'RE animated.", "SEE YOU IN THE FUNNY PAPERS, ODIE!", "Hi, there. I'm Garfield. I'm a cat, and this is my cartoonist, Jon." }; public static string GetSceneNameFromTrackId(TrackId trackId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected I4, but got Unknown return (int)trackId switch { 4 => "E2C1", 12 => "E4C1", 8 => "E3C1", 0 => "E1C1", 9 => "E3C2", 5 => "E2C2", 1 => "E1C2", 13 => "E4C2", 2 => "E1C3", 10 => "E3C3", 14 => "E4C3", 6 => "E2C3", 15 => "E4C4", 3 => "E1C4", 7 => "E2C4", 11 => "E3C4", _ => null, }; } public static long GetRaceVictoryLoc(string startScene) { return startScene switch { "E2C1" => 1L, "E4C1" => 2L, "E3C1" => 3L, "E1C1" => 4L, "E3C2" => 5L, "E2C2" => 6L, "E1C2" => 7L, "E4C2" => 8L, "E1C3" => 9L, "E3C3" => 10L, "E4C3" => 11L, "E2C3" => 12L, "E4C4" => 13L, "E1C4" => 14L, "E2C4" => 15L, "E3C4" => 16L, _ => -1L, }; } public static List GetRaceVictoryCCLocs(string startScene, Difficulty difficulty) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Invalid comparison between I4 and Unknown List list = new List(); long raceVictoryLoc = GetRaceVictoryLoc(startScene); if (raceVictoryLoc == -1) { return list; } for (int i = 0; i <= (int)difficulty; i++) { list.Add(700 + (long)i * 20L + raceVictoryLoc); } return list; } public static long GetCupVictoryLoc(int cupId) { if (cupId < 0 || cupId > 3) { return -1L; } return 101L + (long)cupId; } public static List GetCupVictoryCCLocs(int cupId, Difficulty difficulty) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between I4 and Unknown List list = new List(); if (cupId < 0 || cupId > 3) { return list; } for (int i = 0; i <= (int)difficulty; i++) { list.Add(760 + (long)i * 10L + (cupId + 1)); } return list; } public static long GetPuzzlePieceLoc(string startScene, int puzzleIndex) { return startScene switch { "E2C1" => 201L + (long)puzzleIndex, "E4C1" => 204L + (long)puzzleIndex, "E3C1" => 207L + (long)puzzleIndex, "E1C1" => 210L + (long)puzzleIndex, "E3C2" => 213L + (long)puzzleIndex, "E2C2" => 216L + (long)puzzleIndex, "E1C2" => 219L + (long)puzzleIndex, "E4C2" => 222L + (long)puzzleIndex, "E1C3" => 225L + (long)puzzleIndex, "E3C3" => 228L + (long)puzzleIndex, "E4C3" => 231L + (long)puzzleIndex, "E2C3" => 234L + (long)puzzleIndex, "E4C4" => 237L + (long)puzzleIndex, "E1C4" => 240L + (long)puzzleIndex, "E2C4" => 243L + (long)puzzleIndex, "E3C4" => 246L + (long)puzzleIndex, _ => -1L, }; } public static long GetLapSanityLoc(string startScene, int lapIndex) { long num = startScene switch { "E2C1" => 500L, "E4C1" => 510L, "E3C1" => 520L, "E1C1" => 530L, "E3C2" => 540L, "E2C2" => 550L, "E1C2" => 560L, "E4C2" => 570L, "E1C3" => 580L, "E3C3" => 590L, "E4C3" => 600L, "E2C3" => 610L, "E4C4" => 620L, "E1C4" => 630L, "E2C4" => 640L, "E3C4" => 650L, _ => -1L, }; if (num == -1) { return -1L; } return num + lapIndex; } public static long GetTimeTrialLoc(string startScene, E_TimeTrialMedal medal) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Expected I4, but got Unknown int num = (int)medal; if (num < 1 || num > 4) { return -1L; } long raceVictoryLoc = GetRaceVictoryLoc(startScene); if (raceVictoryLoc == -1) { return -1L; } return 20L * (long)num + raceVictoryLoc; } public static List GetTimeTrialLocs(string startScene, E_TimeTrialMedal medal) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Invalid comparison between I4 and Unknown List list = new List(); for (int i = 1; i <= (int)medal; i++) { long timeTrialLoc = GetTimeTrialLoc(startScene, (E_TimeTrialMedal)i); if (timeTrialLoc != -1) { list.Add(timeTrialLoc); } } return list; } public static long GetHatLoc(string startScene) { long raceVictoryLoc = GetRaceVictoryLoc(startScene); if (raceVictoryLoc == -1) { return -1L; } return 400 + raceVictoryLoc; } public static long GetHatItemId(string hat) { switch (hat) { case "EgyptPriestHatN": case "EgyptPriestHatR": case "EgyptPriestHatU": return 423L; case "SleepingHatN": case "SleepingHatR": case "SleepingHatU": return 421L; case "PharaonHatN": case "PharaonHatR": case "PharaonHatU": return 434L; case "BeautyHatN": case "BeautyHatR": case "BeautyHatU": return 433L; case "PiratHatN": case "PiratHatR": case "PiratHatU": return 428L; case "FootballHelmetN": case "FootballHelmetR": case "FootballHelmetU": return 432L; case "ChickenHatN": case "ChickenHatR": case "ChickenHatU": return 424L; case "SpaceHelmetN": case "SpaceHelmetR": case "SpaceHelmetU": return 429L; case "CrownHatN": case "CrownHatR": case "CrownHatU": return 426L; case "PizzaioloHatN": case "PizzaioloHatR": case "PizzaioloHatU": return 430L; case "VikingHelmetN": case "VikingHelmetR": case "VikingHelmetU": return 427L; case "MagicHatN": case "MagicHatR": case "MagicHatU": return 422L; case "WizardHatN": case "WizardHatR": case "WizardHatU": return 435L; case "DunkeyHatN": case "DunkeyHatR": case "DunkeyHatU": return 436L; case "PastryHatN": case "PastryHatR": case "PastryHatU": return 425L; case "RabbitHatN": case "RabbitHatR": case "RabbitHatU": return 431L; default: return -1L; } } public static List GetSpoilerLocs(int cupId) { List list = new List(); if (cupId < 0 || cupId > 3) { return list; } list.Add(301L + (long)cupId); list.Add(311L + (long)cupId); return list; } public static long GetSpoilerItemId(string custom) { switch (custom) { case "KGC_ManiabilityN": case "KGC_ManiabilityR": case "KGC_ManiabilityU": return 521L; case "KJC_SpeedN": case "KJC_SpeedR": case "KJC_SpeedU": return 522L; case "KLC_AccelerationN": case "KLC_AccelerationR": case "KLC_AccelerationU": return 523L; case "KOC_AccelerationN": case "KOC_AccelerationR": case "KOC_AccelerationU": return 524L; case "KAC_AccelerationN": case "KAC_AccelerationR": case "KAC_AccelerationU": return 525L; case "KNC_AccelerationN": case "KNC_AccelerationR": case "KNC_AccelerationU": return 526L; case "KSC_ManiabilityN": case "KSC_ManiabilityR": case "KSC_ManiabilityU": return 527L; case "KHC_SpeedN": case "KHC_SpeedR": case "KHC_SpeedU": return 528L; default: return -1L; } } } public class ArchipelagoItemTracker { private static readonly ConcurrentDictionary receivedItems = new ConcurrentDictionary(); private static readonly ConcurrentDictionary checkedLocations = new ConcurrentDictionary(); private static int liveItemCursor; public static void Initialize() { Log.Message("Initializing Archipelago Item Tracker"); } public static void AddReceivedItem(long itemId) { receivedItems.AddOrUpdate(itemId, 1, (long _, int existing) => existing + 1); ArchipelagoFillerManager.TryReceiveFiller(itemId); } public static void ProcessLiveReceivedItems() { ArchipelagoClient aPClient = GarfieldKartAPMod.APClient; object obj; if (aPClient == null) { obj = null; } else { ArchipelagoSession session = aPClient.GetSession(); if (session == null) { obj = null; } else { IReceivedItemsHelper items = session.Items; obj = ((items != null) ? items.AllItemsReceived : null); } } ReadOnlyCollection readOnlyCollection = (ReadOnlyCollection)obj; if (readOnlyCollection != null) { while (liveItemCursor < readOnlyCollection.Count) { long itemId = readOnlyCollection[liveItemCursor].ItemId; AddReceivedItem(itemId); ArchipelagoTrapEffects.OnMidRaceReceive(itemId); liveItemCursor++; } } } public static bool HasItem(long itemId) { return receivedItems.ContainsKey(itemId); } public static int AmountOfItem(long itemId) { return receivedItems.GetValueOrDefault(itemId, 0); } public static void AddCheckedLocation(long locationId) { checkedLocations.TryAdd(locationId, 0); } public static bool HasLocation(long locationId) { return checkedLocations.ContainsKey(locationId); } public static int GetCheckedLocationCount() { return checkedLocations.Count; } public static void Clear() { receivedItems.Clear(); checkedLocations.Clear(); Log.Message("[AP] Cleared all received items and checked locations"); } public static void LoadFromServer() { try { ArchipelagoSession session = GarfieldKartAPMod.APClient.GetSession(); if (session == null) { return; } Clear(); List list = session.Items.AllItemsReceived?.ToList(); if (list != null) { Log.Message($"[AP] Loading {list.Count} items from server"); foreach (ItemInfo item in list) { Log.Message($"[AP] Item: {item.ItemName} (ID: {item.ItemId})"); receivedItems.AddOrUpdate(item.ItemId, 1, (long _, int existing) => existing + 1); } ArchipelagoFillerManager.LoadFillerFromReceivedItems(list); } IReceivedItemsHelper items = session.Items; liveItemCursor = ((items != null) ? items.Index : liveItemCursor); List list2 = session.Locations.AllLocationsChecked?.ToList(); if (list2 == null) { return; } Log.Message($"[AP] Loading {list2.Count} checked locations from server"); foreach (long item2 in list2) { Log.Message($"[AP] Location checked: {item2}"); checkedLocations.TryAdd(item2, 0); } } catch (Exception arg) { Log.Error($"[AP] LoadFromServer exception: {arg}"); } } public static void ResyncFromServer() { Log.Message("[AP] Resyncing Archipelago state from server"); LoadFromServer(); } public static List GetAvailableCups() { List list = new List(); for (int i = 0; i < 4; i++) { if (CanAccessCup(i)) { list.Add(i); } } return list; } public static bool HasRace(int raceId) { int cupId = raceId / 4; bool flag = ArchipelagoHelper.IsRacesRandomized(); bool flag2 = ArchipelagoHelper.IsCupsRandomized(); if (!flag && !flag2) { return true; } if (flag2 && !flag) { return HasCup(cupId); } return HasItem(101L + (long)raceId); } public static bool HasCup(int cupId) { bool flag = ArchipelagoHelper.IsCupsRandomized(); if (ArchipelagoHelper.IsRacesRandomized() && !flag) { return HasAllRacesInCup(cupId); } if (flag) { if (ArchipelagoHelper.IsProgressiveCupsEnabled()) { return AmountOfItem(200L) >= cupId; } return HasItem(201L + (long)cupId); } return true; } public static bool CanAccessCup(int cupId) { if (!HasCup(cupId)) { return false; } return HasAllRacesInCup(cupId); } public static bool HasRaceInCup(int cupId) { int num = cupId * 4; for (int i = 0; i < 4; i++) { if (HasRace(num + i)) { return true; } } return false; } public static bool HasAllRacesInCup(int cupId) { int num = cupId * 4; for (int i = 0; i < 4; i++) { if (!HasRace(num + i)) { return false; } } return true; } public static int GetPuzzlePieceCount(string startScene) { long puzzlePieceLoc = ArchipelagoConstants.GetPuzzlePieceLoc(startScene, 0); if (puzzlePieceLoc == -1) { return 0; } int num = 0; for (int i = 0; i < 3; i++) { if (HasLocation(puzzlePieceLoc + i)) { num++; } } return num; } public static int GetOverallPuzzlePieceCount() { return AmountOfItem(49L); } public static bool HasBonusAvailable(BonusCategory bonus) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected I4, but got Unknown if (!ArchipelagoHelper.IsItemRandomizerEnabled()) { return true; } return (bonus - 1) switch { 0 => HasItem(901L), 1 => HasItem(902L), 3 => HasItem(906L), 2 => HasItem(909L), 4 => HasItem(903L), 5 => HasItem(907L), 6 => HasItem(908L), 7 => HasItem(905L), 8 => HasItem(904L), _ => true, }; } public static void LogAllReceivedItems() { int num = receivedItems.Sum((KeyValuePair kv) => kv.Value); Log.Message($"[AP Debug] === All Received Items ({num} total entries) ==="); foreach (KeyValuePair item in receivedItems.OrderBy((KeyValuePair kv) => kv.Key)) { Log.Message($"[AP Debug] Item ID: {item.Key} Count: {item.Value}"); } } public static void LogAllCheckedLocations() { Log.Message($"[AP Debug] === All Checked Locations ({checkedLocations.Count} total) ==="); foreach (long item in checkedLocations.Keys.OrderBy((long x) => x)) { Log.Message($"[AP Debug] Location ID: {item}"); } } } public class ConnectionUI : MonoBehaviour { private bool showUI = true; private bool m_paused; private string hostname = "archipelago.gg"; private string slotName = ""; private string port = "38281"; private string password = ""; private string statusMessage = ""; private Rect windowRect = new Rect((float)(Screen.width / 2 - 300), (float)(Screen.height / 2 - 250), 800f, 700f); private ArchipelagoClient apClient; private bool originalCursorVisible; private CursorLockMode originalLockMode; private bool NeedsConnection => !(apClient?.IsConnected ?? false); public void Initialize(ArchipelagoClient client) { //IL_00d9: 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) apClient = client; apClient.OnConnected += delegate { statusMessage = "Connected successfully!"; }; apClient.OnConnectionFailed += delegate(string error) { statusMessage = "Failed: " + error; }; apClient.OnDisconnected += delegate { statusMessage = "Disconnected"; }; apClient.OnConnected += delegate { FileWriter fileWriter = Object.FindObjectOfType(); if (!((Object)(object)fileWriter == (Object)null)) { int.TryParse(port, out var result); fileWriter.WriteLastConnection(hostname, result, slotName, password); } }; (string, string, string, string) tuple = FileWriter.ReadLastConnection(); if (!string.IsNullOrEmpty(tuple.Item1)) { (hostname, _, _, _) = tuple; } if (!string.IsNullOrEmpty(tuple.Item2)) { port = tuple.Item2; } if (!string.IsNullOrEmpty(tuple.Item3)) { slotName = tuple.Item3; } if (!string.IsNullOrEmpty(tuple.Item4)) { password = tuple.Item4; } originalCursorVisible = Cursor.visible; originalLockMode = Cursor.lockState; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } public void ToggleUI() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) showUI = !showUI; if (showUI) { originalCursorVisible = Cursor.visible; originalLockMode = Cursor.lockState; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else { Cursor.visible = originalCursorVisible; Cursor.lockState = originalLockMode; } } public void ForceShow() { Time.timeScale = 0f; m_paused = true; showUI = true; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } private void Update() { bool needsConnection = NeedsConnection; if (needsConnection && !m_paused) { Time.timeScale = 0f; m_paused = true; showUI = true; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else if (!needsConnection && m_paused) { Time.timeScale = 1f; m_paused = false; } if (!needsConnection && Input.GetKeyDown((KeyCode)282)) { ToggleUI(); } } private void OnGUI() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (showUI || NeedsConnection) { GUI.skin.label.fontSize = 24; GUI.skin.button.fontSize = 24; GUI.skin.textField.fontSize = 24; Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = new Color(1f, 0.5f, 0f); windowRect = GUI.Window(0, windowRect, new WindowFunction(DrawWindow), "Archipelago Connection"); GUI.backgroundColor = backgroundColor; } } private void DrawWindow(int windowID) { GUILayout.BeginVertical(Array.Empty()); GUILayout.Label("Press F1 to show this menu while connected ingame.", Array.Empty()); GUILayout.Space(15f); GUILayout.Label("Hostname:", Array.Empty()); hostname = GUILayout.TextField(hostname, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }); GUILayout.Space(10f); GUILayout.Label("Port:", Array.Empty()); port = GUILayout.TextField(port, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }); GUILayout.Space(10f); GUILayout.Label("Slot Name:", Array.Empty()); slotName = GUILayout.TextField(slotName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }); GUILayout.Space(10f); GUILayout.Label("Password (optional):", Array.Empty()); password = GUILayout.PasswordField(password, '*', (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) }); GUILayout.Space(15f); ArchipelagoClient archipelagoClient = apClient; if (archipelagoClient != null && archipelagoClient.IsConnected) { if (GUILayout.Button("Disconnect", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) })) { apClient.Disconnect(); } } else if (GUILayout.Button("Connect", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) })) { int result; if (string.IsNullOrEmpty(slotName)) { statusMessage = "Please enter a slot name!"; } else if (int.TryParse(port, out result)) { statusMessage = "Connecting..."; apClient?.Connect(hostname, result, slotName, password); } else { statusMessage = "Invalid port number!"; } } GUILayout.Space(15f); if (!string.IsNullOrEmpty(statusMessage)) { GUILayout.Label("Status: " + statusMessage, Array.Empty()); } GUILayout.EndVertical(); GUI.DragWindow(); } } public class FileWriter : MonoBehaviour { private const string LastConnectionFileName = "last_connection.txt"; public void WriteLastConnection(string host, int port, string slotName, string password) { try { string path = Application.persistentDataPath + "/last_connection.txt"; List contents = new List { host ?? "", port.ToString(), slotName ?? "", password ?? "" }; File.WriteAllLines(path, contents); } catch (Exception ex) { Debug.LogError((object)("Failed to write last connection info: " + ex.Message)); } } public static (string host, string port, string slotName, string password) ReadLastConnection() { try { string path = Application.persistentDataPath + "/last_connection.txt"; if (!File.Exists(path)) { return (host: null, port: null, slotName: null, password: null); } string[] array = File.ReadAllLines(path); string item = ((array.Length != 0) ? array[0] : null); string item2 = ((array.Length > 1) ? array[1] : null); string item3 = ((array.Length > 2) ? array[2] : null); string item4 = ((array.Length > 3) ? array[3] : null); return (host: item, port: item2, slotName: item3, password: item4); } catch (Exception ex) { Debug.LogError((object)("Failed to read last connection info: " + ex.Message)); return (host: null, port: null, slotName: null, password: null); } } } public enum ItemManiaMode { UseYaml, On, Off } public enum DeathLinkMode { UseYaml, On, Off } [BepInPlugin("Jeffdev.GarfieldKartAPMod", "GarfieldKartAPMod", "1.0.2")] public class GarfieldKartAPMod : BaseUnityPlugin { private const string PluginGuid = "Jeffdev.GarfieldKartAPMod"; private const string PluginAuthor = "Jeffdev"; private const string PluginName = "GarfieldKartAPMod"; private const string PluginVersion = "1.0.2"; public static ConfigEntry notificationTime; public static ConfigEntry lapCountOverride; public static ConfigEntry showNotifications; public static ConfigEntry showOnlyRelevantNotifications; public static ConfigEntry disableStatRandomization; public static ConfigEntry lapSanityPlacementRequirement; public static ConfigEntry strictCpuItems; public static ConfigEntry itemManiaMode; public static ConfigEntry deathLink; private Harmony harmony; public static Dictionary sessionSlotData; private static GameObject uiObject; private static bool uiCreated; private static NotificationDisplay notificationDisplay; private FileWriter fileWriter; public static ArchipelagoClient APClient { get; private set; } public void Awake() { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown notificationTime = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Server Message On-Screen Time", 3, "How long to show archipelago server messages and checks on the screen, in seconds."); lapCountOverride = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Lap Count Override", 0, "Override the lap count for races. Set to 0 to use the lap count from Archipelago slot data."); showNotifications = ((BaseUnityPlugin)this).Config.Bind("Display", "Show Log Messages", true, "Show Archipelago server log messages at the top of the screen."); showOnlyRelevantNotifications = ((BaseUnityPlugin)this).Config.Bind("Display", "Show Only Relevant Messages", true, "Only show log messages relevant to you (items you send or receive, your hints). Other message types still appear."); disableStatRandomization = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Disable Stat Randomization", false, "Disable kart and character stat randomization, even if the Archipelago slot has it enabled."); lapSanityPlacementRequirement = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Lap Sanity Placement Requirement", 1, new ConfigDescription("The placement you must be in (or better) when completing a lap for it to count as a lap sanity check. 1 = 1st place only, 8 = any placement.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); strictCpuItems = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Strict CPU Items", false, "CPU racers can only use items you have received from Archipelago, instead of being able to use any item."); itemManiaMode = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Item Mania", ItemManiaMode.UseYaml, "Control Item Mania (CPUs hold 3 items and fire them rapidly). UseYaml follows the Archipelago slot setting; On/Off force it regardless of the yaml."); deathLink = ((BaseUnityPlugin)this).Config.Bind("Archipelago", "Death Link", DeathLinkMode.UseYaml, "Control DeathLink (falling off the track sends a death to other DeathLink players, and their deaths force your kart to respawn). UseYaml follows the Archipelago slot setting; On/Off force it regardless of the yaml."); deathLink.SettingChanged += delegate { DeathLinkManager.ApplyConfig(); }; InitializeLogging(); InitializeAssemblyResolution(); InitializeComponents(); ApplyPatches(); Log.Info("GarfieldKartAPMod loaded successfully!"); } private void InitializeLogging() { Log.Init(((BaseUnityPlugin)this).Logger); } private void InitializeAssemblyResolution() { ForceLoadNewtonsoftJson(); AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; CheckSystemNumericsAvailability(); } private void ForceLoadNewtonsoftJson() { try { Type typeFromHandle = typeof(JsonConvert); Log.Message($"Loaded Newtonsoft.Json version: {typeFromHandle.Assembly.GetName().Version}"); } catch (Exception ex) { Log.Error("Failed to preload Newtonsoft.Json: " + ex.Message); } } private void CheckSystemNumericsAvailability() { try { Type type = Type.GetType("System.Numerics.BigInteger, System.Numerics"); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"BigInteger available: {type != null}"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("BigInteger check failed: " + ex.Message)); } } private void InitializeComponents() { UITextureSwapper.Initialize(); fileWriter = ((Component)this).gameObject.AddComponent(); APClient = new ArchipelagoClient(); APClient.OnConnected += OnArchipelagoConnected; APClient.OnDisconnected += OnArchipelagoDisconnected; CreateUI(); } private void ApplyPatches() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown harmony = new Harmony("Jeffdev.GarfieldKartAPMod"); harmony.PatchAll(Assembly.GetExecutingAssembly()); } public void Update() { DeathLinkManager.ProcessPendingDeath(); TickActiveTrapTimers(); if (ArchipelagoHelper.IsConnectedAndEnabled) { ArchipelagoItemTracker.ProcessLiveReceivedItems(); ArchipelagoFillerEffects.Update(); ArchipelagoTrapEffects.Update(); } if (APClient != null && APClient.HasPendingNotifications()) { string message = APClient.DequeuePendingNotification(); if (showNotifications.Value) { notificationDisplay.ShowNotification(message); } } } private static void TickActiveTrapTimers() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 if (!ArchipelagoHelper.IsConnectedAndEnabled) { return; } GameManager instance = Singleton.Instance; GameMode obj = ((instance != null) ? instance.GameMode : null); InGameGameMode val = (InGameGameMode)(object)((obj is InGameGameMode) ? obj : null); if (val == null || !val.HasRaceStarted || (int)Singleton.Instance.GameModeType == 4) { return; } foreach (Driver value in ((GameMode)val).Drivers.Values) { if (value.IsHuman && value.IsLocal) { if (!((Object)(object)value.Kart == (Object)null) && !((RcVehicle)value.Kart).IsRaceEnded()) { ArchipelagoFillerManager.TickTrapTimers(Time.deltaTime); } break; } } } private void OnArchipelagoConnected() { Log.Message("Connected to Archipelago - loading items"); uiObject.GetComponent().ToggleUI(); } private void OnArchipelagoDisconnected() { Log.Message("Disconnected from Archipelago"); uiObject.GetComponent().ForceShow(); } private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) { if (new AssemblyName(args.Name).Name != "Newtonsoft.Json") { return null; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly.GetName().Name != "Newtonsoft.Json")) { Log.Message($"Resolved Newtonsoft.Json to version {assembly.GetName().Version}"); return assembly; } } return null; } public static void CreateUI() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!uiCreated) { Log.Message("Creating Archipelago UI..."); uiObject = new GameObject("ArchipelagoUI"); Object.DontDestroyOnLoad((Object)(object)uiObject); uiObject.AddComponent().Initialize(APClient); notificationDisplay = uiObject.AddComponent(); notificationDisplay.Initialize(); uiCreated = true; } } public void OnDestroy() { APClient?.Disconnect(); if ((Object)(object)uiObject != (Object)null) { Object.Destroy((Object)(object)uiObject); } Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } public static class DeathLinkManager { [CompilerGenerated] private static class <>O { public static DeathLinkReceivedHandler <0>__OnDeathLinkReceived; } private static DeathLinkService service; private static volatile bool deathPending; private static string pendingSource; private static string pendingCause; private static float suppressSendUntil; public static void OnSessionConnected(ArchipelagoSession session) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown service = DeathLinkProvider.CreateDeathLinkService(session); DeathLinkService obj = service; object obj2 = <>O.<0>__OnDeathLinkReceived; if (obj2 == null) { DeathLinkReceivedHandler val = OnDeathLinkReceived; <>O.<0>__OnDeathLinkReceived = val; obj2 = (object)val; } obj.OnDeathLinkReceived += (DeathLinkReceivedHandler)obj2; ApplyConfig(); } public static void OnDisconnected() { service = null; deathPending = false; } public static void ApplyConfig() { if (service != null) { if (ArchipelagoHelper.IsDeathLinkEnabled()) { service.EnableDeathLink(); Log.Message("DeathLink enabled"); } else { service.DisableDeathLink(); Log.Message("DeathLink disabled"); } } } private static void OnDeathLinkReceived(DeathLink deathLink) { pendingSource = deathLink.Source; pendingCause = deathLink.Cause; deathPending = true; } public static void ProcessPendingDeath() { if (!deathPending) { return; } if (!ArchipelagoHelper.IsDeathLinkEnabled()) { deathPending = false; return; } Kart val = FindLocalPlayerKart(); if ((Object)(object)val == (Object)null) { deathPending = false; Log.Message("DeathLink from " + pendingSource + " ignored (not in a race)"); } else if (!ArchipelagoHelper.IsBeingAbductedByUfo(val)) { deathPending = false; string text = (string.IsNullOrEmpty(pendingCause) ? ("DeathLink from " + pendingSource) : pendingCause); Log.Message("DeathLink received: " + text); GarfieldKartAPMod.APClient?.QueueNotification("DeathLink: " + text); suppressSendUntil = Time.realtimeSinceStartup + 3f; ((RcVehicle)val).ForceRespawn(); } } public static void OnLocalPlayerFell() { if (!(Time.realtimeSinceStartup < suppressSendUntil)) { SendDeath(SlotName() + " fell off the track"); } } public static void SendDebugDeath() { SendDeath(SlotName() + " pressed the death button"); } public static void SimulateReceivedDeath() { pendingSource = "Debug"; pendingCause = "Simulated DeathLink"; deathPending = true; } private static void SendDeath(string cause) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (service == null || !ArchipelagoHelper.IsDeathLinkEnabled()) { return; } try { service.SendDeathLink(new DeathLink(SlotName(), cause)); Log.Message("Sent DeathLink: " + cause); } catch (Exception ex) { Log.Error("Failed to send DeathLink: " + ex.Message); } } private static string SlotName() { return GarfieldKartAPMod.APClient?.SlotName ?? "Player"; } private static Kart FindLocalPlayerKart() { Driver[] array = Object.FindObjectsOfType(); foreach (Driver val in array) { if (val.IsHuman && val.IsLocal && (Object)(object)val.Kart != (Object)null) { return val.Kart; } } return null; } } internal static class Log { private static ManualLogSource _logSource; internal static void Init(ManualLogSource logSource) { _logSource = logSource; } internal static void Debug(object data) { _logSource.LogDebug(data); } internal static void Error(object data) { _logSource.LogError(data); } internal static void Fatal(object data) { _logSource.LogFatal(data); } internal static void Info(object data) { _logSource.LogInfo(data); } internal static void Message(object data) { _logSource.LogMessage(data); } internal static void Warning(object data) { _logSource.LogWarning(data); } } public class NotificationDisplay : MonoBehaviour { private static readonly Vector2 ReferenceResolution = new Vector2(1920f, 1080f); private TextMeshProUGUI notificationText; private TextMeshProUGUI shadowText; private readonly Queue notificationQueue = new Queue(); private bool isDisplaying; public void Initialize() { //IL_002f: 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) //IL_0055: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b8: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) Canvas obj = ((Component)this).gameObject.AddComponent(); obj.renderMode = (RenderMode)0; obj.sortingOrder = 1000; CanvasScaler obj2 = ((Component)this).gameObject.AddComponent(); obj2.uiScaleMode = (ScaleMode)1; obj2.referenceResolution = ReferenceResolution; obj2.screenMatchMode = (ScreenMatchMode)0; obj2.matchWidthOrHeight = 1f; GameObject val = new GameObject("NotificationShadow"); val.transform.SetParent(((Component)this).transform); shadowText = val.AddComponent(); ConfigureText(shadowText); ((Graphic)shadowText).color = Color.black; ((Component)shadowText).GetComponent().anchoredPosition = new Vector2(2f, -22f); GameObject val2 = new GameObject("NotificationText"); val2.transform.SetParent(((Component)this).transform); notificationText = val2.AddComponent(); ConfigureText(notificationText); ((Graphic)notificationText).color = Color.white; ((TMP_Text)notificationText).text = ""; ((TMP_Text)shadowText).text = ""; } private void ConfigureText(TextMeshProUGUI text) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) ((TMP_Text)text).fontSize = 24f; ((TMP_Text)text).alignment = (TextAlignmentOptions)258; ((TMP_Text)text).autoSizeTextContainer = true; ((TMP_Text)text).enableWordWrapping = true; ((TMP_Text)text).richText = true; RectTransform component = ((Component)text).GetComponent(); component.anchorMin = new Vector2(0f, 1f); component.anchorMax = new Vector2(1f, 1f); component.pivot = new Vector2(0.5f, 1f); component.anchoredPosition = new Vector2(0f, -20f); component.sizeDelta = new Vector2(-40f, 100f); } public void ShowNotification(string message) { if (!message.Contains("Now that you are connected") && !message.Contains("Warning: your client does not")) { notificationQueue.Enqueue(message); if (!isDisplaying) { ((MonoBehaviour)this).StartCoroutine(DisplayNextNotification()); } } } private IEnumerator DisplayNextNotification() { isDisplaying = true; while (notificationQueue.Count > 0) { string text = notificationQueue.Dequeue(); ((TMP_Text)notificationText).text = text; ((TMP_Text)shadowText).text = StripColorTags(text); yield return (object)new WaitForSeconds((float)GarfieldKartAPMod.notificationTime.Value); } ((TMP_Text)notificationText).text = ""; ((TMP_Text)shadowText).text = ""; isDisplaying = false; } private string StripColorTags(string input) { if (string.IsNullOrEmpty(input)) { return input; } string text = input; while (text.Contains("", num); if (num2 == -1) { break; } text = text.Remove(num, num2 - num + 1); } return text.Replace("", ""); } } [Serializable] public class SlotDataException : ApplicationException { public SlotDataException() { } public SlotDataException(string message) : base(message) { } public SlotDataException(string message, Exception innerException) : base(message, innerException) { } } public static class UITextureSwapper { public static string spriteFolder = "Resources/Sprites"; private static Sprite baseArchipelagoSprite; public static Sprite puzzlePieceFilledSprite; public static Sprite puzzlePieceEmptySprite; public static Sprite mainMenuLogoSprite; public static Sprite galleryIconSprite; private static bool initialized; private static bool hasSwappedThisMenu; private const float GalleryIconScale = 0.7f; private static readonly Vector2 GalleryIconNudge = new Vector2(10f, 0f); public static void Initialize() { if (!initialized) { Log.Message("Initializing UI texture swapper..."); if (TryLoadSprite("garfkart_ap_puzzle_filled.png", out baseArchipelagoSprite) && TryLoadSprite("garfkart_ap_puzzle_filled.png", out puzzlePieceFilledSprite) && TryLoadSprite("garfkart_ap_puzzle_empty.png", out puzzlePieceEmptySprite) && TryLoadSprite("logo_garfAP_complete.png", out mainMenuLogoSprite) && TryLoadSprite("garfkart_ap_icon.png", out galleryIconSprite)) { initialized = true; } } } private static bool TryLoadSprite(string path, out Sprite targetSprite) { //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) _ = typeof(UITextureSwapper).Namespace; targetSprite = null; try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); string text = null; string[] array = manifestResourceNames; foreach (string text2 in array) { if (!(text2 != path) || text2.EndsWith("." + path)) { if (text != null) { throw new ApplicationException("Duplicate resource name found, unable to load the correct texture: " + text2); } text = text2; } } if (text == null) { Log.Warning("Couldn't find " + path + " in embedded resources, loading default sprite instead."); targetSprite = CreateDefaultSprite(); return false; } Log.Message("Loading embedded resource: " + text); using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { Log.Error("Failed to load " + path + " for unknown reasons :)"); targetSprite = CreateDefaultSprite(); return false; } byte[] array2 = new byte[stream.Length]; stream.Read(array2, 0, (int)stream.Length); Texture2D val = new Texture2D(2, 2); ImageConversion.LoadImage(val, array2); val.Apply(); targetSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); Log.Message($"Successfully loaded {path} ({((Texture)val).width}x{((Texture)val).height})"); return true; } catch (Exception ex) { Log.Error("Failed to load " + path + ": " + ex.Message + "\n" + ex.StackTrace); targetSprite = CreateDefaultSprite(); return false; } } private static Sprite CreateDefaultSprite() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64); Color[] array = (Color[])(object)new Color[4096]; for (int i = 0; i < array.Length; i++) { array[i] = Color.red; } val.SetPixels(array); val.Apply(); Log.Message("Created default red placeholder sprite"); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f); } public static void ResetSwapFlag() { hasSwappedThisMenu = false; } public static void SwapMainMenuLogo(GameObject root) { if ((Object)(object)mainMenuLogoSprite == (Object)null) { Log.Error("Cannot swap - main menu logo sprite not loaded"); return; } try { int num = 0; bool flag = false; Image[] componentsInChildren = root.GetComponentsInChildren(true); foreach (Image val in componentsInChildren) { if ((Object)(object)val.sprite == (Object)null) { continue; } if ((Object)(object)val.sprite == (Object)(object)mainMenuLogoSprite) { flag = true; continue; } string text = ((Object)val.sprite).name.ToLower(); string text2 = ((Object)((Component)val).gameObject).name.ToLower(); if (text.Contains("titlelogo") || text2.Contains("titlelogo")) { val.sprite = mainMenuLogoSprite; val.preserveAspect = true; num++; Log.Message("Swapped main menu logo on: " + ((Object)((Component)val).gameObject).name); } } if (num == 0 && !flag) { Log.Warning("No main menu logo image found to swap"); } } catch (Exception ex) { Log.Error("Failed to swap main menu logo: " + ex.Message); } } public static void SwapGalleryButtonIcon(GameObject galleryButton) { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)galleryButton == (Object)null) { return; } if ((Object)(object)galleryIconSprite == (Object)null) { Log.Error("Cannot swap - AP gallery icon sprite not loaded"); return; } try { Button component = galleryButton.GetComponent