using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Rendering; using cakeslice; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("Sail-a-dex")] [assembly: AssemblyDescription("https://github.com/bryon82/SailwindSail-a-dex")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("raddude")] [assembly: AssemblyProduct("Sail-a-dex")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("165a01b3-48da-400d-a25f-d6d01b2b3120")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.0.0.0")] [module: UnverifiableCode] namespace sailadex; internal class PassageDude { public class FerryTravelPatches { [HarmonyPostfix] public static void TeleportPlayerPatch() { if (Configs.statsUIEnabled.Value) { StatsUI.Instance.PlayerTeleported(); } } } public static void PatchMod() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown Type type = AccessTools.TypeByName("FerryTravel"); MethodInfo methodInfo = AccessTools.Method(type, "TeleportPlayer", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(FerryTravelPatches), "TeleportPlayerPatch", (Type[])null, (Type[])null); SAD_Plugin.HarmonyInstance.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } internal class REConfigs { internal static bool IsSeaLifeModEnabled => Get("IsSeaLifeModEnabled"); internal static bool IsFlotsamEnabled => Get("IsFlotsamEnabled"); internal static bool IsDenseFogEnabled => Get("IsDenseFogEnabled"); internal static bool IsFishingBonanzaEnabled => Get("IsFishingBonanzaEnabled"); internal static bool IsIntenseStormEnabled => Get("IsIntenseStormEnabled"); private static bool Get([CallerMemberName] string property = "") { return SAD_Plugin.RE_PluginInstance.GetStaticProperty(property); } } internal class EventPatches { [HarmonyPatch(typeof(FishingRodFish))] private class FishingRodFishPatches { [HarmonyPrefix] [HarmonyPatch("CollectFish")] public static void CollectFishPatch(GameObject ___currentFish) { if (Configs.fishCaughtUIEnabled.Value) { FishCaughtUI.Instance.RegisterCatch(___currentFish); } } } [HarmonyPatch(typeof(IslandMarketWarehouseArea))] private class IslandMarketWarehouseAreaPatches { [HarmonyPostfix] [HarmonyPatch("OnTriggerEnter")] public static void OnTriggerEnterPatch(IslandMarket ___market, Collider other) { if (Configs.portsVisitedUIEnabled.Value && ((Component)other).CompareTag("Player")) { PortsVisitedUI.Instance.RegisterVisit(___market.GetPortName()); } if (Configs.statsUIEnabled.Value && ((Component)other).CompareTag("Player")) { StatsUI.Instance.IncrementPortVisited(___market.GetPortName()); } } } [HarmonyPatch(typeof(ShipItem))] private class ShipItemPatches { [HarmonyPostfix] [HarmonyPatch("EnterBoat")] public static void EnterBoatPatch() { if (Configs.statsUIEnabled.Value && GameState.playing) { StatsUI.Instance.RegisterCurrentMass(); } } [HarmonyPostfix] [HarmonyPatch("ExitBoat")] public static void ExitBoatPatch() { if (Configs.statsUIEnabled.Value && GameState.playing) { StatsUI.Instance.RegisterCurrentMass(); } } } [HarmonyPatch(typeof(PickupableBoatMooringRope))] private class PickupableBoatMooringRopePatches { [HarmonyPrefix] [HarmonyPatch("OnPickup")] public static void OnPickupPrePatch(Rigidbody ___boatRigidbody, out string __state) { __state = (from r in ((Component)___boatRigidbody).gameObject.GetComponent().ropes where (Object)(object)r.GetPrivateField("mooredToSpring") != (Object)null select ((Object)((Component)r.GetPrivateField("mooredToSpring")).transform.parent).name).FirstOrDefault(); } [HarmonyPostfix] [HarmonyPatch("OnPickup")] public static void OnPickupPatch(Rigidbody ___boatRigidbody, string __state) { if (Configs.statsUIEnabled.Value && !GameState.currentlyLoading && GameState.playing && !((Component)___boatRigidbody).gameObject.GetComponent().AnyRopeMoored()) { SAD_Plugin.LogDebug($"Unmoor from {__state} Day: {GameState.day} Time: {Sun.sun.globalTime}"); StatsUI.Instance.RegisterUnderway(__state); } } [HarmonyPostfix] [HarmonyPatch("MoorTo")] public static void MoorToPatch(Rigidbody ___boatRigidbody) { if (!Configs.statsUIEnabled.Value || GameState.currentlyLoading || !GameState.playing) { return; } if (!((Object)(object)((Component)___boatRigidbody).transform == (Object)(object)GameState.lastBoat)) { Transform transform = ((Component)___boatRigidbody).transform; Transform currentBoat = GameState.currentBoat; if (!((Object)(object)transform == (Object)(object)((currentBoat != null) ? currentBoat.parent : null))) { return; } } if (((Component)___boatRigidbody).gameObject.GetComponent().AnyRopeMoored()) { string text = (from r in ((Component)___boatRigidbody).gameObject.GetComponent().ropes where (Object)(object)r.GetPrivateField("mooredToSpring") != (Object)null select ((Object)((Component)r.GetPrivateField("mooredToSpring")).transform.parent).name).FirstOrDefault(); SAD_Plugin.LogDebug($"Moored at: {text} Day: {GameState.day} Time: {Sun.sun.globalTime} "); StatsUI.Instance.RegisterMoored(text); StatsUI.Instance.UpdateMilesText(); } } } [HarmonyPatch(typeof(ShipItemBottle))] private class ShipItemBottlePatches { [HarmonyPostfix] [HarmonyPatch("Drink")] public static void DrinkPatch(float ___health) { if (Configs.statsUIEnabled.Value && ___health > 0f) { StatsUI.Instance.IncrementIntStat("DrinksTaken"); } } } [HarmonyPatch(typeof(ShipItemFood))] private class ShipItemFoodPatches { [HarmonyPrefix] [HarmonyPatch("EatFood")] public static void EatFoodPatch() { if (Configs.statsUIEnabled.Value && !(PlayerNeeds.instance.eatCooldown > 0f)) { StatsUI.Instance.IncrementIntStat("FoodsEaten"); } } } [HarmonyPatch(typeof(ShipItemPipe))] private class ShipItemPipePatches { [HarmonyPrefix] [HarmonyPatch("StopSmoking")] public static void StopSmokingPatch(float ___currentInhaleDuration) { if (Configs.statsUIEnabled.Value && ___currentInhaleDuration > 0f) { StatsUI.Instance.IncrementIntStat("TimesSmoked"); } } } [HarmonyPatch(typeof(Sleep))] private class SleepPatches { [HarmonyPostfix] [HarmonyPatch("EnterBed")] public static void EnterBedPatch() { if (Configs.statsUIEnabled.Value) { StatsUI.Instance.IncrementIntStat("TimesSlept"); if (Configs.updateMilesSailed.Value == "sleep") { StatsUI.Instance.UpdateMilesText(); } } } } [HarmonyPatch(typeof(PlayerMissions))] private class PlayerMissionsPatches { [HarmonyPostfix] [HarmonyPatch("CompleteMission")] public static void CompleteMissionPatch() { if (Configs.statsUIEnabled.Value) { StatsUI.Instance.IncrementIntStat("MissionsCompleted"); } } } [HarmonyPatch(typeof(Port))] private class PortPatches { [HarmonyPostfix] [HarmonyPatch("Update")] public static void UpdatePatch(bool ___teleportPlayer) { if (Configs.statsUIEnabled.Value && ___teleportPlayer) { StatsUI.Instance.PlayerTeleported(); } } } [HarmonyPatch(typeof(BoatMass))] private class BoatMassPatches { [HarmonyPostfix] [HarmonyPatch("Update")] public static void UpdatePatch() { if (Configs.statsUIEnabled.Value && (Object)(object)GameState.currentBoat != (Object)null) { StatsUI.Instance.TrackDistance(); } } [HarmonyPostfix] [HarmonyPatch("UpdateMass")] public static void UpdateMassPatch(Rigidbody ___body) { if (Configs.statsUIEnabled.Value && (Object)(object)GameState.currentBoat != (Object)null) { StatsUI.Instance.RegisterTotalMass(___body.mass); } } } [HarmonyPatch(typeof(WeatherStorms))] private class WeatherStormPatches { [HarmonyPostfix] [HarmonyPatch("GetNormalizedDistance")] public static void GetNormalizedDistancePatch(float __result) { if (GameState.playing) { if (Configs.statsUIEnabled.Value && (Object)(object)GameState.currentBoat != (Object)null && StatsUI.Instance.IsUnderway && __result <= 0.33f) { StatsUI.Instance.IncrementStormsWeathered(); } if (__result > 0.66f) { StatsUI.Instance.ClearLastStorm(); } } } } } internal class ModDataPatches { [HarmonyPatch(typeof(SaveLoadManager))] private class SaveLoadManagerPatches { [HarmonyPrefix] [HarmonyPatch("SaveModData")] public static void SaveModData() { FishCaughtUI.Instance.SaveFishCaughtUI(); PortsVisitedUI.Instance.SavePortsVisitedUI(); StatsUI.Instance.SaveStatsUI(); } [HarmonyPrefix] [HarmonyPatch("LoadModData")] public static void LoadModData() { FishCaughtUI.Instance.LoadFishCaughtUI(); PortsVisitedUI.Instance.LoadPortsVisitedUI(); StatsUI.Instance.LoadStatsUI(); } } } public class FishCaughtUI : MonoBehaviour { public TextMesh[] _fishNameTMs; public TextMesh[] _caughtCountTMs; public Dictionary _fishBadgeGOs; public Dictionary _caughtFish; public Dictionary _fishBadges; private static readonly int[] FISH_BADGE_AMOUNTS = new int[3] { 25, 50, 100 }; private static readonly int[] TOTAL_FISH_BADGE_AMOUNTS = new int[3] { 50, 250, 500 }; public static readonly string[] FishNames = new string[12] { "templefish", "sunspot fish", "tuna", "blue shimmertail", "salmon", "eel", "blackfin hunter", "trout", "north fish", "swamp snapper", "blue bubbler", "fire fish" }; public static readonly string[] TotalFishBadgeNames = new string[4] { "caught50", "caught250", "caught500", "caughtAll" }; public static FishCaughtUI Instance { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _caughtFish = new Dictionary(); _fishBadges = new Dictionary(); _fishBadgeGOs = new Dictionary(); string[] fishNames = FishNames; foreach (string text in fishNames) { _caughtFish.Add(text, 0); int[] fISH_BADGE_AMOUNTS = FISH_BADGE_AMOUNTS; foreach (int num in fISH_BADGE_AMOUNTS) { _fishBadges.Add($"{text}{num}", value: false); } } string[] totalFishBadgeNames = TotalFishBadgeNames; foreach (string key in totalFishBadgeNames) { _fishBadges.Add(key, value: false); } } public void RegisterCatch(GameObject fish) { string name = ((ShipItem)fish.GetComponent()).name; if (!_caughtFish.ContainsKey(name)) { SAD_Plugin.LogWarning("Fish caught " + name + " is not in fish caught log"); return; } _caughtFish[name]++; CheckBadges(name); SAD_Plugin.LogDebug("Caught: " + name); } public void UpdatePage() { UpdateTexts(); UpdateBadges(); } private void UpdateTexts() { int num = 0; int num2 = 0; foreach (KeyValuePair item in _caughtFish) { if (Configs.fishNamesHidden.Value) { _fishNameTMs[num].text = ((item.Value > 0) ? item.Key : "???"); } else { _fishNameTMs[num].text = item.Key; } _caughtCountTMs[num].text = item.Value.ToString(); num2 += item.Value; num++; } _fishNameTMs[_fishNameTMs.Length - 1].text = "Total"; _caughtCountTMs[_caughtCountTMs.Length - 1].text = $"{num2}"; } public void CheckBadges(string fishName) { CheckIndividualFishBadges(fishName); CheckAllFishBadges(); } public void CheckIndividualFishBadges(string fishName) { int[] fISH_BADGE_AMOUNTS = FISH_BADGE_AMOUNTS; foreach (int num in fISH_BADGE_AMOUNTS) { if (!_fishBadges[$"{fishName}{num}"] && _caughtFish[fishName] >= num) { if (Configs.notificationsEnabled.Value) { NotificationUiQueue.Instance.QueueNotification($"Caught {num} {fishName}"); } _fishBadges[$"{fishName}{num}"] = true; } } } public void CheckAllFishBadges() { int num = _caughtFish.Values.Sum(); for (int i = 0; i < TOTAL_FISH_BADGE_AMOUNTS.Length; i++) { if (!_fishBadges[TotalFishBadgeNames[i]] && num >= TOTAL_FISH_BADGE_AMOUNTS[i]) { if (Configs.notificationsEnabled.Value) { NotificationUiQueue.Instance.QueueNotification($"Caught {TOTAL_FISH_BADGE_AMOUNTS[i]} fish"); } _fishBadges[TotalFishBadgeNames[i]] = true; } } if (!_fishBadges[TotalFishBadgeNames[3]] && !_caughtFish.Values.Any((int v) => v.Equals(0))) { if (Configs.notificationsEnabled.Value) { NotificationUiQueue.Instance.QueueNotification("Caught all fish"); } _fishBadges[TotalFishBadgeNames[3]] = true; } } private void UpdateBadges() { foreach (KeyValuePair fishBadge in _fishBadges) { _fishBadgeGOs[fishBadge.Key].SetActive(fishBadge.Value); } } public void SetUIElems(TextMesh[] fishNameTMs, TextMesh[] caughtCountTMs, Dictionary fishBadgeGOs) { _fishNameTMs = fishNameTMs; _caughtCountTMs = caughtCountTMs; _fishBadgeGOs = fishBadgeGOs; } public void LoadFishCaughtUI() { ModData.GetDictEntry("Sail-a-dex.CaughtFish", _caughtFish); ModData.GetDictEntry("Sail-a-dex.FishBadges", _fishBadges); } public void SaveFishCaughtUI() { ModData.AddDictEntry("Sail-a-dex.CaughtFish", _caughtFish); ModData.AddDictEntry("Sail-a-dex.FishBadges", _fishBadges); } } internal class LogUIPatches { [HarmonyPatch(typeof(MissionListUI))] private class MissionListUIPatches { [HarmonyPrefix] [HarmonyPatch("ToggleMenu")] public static void TogglePatch() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) bookmarks[0].SetActive(false); bookmarks[1].SetActive(false); bookmarks[2].SetActive(false); Stack stack = new Stack(); stack.Push(new Vector3(-0.515f, -0.0035f, -0.4566f)); stack.Push(new Vector3(-0.387f, 0.0028f, -0.4566f)); stack.Push(new Vector3(-0.26f, 0.0032f, -0.4566f)); Stack stack2 = new Stack(); stack2.Push(new Vector3(-0.515f, 0.0082f, -0.4516f)); stack2.Push(new Vector3(-0.387f, 0.0138f, -0.4516f)); stack2.Push(new Vector3(-0.26f, 0.0137f, -0.4516f)); if (Configs.fishCaughtUIEnabled.Value) { logModeButtons[5].SetPrivateField("inactiveLocalPos", stack.Pop()); logModeButtons[5].SetPrivateField("activeLocalPos", stack2.Pop()); bookmarks[0].SetActive(true); } if (Configs.portsVisitedUIEnabled.Value) { logModeButtons[6].SetPrivateField("inactiveLocalPos", stack.Pop()); logModeButtons[6].SetPrivateField("activeLocalPos", stack2.Pop()); bookmarks[1].SetActive(true); } if (Configs.statsUIEnabled.Value) { logModeButtons[7].SetPrivateField("inactiveLocalPos", stack.Pop()); logModeButtons[7].SetPrivateField("activeLocalPos", stack2.Pop()); bookmarks[2].SetActive(true); } } [HarmonyPostfix] [HarmonyPatch("HideUI")] public static void HideUIPatches() { fishCaughtUI.SetActive(false); portsVisitedUI.SetActive(false); statsUI.SetActive(false); } [HarmonyPostfix] [HarmonyPatch("SwitchMode")] public static void SwitchModePatches(MissionListMode mode) { //IL_0025: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected I4, but got Unknown fishCaughtUI.SetActive(false); portsVisitedUI.SetActive(false); statsUI.SetActive(false); switch (mode - 5) { case 0: fishCaughtUI.SetActive(true); FishCaughtUI.Instance.UpdatePage(); break; case 1: portsVisitedUI.SetActive(true); PortsVisitedUI.Instance.UpdatePage(); break; case 2: statsUI.SetActive(true); StatsUI.Instance.UpdatePage(); break; } } [HarmonyPrefix] [HarmonyPatch("Start")] public static void StartPatch(GameObject ___modeButtons, ref GPButtonLogMode[] ___logModeButtons, GameObject ___reputationUI) { List existingLogModeButtons = new List(___logModeButtons); (List, GPButtonLogMode[]) tuple = UIBuilder.MakeBookmarks(___modeButtons, existingLogModeButtons); bookmarks = tuple.Item1; logModeButtons = tuple.Item2; statsUI = UIBuilder.MakeStatsUI(___reputationUI); portsVisitedUI = UIBuilder.MakePortsVisitedUI(___reputationUI); fishCaughtUI = UIBuilder.MakeFishCaughtUI(___reputationUI); ___logModeButtons = logModeButtons; } } [HarmonyPatch(typeof(NotificationUi))] private class NotificationUiPatches { [HarmonyPostfix] [HarmonyPatch("Start")] public static void StartPatch(NotificationUi ___instance) { if (Configs.notificationsEnabled.Value) { ((Component)___instance).gameObject.AddComponent(); } } } private static GameObject fishCaughtUI; private static GameObject portsVisitedUI; private static GameObject statsUI; private static List bookmarks; private static GPButtonLogMode[] logModeButtons; } internal sealed class Region { private readonly int _index; private readonly string _name; private readonly string _badgeName; private readonly string _code; private readonly List _ports; private readonly List _islands; public static readonly Region AlAnkh; public static readonly Region EmeraldArchipelago; public static readonly Region Aestrin; public static readonly Region FireFishLagoon; public static readonly IReadOnlyList AllRegions; public static readonly IReadOnlyList AllBadgeNames; public int Index => _index; public string Name => _name; public string BadgeName => _badgeName; public string Code => _code; public IReadOnlyList Ports => _ports.AsReadOnly(); public IReadOnlyList Islands => _islands.AsReadOnly(); public static IReadOnlyList AllPorts { get; private set; } public static IReadOnlyList TransitCodes { get; private set; } private Region(int index, string name, string badgeName, string code, List ports, List islands) { _index = index; _name = name; _badgeName = badgeName; _code = code; _ports = ports; _islands = islands; } public override string ToString() { return Name ?? ""; } static Region() { AlAnkh = new Region(0, "Al'Ankh", "alankhBadge", "Aa", new List { "Gold Rock City", "Al'Nilem", "Neverdin", "Albacore Town", "Alchemist's Island", "Al'Ankh Academy", "Oasis", "Old Ankh Town", "Mirage Mountain", "Saffron Island" }, new List { "island 1 A (gold rock)", "island 2 A (AlNilem)", "island 3 A (Neverdin)", "island 4 A (fish island)", "island 5 A (clear mind)", "island 6 A (lion fang)", "island 7 A (alchemist's island)", "island 8 A (academy)", "island 20 A (Oasis)", "island 40 (coffee)", "island 41 (mirage mountain)", "island 42 ()" }); EmeraldArchipelago = new Region(1, "Emerald Archipelago", "emeraldBadge", "Ea", new List { "Dragon Cliffs", "Sanctuary", "Crab Beach", "New Port", "Sage Hills", "Serpent Isle", "Dead Cove", "Turtle Island" }, new List { "island 9 E (dragon cliffs)", "island 10 E (sanctuary)", "island 11 E (crab beach)", "island 12 E (New Port)", "island 13 E (Sage Hills)", "island 22 E (serpent isle)", "island 37 E (swamp)", "island 38 E (jungle)", "island 39 E (onsen)" }); Aestrin = new Region(2, "Aestrin", "mediBadge", "Ae", new List { "Fort Aestrin", "Sunspire", "Mount Malefic", "Siren Song", "Eastwind", "Firefly Grotto", "Aestra Abbey", "Fey Valley", "Happy Bay", "Chronos" }, new List { "island 15 M (Fort)", "island 16 M (Sunspire)", "island 17 M (Mount Malefic)", "island 19 M (Eastwind)", "island 21 M (Siren Song)", "island 33 M cave church", "island 34 M monastery", "island 35 M valley", "island 23 M oracle", "island 18 M (Oasis)", "island 25 (chronos)" }); FireFishLagoon = new Region(3, "Fire Fish Lagoon", "lagoonBadge", "Ffl", new List { "Kicia Bay", "Fire Fish Town", "On'na", "Sen'na" }, new List { "island 26 Lagoon Temple", "island 27 Lagoon Shipyard", "island 28 Lagoon Senna", "island 29 Lagoon Onna", "island 31 Lagoon Fisherman" }); AllRegions = new List { AlAnkh, EmeraldArchipelago, Aestrin, FireFishLagoon }.AsReadOnly(); AllBadgeNames = new List { AlAnkh.BadgeName, EmeraldArchipelago.BadgeName, Aestrin.BadgeName, FireFishLagoon.BadgeName, "allPortsBadge" }.AsReadOnly(); List list = new List(); foreach (Region allRegion in AllRegions) { list.AddRange(allRegion.Ports); } AllPorts = list.AsReadOnly(); List list2 = new List(); foreach (Region allRegion2 in AllRegions) { foreach (Region allRegion3 in AllRegions) { if (allRegion2.Index != allRegion3.Index) { list2.Add(allRegion2.Code + allRegion3.Code); } } } TransitCodes = list2.AsReadOnly(); } } internal class ModData { public static void AddEntry(string dataName, T data) { string value = ((data == null) ? string.Empty : data.ToString()); if (GameState.modData.ContainsKey(dataName)) { GameState.modData[dataName] = value; } else { GameState.modData.Add(dataName, value); } } public static T GetEntry(string dataName) { if (!GameState.modData.ContainsKey(dataName)) { SAD_Plugin.LogWarning("GetEntry: " + dataName + " not found in modData"); return default(T); } string value = GameState.modData[dataName]; return (T)Convert.ChangeType(value, typeof(T)); } public static void AddDictEntry(string dataName, Dictionary data) { StringBuilder stringBuilder = new StringBuilder(); if (typeof(T) == typeof(bool[])) { foreach (KeyValuePair datum in data) { stringBuilder.AppendLine(string.Format("{0}|{1}", datum.Key, string.Join(",", (bool[])(object)datum.Value))); } } else if (typeof(T) == typeof(float)) { foreach (KeyValuePair datum2 in data) { stringBuilder.AppendLine($"{datum2.Key}|{((float)(object)datum2.Value).ToString(CultureInfo.InvariantCulture)}"); } } else { foreach (KeyValuePair datum3 in data) { stringBuilder.AppendLine($"{datum3.Key}|{datum3.Value}"); } } string value = stringBuilder.ToString(); if (GameState.modData.ContainsKey(dataName)) { GameState.modData[dataName] = value; } else { GameState.modData.Add(dataName, value); } } public static void GetDictEntry(string dataName, Dictionary gameDict) { if (!GameState.modData.ContainsKey(dataName)) { SAD_Plugin.LogWarning("LoadDictFromModData: " + dataName + " not found in modData"); return; } string text = GameState.modData[dataName]; string[] array = text.Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text2 in array2) { string[] array3 = text2.Trim().Split(new char[1] { '|' }); if (array3.Length >= 2) { K val = (K)Convert.ChangeType(array3[0], typeof(K)); if (!gameDict.ContainsKey(val)) { SAD_Plugin.LogWarning($"LoadDictFromModData: {val} not found in game"); } else { gameDict[val] = ParseValue(array3[1]); } } } } private static T ParseValue(string raw) { if (typeof(T) == typeof(bool[])) { bool[] array = Array.ConvertAll(raw.Split(new char[1] { ',' }), bool.Parse); return (T)(object)array; } if (typeof(T) == typeof(float)) { return (T)(object)float.Parse(raw, CultureInfo.InvariantCulture); } return (T)Convert.ChangeType(raw, typeof(T)); } } internal class UIBuilder { internal const MissionListMode FISH_CAUGHT = (MissionListMode)5; internal const MissionListMode PORTS_VISITED = (MissionListMode)6; internal const MissionListMode STATS = (MissionListMode)7; private const int FISH_CAUGHT_FONT_SIZE = 50; private const int STAT_HEADER_FONT_SIZE = 45; private const int STAT_FONT_SIZE = 40; internal static (List, GPButtonLogMode[]) MakeBookmarks(GameObject modeButtons, List existingLogModeButtons) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) List list = new List(); GameObject gameObject = ((Component)modeButtons.transform.GetChild(9)).gameObject; GameObject val = Object.Instantiate(gameObject); val.transform.parent = modeButtons.transform; val.transform.localRotation = gameObject.transform.localRotation; val.transform.localScale = gameObject.transform.localScale; ((Object)val).name = "bookmark fish caught"; ((Component)val.transform.GetChild(0)).gameObject.GetComponent().text = "fish caught"; GPButtonLogMode component = val.GetComponent(); Traverse.Create((object)component).Field("mode").SetValue((object)(MissionListMode)5); Object.Destroy((Object)(object)val.GetComponent()); list.Add(val); existingLogModeButtons.Add(component); GameObject val2 = Object.Instantiate(gameObject); val2.transform.parent = modeButtons.transform; val2.transform.localRotation = gameObject.transform.localRotation; val2.transform.localScale = gameObject.transform.localScale; ((Object)val2).name = "bookmark ports visited"; ((Component)val2.transform.GetChild(0)).gameObject.GetComponent().text = "ports visited"; GPButtonLogMode component2 = val2.GetComponent(); Traverse.Create((object)component2).Field("mode").SetValue((object)(MissionListMode)6); Object.Destroy((Object)(object)val2.GetComponent()); list.Add(val2); existingLogModeButtons.Add(component2); GameObject val3 = Object.Instantiate(gameObject); val3.transform.parent = modeButtons.transform; val3.transform.localRotation = gameObject.transform.localRotation; val3.transform.localScale = gameObject.transform.localScale; ((Object)val3).name = "bookmark stats"; ((Component)val3.transform.GetChild(0)).gameObject.GetComponent().text = "stats & transit"; GPButtonLogMode component3 = val3.GetComponent(); Traverse.Create((object)component3).Field("mode").SetValue((object)(MissionListMode)7); Object.Destroy((Object)(object)val3.GetComponent()); list.Add(val3); existingLogModeButtons.Add(component3); return (list, existingLogModeButtons.ToArray()); } internal static GameObject MakeFishCaughtUI(GameObject repUI) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_058d: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(repUI); Object.Destroy((Object)(object)val.GetComponent()); val.transform.parent = repUI.transform.parent; val.transform.localPosition = repUI.transform.localPosition; val.transform.localRotation = repUI.transform.localRotation; val.transform.localScale = repUI.transform.localScale; ((Object)val).name = "fish caught ui"; Object.Destroy((Object)(object)((Component)val.transform.GetChild(7)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(6)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(5)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(0)).gameObject); val.AddComponent(); GameObject gameObject = ((Component)val.transform.GetChild(1)).gameObject; gameObject.SetActive(true); gameObject.GetComponent().font = ((Component)gameObject.transform.GetChild(1)).GetComponent().font; ((Renderer)gameObject.GetComponent()).material = ((Renderer)((Component)gameObject.transform.GetChild(1)).GetComponent()).material; ((Object)((Component)gameObject.transform.GetChild(1)).gameObject).name = "caught count"; Transform child = gameObject.transform.GetChild(1); Vector3 localPosition = gameObject.transform.GetChild(1).localPosition; child.localPosition = new Vector3(55f, 0f, ((Vector3)(ref localPosition))[2]); ((Component)gameObject.transform.GetChild(1)).GetComponent().fontSize = 50; TextMesh[] array = (TextMesh[])(object)new TextMesh[FishCaughtUI.FishNames.Length + 1]; TextMesh[] array2 = (TextMesh[])(object)new TextMesh[FishCaughtUI.FishNames.Length + 1]; Dictionary dictionary = new Dictionary(); for (int i = 0; i < FishCaughtUI.FishNames.Length; i++) { GameObject val2 = Object.Instantiate(gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(0)).gameObject); val2.GetComponent().fontSize = 50; ((Object)val2).name = FishCaughtUI.FishNames[i]; val2.transform.parent = gameObject.transform.parent; Transform transform = val2.transform; float num = 0.24f - 0.0375f * (float)i; localPosition = gameObject.transform.localPosition; transform.localPosition = new Vector3(0.8f, num, ((Vector3)(ref localPosition))[2]); val2.transform.localRotation = gameObject.transform.localRotation; val2.transform.localScale = gameObject.transform.localScale; array2[i] = val2.GetComponent(); array[i] = ((Component)val2.transform.GetChild(1)).GetComponent(); string[] array3 = new string[3] { "25", "50", "100" }; for (int j = 0; j < array3.Length; j++) { string name = ((Object)val2).name + array3[j]; ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(CreateBadgeObject(dictionary, name, val2.transform, new Vector3(12f, 12f, 1f), new Vector3(75f + (float)j * 13f, 0f, 0f))); } } GameObject val3 = Object.Instantiate(gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(0)).gameObject); ((Object)val3).name = "totalCaught"; val3.transform.parent = gameObject.transform.parent; Transform transform2 = val3.transform; localPosition = gameObject.transform.localPosition; transform2.localPosition = new Vector3(0.8f, -0.21f, ((Vector3)(ref localPosition))[2]); val3.transform.localRotation = gameObject.transform.localRotation; val3.transform.localScale = gameObject.transform.localScale; array2[FishCaughtUI.FishNames.Length] = val3.GetComponent(); array[FishCaughtUI.FishNames.Length] = ((Component)val3.transform.GetChild(1)).GetComponent(); string[] array4 = new string[4] { "caught50", "caught250", "caught500", "caughtAll" }; for (int k = 0; k < array4.Length; k++) { string name2 = array4[k]; ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(CreateBadgeObject(dictionary, name2, val3.transform, new Vector3(15f, 15f, 1f), new Vector3(15f + (float)k * 20f, -13f, 0f))); } Object.Destroy((Object)(object)gameObject); FishCaughtUI.Instance.SetUIElems(array2, array, dictionary); SAD_Plugin.LogDebug("Loaded fish caught UI"); return val; } internal static GameObject MakePortsVisitedUI(GameObject repUI) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_0758: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) //IL_0575: Unknown result type (might be due to invalid IL or missing references) //IL_058e: Unknown result type (might be due to invalid IL or missing references) //IL_05e8: Unknown result type (might be due to invalid IL or missing references) //IL_05ed: Unknown result type (might be due to invalid IL or missing references) //IL_05fe: Unknown result type (might be due to invalid IL or missing references) //IL_0603: Unknown result type (might be due to invalid IL or missing references) //IL_061e: Unknown result type (might be due to invalid IL or missing references) //IL_0623: Unknown result type (might be due to invalid IL or missing references) //IL_062d: Unknown result type (might be due to invalid IL or missing references) //IL_0646: Unknown result type (might be due to invalid IL or missing references) //IL_065f: Unknown result type (might be due to invalid IL or missing references) //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_06fb: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(repUI); Object.Destroy((Object)(object)val.GetComponent()); val.transform.parent = repUI.transform.parent; val.transform.localPosition = repUI.transform.localPosition; val.transform.localRotation = repUI.transform.localRotation; val.transform.localScale = repUI.transform.localScale; ((Object)val).name = "ports visited ui"; Object.Destroy((Object)(object)((Component)val.transform.GetChild(7)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(6)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(5)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(3)).gameObject); val.AddComponent(); Transform child = val.transform.GetChild(0); Vector3 localPosition = val.transform.GetChild(0).localPosition; child.localPosition = new Vector3(0.75f, 0.245f, ((Vector3)(ref localPosition))[2]); Transform child2 = val.transform.GetChild(1); localPosition = val.transform.GetChild(1).localPosition; child2.localPosition = new Vector3(0.75f, -0.05f, ((Vector3)(ref localPosition))[2]); Transform child3 = val.transform.GetChild(2); localPosition = val.transform.GetChild(2).localPosition; child3.localPosition = new Vector3(0.02f, 0.245f, ((Vector3)(ref localPosition))[2]); ((Component)val.transform.GetChild(1)).gameObject.SetActive(true); ((Component)val.transform.GetChild(2)).gameObject.SetActive(true); GameObject val2 = Object.Instantiate(((Component)val.transform.GetChild(1)).gameObject); val2.transform.parent = val.transform; Transform transform = val2.transform; localPosition = val.transform.GetChild(1).localPosition; transform.localPosition = new Vector3(0.02f, -0.05f, ((Vector3)(ref localPosition))[2]); val2.transform.localRotation = val.transform.GetChild(1).localRotation; val2.transform.localScale = val.transform.GetChild(1).localScale; ((Object)val2).name = "lagoon"; val2.GetComponent().text = "Fire Fish Lagoon"; TextMesh[] array = (TextMesh[])(object)new TextMesh[Region.AllPorts.Count]; TextMesh[] array2 = (TextMesh[])(object)new TextMesh[Region.AllPorts.Count]; Dictionary dictionary = new Dictionary(); int num = 0; int[] array3 = new int[4] { Region.AlAnkh.Ports.Count, Region.EmeraldArchipelago.Ports.Count, Region.Aestrin.Ports.Count, Region.FireFishLagoon.Ports.Count }; for (int i = 0; i < array3.Length; i++) { Transform child4 = val.transform.GetChild(i); if (i == 3) { child4 = val.transform.GetChild(8); } Object.Destroy((Object)(object)((Component)child4.GetChild(1)).gameObject); Object.Destroy((Object)(object)((Component)child4.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)child4.GetChild(4)).gameObject); if (i == 0) { Object.Destroy((Object)(object)((Component)child4.GetChild(5)).gameObject); ((Component)child4.GetChild(6)).GetComponent().alignment = (TextAlignment)0; ((Component)child4.GetChild(6)).GetComponent().anchor = (TextAnchor)3; ((Component)child4.GetChild(6)).GetComponent().fontSize = 60; ((Component)child4.GetChild(6)).transform.localPosition = Vector3.zero; } GameObject gameObject = ((Component)child4.GetChild(0)).gameObject; GameObject gameObject2 = ((Component)child4.GetChild(3)).gameObject; gameObject2.SetActive(true); ((Object)gameObject).name = "port1"; gameObject.transform.localPosition = new Vector3(5f, -8f, -0.1f); gameObject.GetComponent().alignment = (TextAlignment)0; gameObject.GetComponent().anchor = (TextAnchor)3; gameObject.GetComponent().fontSize = 50; ((Object)gameObject2).name = "visited port1"; gameObject2.transform.localPosition = new Vector3(70f, -9f, 0f); gameObject2.GetComponent().alignment = (TextAlignment)2; gameObject2.GetComponent().anchor = (TextAnchor)5; gameObject2.GetComponent().fontSize = 50; array[num] = gameObject.GetComponent(); array2[num] = gameObject2.GetComponent(); num++; for (int j = 1; j < array3[i]; j++) { GameObject val3 = Object.Instantiate(gameObject); val3.transform.parent = gameObject.transform.parent; Transform transform2 = val3.transform; localPosition = gameObject.transform.localPosition; float num2 = ((Vector3)(ref localPosition))[0]; localPosition = gameObject.transform.localPosition; float num3 = ((Vector3)(ref localPosition))[1] - 7.5f * (float)j; localPosition = gameObject.transform.localPosition; transform2.localPosition = new Vector3(num2, num3, ((Vector3)(ref localPosition))[2]); val3.transform.localRotation = gameObject.transform.localRotation; val3.transform.localScale = gameObject.transform.localScale; ((Object)val3).name = "port" + (j + 1); GameObject val4 = Object.Instantiate(gameObject2); val4.transform.parent = gameObject2.transform.parent; Transform transform3 = val4.transform; localPosition = gameObject2.transform.localPosition; float num4 = ((Vector3)(ref localPosition))[0]; localPosition = gameObject2.transform.localPosition; float num5 = ((Vector3)(ref localPosition))[1] - 7.5f * (float)j; localPosition = gameObject2.transform.localPosition; transform3.localPosition = new Vector3(num4, num5, ((Vector3)(ref localPosition))[2]); val4.transform.localRotation = gameObject2.transform.localRotation; val4.transform.localScale = gameObject2.transform.localScale; ((Object)val4).name = $"visited port{j + 1}"; array[num] = val3.GetComponent(); array2[num] = val4.GetComponent(); num++; } string name = ((Object)child4).name + "Badge"; ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(CreateBadgeObject(dictionary, name, child4, new Vector3(15f, 15f, 1f), new Vector3(-8f, -2f, 0f))); } ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(CreateBadgeObject(dictionary, "allPortsBadge", val.transform, new Vector3(0.1f, 0.0675f, 1f), new Vector3(-0.15f, -0.23f, -0.007f))); PortsVisitedUI.Instance.SetUIElems(array, array2, dictionary); SAD_Plugin.LogDebug("Loaded ports visited UI"); return val; } internal static GameObject MakeStatsUI(GameObject repUI) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_04c4: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_0670: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(repUI); Object.Destroy((Object)(object)val.GetComponent()); val.transform.parent = repUI.transform.parent; val.transform.localPosition = repUI.transform.localPosition; val.transform.localRotation = repUI.transform.localRotation; val.transform.localScale = repUI.transform.localScale; ((Object)val).name = "stats ui"; Object.Destroy((Object)(object)((Component)val.transform.GetChild(7)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(6)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(5)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(0)).gameObject); val.AddComponent(); GameObject gameObject = ((Component)val.transform.GetChild(1)).gameObject; gameObject.SetActive(true); gameObject.GetComponent().font = ((Component)gameObject.transform.GetChild(1)).GetComponent().font; gameObject.GetComponent().fontSize = 40; gameObject.GetComponent().characterSize = 1f; ((Renderer)gameObject.GetComponent()).material = ((Renderer)((Component)gameObject.transform.GetChild(1)).GetComponent()).material; ((Object)((Component)gameObject.transform.GetChild(0)).gameObject).name = "current value"; gameObject.transform.GetChild(0).localPosition = new Vector3(38f, 0f, 0f); ((Component)gameObject.transform.GetChild(0)).GetComponent().font = ((Component)gameObject.transform.GetChild(1)).GetComponent().font; ((Component)gameObject.transform.GetChild(0)).GetComponent().fontSize = 40; ((Component)gameObject.transform.GetChild(0)).GetComponent().anchor = (TextAnchor)3; ((Component)gameObject.transform.GetChild(0)).GetComponent().fontStyle = (FontStyle)0; ((Component)gameObject.transform.GetChild(0)).GetComponent().characterSize = 1f; ((Component)gameObject.transform.GetChild(0)).GetComponent().lineSpacing = 1f; ((Renderer)((Component)gameObject.transform.GetChild(0)).GetComponent()).material = ((Renderer)((Component)gameObject.transform.GetChild(1)).GetComponent()).material; ((Object)((Component)gameObject.transform.GetChild(1)).gameObject).name = "record value"; gameObject.transform.GetChild(1).localPosition = new Vector3(80f, 0f, 0f); ((Component)gameObject.transform.GetChild(1)).GetComponent().fontSize = 40; ((Component)gameObject.transform.GetChild(1)).GetComponent().anchor = (TextAnchor)3; ((Component)gameObject.transform.GetChild(1)).GetComponent().fontStyle = (FontStyle)0; Dictionary dictionary = new Dictionary(); AddTrackedStat(gameObject, "CargoMass", 0.215f, dictionary); AddTrackedStat(gameObject, "TotalMass", 0.19f, dictionary); AddTrackedStat(gameObject, "UnderwayTime", 0.165f, dictionary); AddTrackedStat(gameObject, "MilesSailed", 0.09f, dictionary, ltime: true); List list = new List(); int num = 0; string[] intStatNames = StatsUI.IntStatNames; foreach (string text in intStatNames) { if (!(text == "UnderwayDay")) { if (StatsUI.RandomEncounterStats.ContainsKey(text)) { list.Add(0.065f - 0.025f * (float)num); } AddTrackedStat(gameObject, text, 0.065f - 0.025f * (float)num, dictionary, ltime: true); num++; } } StatsUI.RandomEncounterStatYPos = list; int num2 = 0; foreach (string transitCode in Region.TransitCodes) { AddTrackedStat(gameObject, transitCode, 0.215f - 0.025f * (float)num2, dictionary, ltime: false, transit: true); num2++; } StatsUI.Instance.SetUIElems(dictionary); ((Object)gameObject).name = "stats header"; gameObject.GetComponent().text = "Stat Current Record"; gameObject.transform.localPosition = new Vector3(0.82f, 0.24f, -0.007f); gameObject.GetComponent().fontSize = 45; gameObject.GetComponent().fontStyle = (FontStyle)1; Object.Destroy((Object)(object)((Component)gameObject.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)gameObject.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)gameObject.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)gameObject.transform.GetChild(1)).gameObject); Object.Destroy((Object)(object)((Component)gameObject.transform.GetChild(0)).gameObject); GameObject val2 = Object.Instantiate(gameObject, gameObject.transform.parent); ((Object)val2).name = "lifetime stats header"; val2.GetComponent().text = "Lifetime Stats"; val2.transform.localPosition = new Vector3(0.82f, 0.115f, -0.007f); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(1)).gameObject); Object.Destroy((Object)(object)((Component)val2.transform.GetChild(0)).gameObject); GameObject val3 = Object.Instantiate(gameObject, gameObject.transform.parent); ((Object)val3).name = "transit times header"; val3.GetComponent().text = "Transit Times Last Record"; val3.transform.localPosition = new Vector3(0.14f, 0.24f, -0.007f); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(2)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(1)).gameObject); Object.Destroy((Object)(object)((Component)val3.transform.GetChild(0)).gameObject); SAD_Plugin.LogDebug("Loaded stats & transit UI"); return val; } private static void AddTrackedStat(GameObject templateGO, string name, float yPos, Dictionary statTMs, bool ltime = false, bool transit = false) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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) float num = (transit ? 0.14f : 0.82f); string text = (transit ? "last" : "current"); GameObject val = Object.Instantiate(templateGO); Object.Destroy((Object)(object)((Component)val.transform.GetChild(4)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(3)).gameObject); Object.Destroy((Object)(object)((Component)val.transform.GetChild(2)).gameObject); if (ltime) { Object.Destroy((Object)(object)((Component)val.transform.GetChild(1)).gameObject); val.transform.GetChild(0).localPosition = new Vector3(41f, 0f, 0f); } ((Object)val).name = name; val.transform.parent = templateGO.transform.parent; Transform transform = val.transform; Vector3 localPosition = templateGO.transform.localPosition; transform.localPosition = new Vector3(num, yPos, ((Vector3)(ref localPosition))[2]); val.transform.localRotation = templateGO.transform.localRotation; val.transform.localScale = templateGO.transform.localScale; statTMs[name] = val.GetComponent(); statTMs[text + name] = ((Component)val.transform.GetChild(0)).GetComponent(); if (!ltime) { statTMs["record" + name] = ((Component)val.transform.GetChild(1)).GetComponent(); } AddLine(((Component)val.transform.GetChild(1)).gameObject); } private static void AddLine(GameObject templateGO) { //IL_0040: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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) GameObject val = Object.Instantiate(templateGO); ((Object)val).name = "line"; val.transform.parent = templateGO.transform.parent; val.transform.localPosition = new Vector3(-1.2f, -1.75f, 0f); val.transform.localRotation = templateGO.transform.localRotation; val.transform.localScale = templateGO.transform.localScale; TextMesh component = val.GetComponent(); component.color = Color32.op_Implicit(new Color32((byte)2, (byte)2, (byte)10, (byte)133)); component.text = "--------------------------------------------------------"; } private static IEnumerator CreateBadgeObject(Dictionary badgeGOs, string name, Transform parent, Vector3 scale, Vector3 position) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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) yield return (object)new WaitUntil((Func)(() => AssetsLoader.BadgesLoaded)); GameObject badge = GameObject.CreatePrimitive((PrimitiveType)5); badge.layer = 5; badge.transform.SetParent(parent, false); badge.transform.localScale = scale; badge.transform.localPosition = position; ((Object)badge).name = name; if (name.Equals("allPortsBadge")) { badge.transform.localEulerAngles = new Vector3(0f, 180f, 0f); } MeshRenderer meshRenderer = badge.GetComponent(); ((Renderer)meshRenderer).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)meshRenderer).material = AssetsLoader.Materials[name]; Object.Destroy((Object)(object)badge.GetComponent()); badgeGOs.Add(name, badge); } } internal class AssetsLoader { private static Dictionary _textures; private static Dictionary _fishTextures; private static Dictionary _badgeRings; private static bool _fishBadgesLoaded; private static bool _portBadgesLoaded; private const string LIB_FILE = "SailadexREBridge.dll"; private const string ASSETS_DIR = "Assets"; private const string BELLS_AUDIO_FILE = "twoBells.wav"; private static readonly List assetPaths = new List { Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)SAD_Plugin.Instance).Info.Location), "Assets"), Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)SAD_Plugin.Instance).Info.Location)) }; public static bool BadgesLoaded => _fishBadgesLoaded && _portBadgesLoaded; public static AudioClip NotificationSound { get; private set; } public static Dictionary Materials { get; private set; } public static string FindAssetPath(string fileName) { foreach (string assetPath in assetPaths) { string text = Path.Combine(assetPath, fileName); if (File.Exists(text)) { return text; } } return null; } public static void Start() { Materials = new Dictionary(); _textures = new Dictionary(); _fishTextures = new Dictionary(); _badgeRings = new Dictionary(); ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadAssetsAsync()); } internal static void LoadBridge() { try { string text = FindAssetPath("SailadexREBridge.dll"); if (text == null) { SAD_Plugin.LogError("Assembly file not found: SailadexREBridge.dll"); return; } SAD_Plugin.REBridge_Assembly = Assembly.LoadFrom(text); SAD_Plugin.LogDebug("Loaded assembly: " + SAD_Plugin.REBridge_Assembly.FullName); } catch (Exception ex) { SAD_Plugin.LogError("Failed to load assembly: " + ex.Message); } } private static IEnumerator LoadAssetsAsync() { Coroutine audioCoroutine = ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadAudio()); Coroutine fishBadgeCoroutine = ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFishBadges()); Coroutine portBadgeCoroutine = ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadPortBadges()); yield return audioCoroutine; yield return fishBadgeCoroutine; yield return portBadgeCoroutine; SAD_Plugin.LogInfo("Assets loaded"); } private static IEnumerator LoadAudio() { string clipPath = FindAssetPath("twoBells.wav"); UnityWebRequest webRequest = UnityWebRequestMultimedia.GetAudioClip("file://" + clipPath, (AudioType)20); try { yield return webRequest.SendWebRequest(); if (webRequest.isNetworkError || webRequest.isHttpError) { SAD_Plugin.LogError(webRequest.error); yield break; } AudioClip clip = DownloadHandlerAudioClip.GetContent(webRequest); ((Object)clip).name = "twoBells"; NotificationSound = clip; SAD_Plugin.LogDebug("Audio loaded."); } finally { ((IDisposable)webRequest)?.Dispose(); } } private static IEnumerator LoadFishBadges() { yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadBadgeRings()); yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFishTextures()); yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(GenerateFishBadges()); _fishBadgesLoaded = true; SAD_Plugin.LogDebug("Fish badges loaded."); } private static IEnumerator LoadBadgeRings() { int[] amountNums = new int[3] { 25, 50, 100 }; List ringCoroutines = new List(); int[] array = amountNums; for (int i = 0; i < array.Length; i++) { int amount = array[i]; string ringName = amount + "Fish"; string path = FindAssetPath(ringName + ".png"); ringCoroutines.Add(((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadBadgeRing(path, amount))); } foreach (Coroutine item in ringCoroutines) { yield return item; } } private static IEnumerator LoadBadgeRing(string path, int amount) { if (!File.Exists(path)) { SAD_Plugin.LogError("Badge ring file not found: " + path); yield break; } Texture2D texture2D = new Texture2D(1, 1); byte[] fileData = null; yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFile(path, delegate(byte[] result) { fileData = result; })); if (fileData != null && fileData.Length != 0) { if (!ImageConversion.LoadImage(texture2D, fileData)) { SAD_Plugin.LogError("Failed to load badge ring from bytes: " + path); } else { _badgeRings[amount] = texture2D; } } } private static IEnumerator LoadFishTextures() { List fishCoroutines = new List(); string[] fishNames = FishCaughtUI.FishNames; foreach (string fishName in fishNames) { string path = FindAssetPath(fishName + ".png"); fishCoroutines.Add(((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFishTexture(path, fishName))); } foreach (Coroutine item in fishCoroutines) { yield return item; } } private static IEnumerator LoadFishTexture(string path, string fishName) { if (!File.Exists(path)) { SAD_Plugin.LogError("Fish texture file not found: " + path); yield break; } Texture2D texture2D = new Texture2D(1, 1); byte[] fileData = null; yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFile(path, delegate(byte[] result) { fileData = result; })); if (fileData != null && fileData.Length != 0) { if (!ImageConversion.LoadImage(texture2D, fileData)) { SAD_Plugin.LogError("Failed to load fish texture from bytes: " + path); } else { _fishTextures[fishName] = texture2D; } } } private static IEnumerator GenerateFishBadges() { int[] amountNums = new int[3] { 25, 50, 100 }; string[] fishNames = FishCaughtUI.FishNames; foreach (string fishName in fishNames) { if (!_fishTextures.ContainsKey(fishName)) { SAD_Plugin.LogError("Fish texture not found for: " + fishName); continue; } Texture2D fishTexture = _fishTextures[fishName]; Dictionary scaledFishTextures = new Dictionary(); for (int j = 0; j < amountNums.Length; j++) { int amount = amountNums[j]; if (!_badgeRings.ContainsKey(amount)) { SAD_Plugin.LogError($"Badge ring not found for amount: {amount}"); continue; } Texture2D ringTexture = _badgeRings[amount]; string badgeName = fishName + amount; string sizeKey = $"{((Texture)ringTexture).width}x{((Texture)ringTexture).height}"; if (!scaledFishTextures.TryGetValue(sizeKey, out var scaledFishTexture)) { scaledFishTexture = ScaleTexture(fishTexture, ((Texture)ringTexture).width, ((Texture)ringTexture).height); scaledFishTextures.Add(sizeKey, scaledFishTexture); } Texture2D combinedTexture = CombineTextures(scaledFishTexture, ringTexture); ((Object)combinedTexture).name = badgeName; _textures[badgeName] = combinedTexture; Materials[badgeName] = CreateMaterial(combinedTexture); scaledFishTexture = null; } foreach (Texture2D scaledTexture in scaledFishTextures.Values) { Object.DestroyImmediate((Object)(object)scaledTexture); } yield return null; } string[] totalFishBadgeNames = FishCaughtUI.TotalFishBadgeNames; foreach (string caughtBadge in totalFishBadgeNames) { string path = FindAssetPath(caughtBadge + ".png"); yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadTexture(path, caughtBadge)); } } private static Texture2D CombineTextures(Texture2D scaledFishTexture, Texture2D ringTexture) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) int width = ((Texture)ringTexture).width; int height = ((Texture)ringTexture).height; Texture2D val = new Texture2D(width, height, (TextureFormat)4, false); Color[] pixels = ringTexture.GetPixels(); val.SetPixels(pixels); Color[] pixels2 = scaledFishTexture.GetPixels(); for (int i = 0; i < pixels.Length; i++) { Color val2 = pixels2[i]; Color val3 = pixels[i]; if (val2.a > 0f) { pixels[i] = Color.Lerp(val3, val2, val2.a); } } val.SetPixels(pixels); val.Apply(); return val; } private static Texture2D ScaleTexture(Texture2D source, int targetWidth, int targetHeight) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) float num = (float)((Texture)source).width / (float)((Texture)source).height; float num2 = (float)targetWidth / (float)targetHeight; int num3; int num4; if (num > num2) { num3 = targetWidth; num4 = Mathf.RoundToInt((float)targetWidth / num); } else { num4 = targetHeight; num3 = Mathf.RoundToInt((float)targetHeight * num); } Texture2D val = new Texture2D(targetWidth, targetHeight, source.format, false); Color[] array = (Color[])(object)new Color[targetWidth * targetHeight]; for (int i = 0; i < array.Length; i++) { array[i] = Color.clear; } int num5 = (targetWidth - num3) / 2; int num6 = (targetHeight - num4) / 2; Color[] pixels = source.GetPixels(); for (int j = 0; j < num4; j++) { for (int k = 0; k < num3; k++) { float num7 = (float)k / (float)num3 * (float)((Texture)source).width; float num8 = (float)j / (float)num4 * (float)((Texture)source).height; int num9 = Mathf.FloorToInt(num7); int num10 = Mathf.FloorToInt(num8); num9 = Mathf.Clamp(num9, 0, ((Texture)source).width - 1); num10 = Mathf.Clamp(num10, 0, ((Texture)source).height - 1); int num11 = num10 * ((Texture)source).width + num9; int num12 = (j + num6) * targetWidth + (k + num5); if (num12 >= 0 && num12 < array.Length) { array[num12] = pixels[num11]; } } } val.SetPixels(array); val.Apply(); return val; } private static IEnumerator LoadPortBadges() { List textureCoroutines = new List(); foreach (string pbName in Region.AllBadgeNames) { string path = FindAssetPath(pbName + ".png"); textureCoroutines.Add(((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadTexture(path, pbName))); } foreach (Coroutine item in textureCoroutines) { yield return item; } _portBadgesLoaded = true; SAD_Plugin.LogDebug("Port badges loaded."); } private static IEnumerator LoadTexture(string path, string textureName) { if (!File.Exists(path)) { SAD_Plugin.LogError("File not found: " + path); yield break; } Texture2D texture2D = new Texture2D(1, 1); byte[] fileData = null; yield return ((MonoBehaviour)SAD_Plugin.Instance).StartCoroutine(LoadFile(path, delegate(byte[] result) { fileData = result; })); if (fileData != null && fileData.Length != 0) { if (!ImageConversion.LoadImage(texture2D, fileData)) { SAD_Plugin.LogError("Failed to load texture from bytes: " + path); yield break; } _textures[textureName] = texture2D; Materials[textureName] = CreateMaterial(texture2D); } } private static IEnumerator LoadFile(string path, Action onComplete) { byte[] result = null; yield return null; UnityWebRequest www = UnityWebRequest.Get("file://" + path); try { yield return www.SendWebRequest(); if (www.isNetworkError || www.isHttpError) { SAD_Plugin.LogError(www.error); yield break; } result = www.downloadHandler.data; } finally { ((IDisposable)www)?.Dispose(); } onComplete(result); } private static Material CreateMaterial(Texture2D tex) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown Material val = new Material(Shader.Find("Standard")) { renderQueue = 2001, mainTexture = (Texture)(object)tex }; val.EnableKeyword("_ALPHATEST_ON"); val.SetShaderPassEnabled("ShadowCaster", false); return val; } } internal class Configs { internal static ConfigEntry fishNamesHidden; internal static ConfigEntry portNamesHidden; internal static ConfigEntry fishCaughtUIEnabled; internal static ConfigEntry portsVisitedUIEnabled; internal static ConfigEntry statsUIEnabled; internal static ConfigEntry notificationsEnabled; internal static ConfigEntry notificationSoundVolume; internal static ConfigEntry updateMilesSailed; internal static void InitializeConfigs() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown ConfigFile config = ((BaseUnityPlugin)SAD_Plugin.Instance).Config; fishCaughtUIEnabled = config.Bind("Enable/Disable UI", "Fish Caught UI", true, (ConfigDescription)null); portsVisitedUIEnabled = config.Bind("Enable/Disable UI", "Ports Visited UI", true, (ConfigDescription)null); statsUIEnabled = config.Bind("Enable/Disable UI", "Stats UI", true, (ConfigDescription)null); fishNamesHidden = config.Bind("Gameplay Settings", "Hide Fish Names Before Caught", true, (ConfigDescription)null); portNamesHidden = config.Bind("Gameplay Settings", "Hide Port Names Before Visited", false, (ConfigDescription)null); updateMilesSailed = config.Bind("Gameplay Settings", "Miles Sailed Updates", "moored", new ConfigDescription("Miles sailed text will be updated once moored, going to sleeping or moored, or in real time.", (AcceptableValueBase)(object)new AcceptableValueList(new string[3] { "moored", "sleep", "realtime" }), Array.Empty())); notificationsEnabled = config.Bind("Notification Settings", "Notification on badge earned", true, (ConfigDescription)null); notificationSoundVolume = config.Bind("Notification Settings", "Notification Volume", 0.2f, "Above 1f is loud and not recommended. Set to 0f to disable."); } } internal static class Extensions { public static T GetPrivateField(this object obj, string field) { return (T)Traverse.Create(obj).Field(field).GetValue(); } public static void SetPrivateField(this object obj, string field, object value) { Traverse.Create(obj).Field(field).SetValue(value); } public static T GetPrivateProperty(this object obj, string property) { return (T)Traverse.Create(obj).Property(property, (object[])null).GetValue(); } public static T GetStaticProperty(this object obj, string property) { return (T)Traverse.Create(obj.GetType()).Property(property, (object[])null).GetValue(); } public static object InvokePrivateMethod(this object obj, string method, params object[] parameters) { return AccessTools.Method(obj.GetType(), method, (Type[])null, (Type[])null).Invoke(obj, parameters); } } public class NotificationUiQueue : MonoBehaviour { private Coroutine _queueCoroutine; private Queue _queue; private AudioSource _audioSource; private const float TIMER_DURATION = 3f; public static NotificationUiQueue Instance { get; private set; } public void Start() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _queue = new Queue(); _queueCoroutine = null; _audioSource = ((Component)this).gameObject.AddComponent(); _audioSource.volume = Configs.notificationSoundVolume.Value; _audioSource.spatialBlend = 1f; _audioSource.minDistance = 10f; _audioSource.maxDistance = 20f; } private IEnumerator ProcessQueue() { while (_queue.Count > 0) { NotificationUi.instance.ShowNotification(_queue.Dequeue()); if (Configs.notificationSoundVolume.Value > 0f) { _audioSource.PlayOneShot(AssetsLoader.NotificationSound); } yield return (object)new WaitForSeconds(3f); } _queueCoroutine = null; } public void QueueNotification(string message) { _queue.Enqueue(message); if (_queueCoroutine == null) { _queueCoroutine = ((MonoBehaviour)this).StartCoroutine(ProcessQueue()); } } } [BepInPlugin("com.raddude.sailadex", "Sail-a-dex", "2.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SAD_Plugin : BaseUnityPlugin { public const string PLUGIN_GUID = "com.raddude.sailadex"; public const string PLUGIN_NAME = "Sail-a-dex"; public const string PLUGIN_VERSION = "2.0.0"; public const string PASSAGEDUDE_GUID = "pr0skynesis.passagedude"; public const string RANDOMENCOUNTERS_GUID = "com.raddude.randomencounters"; internal static ManualLogSource _logger; internal static BaseUnityPlugin RE_PluginInstance { get; private set; } internal static Assembly REBridge_Assembly { get; set; } internal static SAD_Plugin Instance { get; private set; } internal static Harmony HarmonyInstance { get; private set; } public static void LogDebug(string message) { _logger.LogDebug((object)message); } public static void LogInfo(string message) { _logger.LogInfo((object)message); } public static void LogWarning(string message) { _logger.LogWarning((object)message); } public static void LogError(string message) { _logger.LogError((object)message); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _logger = ((BaseUnityPlugin)this).Logger; Configs.InitializeConfigs(); AssetsLoader.Start(); HarmonyInstance = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.raddude.sailadex"); bool flag = false; foreach (KeyValuePair pluginInfo in Chainloader.PluginInfos) { BepInPlugin metadata = pluginInfo.Value.Metadata; if (metadata.GUID.Equals("pr0skynesis.passagedude")) { LogInfo("PassageDude mod found"); flag = true; PassageDude.PatchMod(); } if (metadata.GUID.Equals("com.raddude.randomencounters") && metadata.Version >= new Version(2, 0, 0)) { LogInfo("RandomEncounters mod found"); RE_PluginInstance = pluginInfo.Value.Instance; AssetsLoader.LoadBridge(); Type type = AccessTools.TypeByName("EncounterTracker"); AccessTools.Method(type, "TrackEncounters", (Type[])null, (Type[])null).Invoke(null, null); } if (flag && (Object)(object)RE_PluginInstance != (Object)null) { break; } } } } public class PortsVisitedUI : MonoBehaviour { private TextMesh[] _portNameTMs; private TextMesh[] _portVisitedTMs; private Dictionary _portBadgeGOs; private Dictionary _visitedPorts; private Dictionary _portBadges; public static PortsVisitedUI Instance { get; private set; } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _visitedPorts = new Dictionary(); foreach (string allPort in Region.AllPorts) { _visitedPorts[allPort] = false; } _portBadges = new Dictionary(); foreach (string allBadgeName in Region.AllBadgeNames) { _portBadges[allBadgeName] = false; } } public void RegisterVisit(string portName) { if (!_visitedPorts.ContainsKey(portName)) { SAD_Plugin.LogWarning("Attempted to register visit to unknown port: " + portName); return; } if (!_visitedPorts[portName]) { _visitedPorts[portName] = true; CheckBadges(); } SAD_Plugin.LogDebug("Visited: " + portName); } public void UpdatePage() { UpdateTexts(); UpdateBadges(); } private void UpdateTexts() { int num = 0; foreach (KeyValuePair visitedPort in _visitedPorts) { if (num >= _portNameTMs.Length || num >= _portVisitedTMs.Length) { SAD_Plugin.LogWarning("Not enough TextMesh objects to display all ports"); break; } _portNameTMs[num].text = GetPortDisplayName(visitedPort.Key, visitedPort.Value); _portVisitedTMs[num].text = (visitedPort.Value ? "✓" : "✗"); num++; } } private string GetPortDisplayName(string portName, bool visited) { return (Configs.portNamesHidden.Value && !visited) ? "???" : portName; } public void CheckBadges() { foreach (Region allRegion in Region.AllRegions) { if (!_portBadges[allRegion.BadgeName] && allRegion.Ports.All((string p) => _visitedPorts[p])) { _portBadges[allRegion.BadgeName] = true; ShowBadgeNotification(allRegion.Name); } } if (!_portBadges["allPortsBadge"] && Region.AllPorts.All((string p) => _visitedPorts[p])) { _portBadges["allPortsBadge"] = true; ShowBadgeNotification("all"); } } private void ShowBadgeNotification(string region) { if (Configs.notificationsEnabled.Value) { string message = ((region != "all") ? ("Visited all\n" + region + " ports") : "Visited all ports"); NotificationUiQueue.Instance.QueueNotification(message); } } public void UpdateBadges() { foreach (KeyValuePair portBadge in _portBadges) { if (!_portBadgeGOs.ContainsKey(portBadge.Key)) { SAD_Plugin.LogWarning("Missing GameObject for badge: " + portBadge.Key); } else { _portBadgeGOs[portBadge.Key].SetActive(portBadge.Value); } } } public void SetUIElems(TextMesh[] portNameTMs, TextMesh[] portVisitedTMs, Dictionary portBadgeGOs) { _portNameTMs = portNameTMs; _portVisitedTMs = portVisitedTMs; _portBadgeGOs = portBadgeGOs; } public void LoadPortsVisitedUI() { ModData.GetDictEntry("Sail-a-dex.VisitedPorts", _visitedPorts); ModData.GetDictEntry("Sail-a-dex.PortBadges", _portBadges); } public void SavePortsVisitedUI() { ModData.AddDictEntry("Sail-a-dex.VisitedPorts", _visitedPorts); ModData.AddDictEntry("Sail-a-dex.PortBadges", _portBadges); } } public class StatsUI : MonoBehaviour { private Dictionary _statTMs; private Dictionary _floatStats; private Dictionary _intStats; private Dictionary _boolArrayStats; private Vector3 lastPosition; internal string lastPortVisited; private int trackerTimer; internal string lastStorm; private const int TRACKER_TIMER_VALUE = 1000; private const float MILES_CONVERSION_FACTOR = 137.487f; public static readonly string[] FloatStatNames = new string[4] { "CargoMass", "TotalMass", "UnderwayTime", "MilesSailed" }; public static readonly string[] IntStatNames = new string[13] { "UnderwayDay", "PortsVisited", "MissionsCompleted", "DrinksTaken", "FoodsEaten", "TimesSmoked", "TimesSlept", "StormsWeathered", "FlotsamEncounters", "DenseFogEncounters", "SeaLifeEncounters", "FishingBonanzaEncounters", "IntenseStormEncounters" }; private static readonly Dictionary> _randomEncounterStats = new Dictionary> { { "FlotsamEncounters", () => REConfigs.IsFlotsamEnabled }, { "DenseFogEncounters", () => REConfigs.IsDenseFogEnabled }, { "SeaLifeEncounters", () => REConfigs.IsSeaLifeModEnabled }, { "FishingBonanzaEncounters", () => REConfigs.IsFishingBonanzaEnabled }, { "IntenseStormEncounters", () => REConfigs.IsIntenseStormEnabled } }; public static StatsUI Instance { get; private set; } public bool IsUnderway { get; internal set; } public static IReadOnlyDictionary> RandomEncounterStats => _randomEncounterStats; public static List RandomEncounterStatYPos { get; set; } private void Awake() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; _floatStats = new Dictionary(); _intStats = new Dictionary(); _boolArrayStats = new Dictionary(); _statTMs = new Dictionary(); lastPosition = Vector3.zero; lastPortVisited = string.Empty; trackerTimer = 1000; lastStorm = string.Empty; IsUnderway = false; string[] floatStatNames = FloatStatNames; foreach (string text in floatStatNames) { _floatStats.Add(text, 0f); _floatStats.Add("current" + text, 0f); _floatStats.Add("record" + text, 0f); } string[] intStatNames = IntStatNames; foreach (string text2 in intStatNames) { _intStats.Add(text2, 0); _intStats.Add("current" + text2, 0); _intStats.Add("record" + text2, 0); } foreach (string transitCode in Region.TransitCodes) { _floatStats.Add("last" + transitCode + "TransitTime", 0f); _intStats.Add("last" + transitCode + "TransitDay", 0); _floatStats.Add("record" + transitCode + "TransitTime", 0f); _intStats.Add("record" + transitCode + "TransitDay", 0); } foreach (Region allRegion in Region.AllRegions) { _floatStats.Add(allRegion.Code + "UnderwayTime", 0f); _intStats.Add(allRegion.Code + "UnderwayDay", 0); _boolArrayStats.Add(allRegion.Code + "Transit", new bool[4]); } } public void RegisterCurrentMass() { Transform currentBoat = GameState.currentBoat; if (!((Object)(object)((currentBoat != null) ? currentBoat.parent : null) == (Object)null) || !((Object)(object)GameState.lastBoat == (Object)null)) { GameObject val = (((Object)(object)GameState.currentBoat != (Object)null) ? ((Component)GameState.currentBoat.parent).gameObject : ((Component)GameState.lastBoat).gameObject); _floatStats["currentCargoMass"] = (from item in val.GetComponent().GetPrivateField>("itemsOnBoat") where IsCargoItem(item) select item).Sum((ItemRigidbody item) => item.GetBody().mass); } } private bool IsCargoItem(ItemRigidbody item) { Good component = ((Component)item.GetShipItem()).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } string sizeDescription = component.sizeDescription; return sizeDescription.Contains("crate") || sizeDescription.Contains("package") || sizeDescription.Contains("barrel") || sizeDescription.Contains("bundle"); } public void RegisterTotalMass(float totalMass) { _floatStats["currentTotalMass"] = totalMass; } private void UpdateMassRecords() { if (_floatStats["recordCargoMass"] < _floatStats["currentCargoMass"]) { _floatStats["recordCargoMass"] = _floatStats["currentCargoMass"]; } if (_floatStats["recordTotalMass"] < _floatStats["currentTotalMass"]) { _floatStats["recordTotalMass"] = _floatStats["currentTotalMass"]; } } public void RegisterUnderway(string islandName) { if (string.IsNullOrEmpty(islandName)) { return; } IsUnderway = true; UpdateMassRecords(); ResetUnderwayTimers(); if (islandName == "island 18 M (HappyBay)") { return; } foreach (Region allRegion in Region.AllRegions) { if (allRegion.Islands.Contains(islandName)) { TrackRegionUnderway(allRegion.Code); break; } } } private void ResetUnderwayTimers() { _floatStats["UnderwayTime"] = Sun.sun.globalTime; _intStats["UnderwayDay"] = GameState.day; } private void TrackRegionUnderway(string regionCode) { _floatStats[regionCode + "UnderwayTime"] = Sun.sun.globalTime; _intStats[regionCode + "UnderwayDay"] = GameState.day; for (int i = 0; i < Region.AllRegions.Count; i++) { _boolArrayStats[regionCode + "Transit"][i] = false; } } private void UpdateUnderwayRecords() { if (_intStats["currentUnderwayDay"] > _intStats["recordUnderwayDay"] || (_intStats["currentUnderwayDay"] == _intStats["recordUnderwayDay"] && _floatStats["currentUnderwayTime"] > _floatStats["recordUnderwayTime"])) { _intStats["recordUnderwayDay"] = _intStats["currentUnderwayDay"]; _floatStats["recordUnderwayTime"] = _floatStats["currentUnderwayTime"]; } _floatStats["UnderwayTime"] = 0f; _intStats["UnderwayDay"] = 0; } public void RegisterMoored(string islandName) { if (!Utility.IsNullOrWhiteSpace(islandName)) { IsUnderway = false; UpdateStats(); UpdateUnderwayRecords(); if (!islandName.Equals("island 18 M (HappyBay)")) { ProcessRegionalArrival(islandName); } } } private void ProcessRegionalArrival(string islandName) { foreach (Region allRegion in Region.AllRegions) { if (!allRegion.Islands.Contains(islandName)) { continue; } { foreach (Region allRegion2 in Region.AllRegions) { if (!(allRegion2.Code == allRegion.Code)) { CheckPossibleTransit(allRegion2.Code, allRegion.Code, allRegion.Index); } } break; } } } private void CheckPossibleTransit(string departureRegion, string arrivalRegion, int arrivalIndex) { string transitCode = departureRegion + arrivalRegion; bool flag = _floatStats[departureRegion + "UnderwayTime"] > 0f || _intStats[departureRegion + "UnderwayDay"] > 0; bool flag2 = _boolArrayStats[departureRegion + "Transit"][arrivalIndex]; if (!flag2 && flag) { CheckTransitTime(departureRegion, transitCode, arrivalIndex); } } public void CheckTransitTime(string underwayKey, string transitCode, int destInt) { int num = GameState.day - _intStats[underwayKey + "UnderwayDay"]; float num2 = Sun.sun.globalTime - _floatStats[underwayKey + "UnderwayTime"]; if (num2 < 0f) { num2 += 24f; num--; } _intStats["last" + transitCode + "TransitDay"] = num; _floatStats["last" + transitCode + "TransitTime"] = num2; if ((_intStats["record" + transitCode + "TransitDay"] == 0 && _floatStats["record" + transitCode + "TransitTime"] == 0f) || _intStats["record" + transitCode + "TransitDay"] > num || (_intStats["record" + transitCode + "TransitDay"] == num && _floatStats["record" + transitCode + "TransitTime"] > num2)) { _intStats["record" + transitCode + "TransitDay"] = num; _floatStats["record" + transitCode + "TransitTime"] = num2; if (Configs.notificationsEnabled.Value) { NotificationUiQueue.Instance.QueueNotification("Fastest " + FormatTransitName(transitCode) + " time"); } } _boolArrayStats[underwayKey + "Transit"][destInt] = true; } public void PlayerTeleported() { SAD_Plugin.LogInfo("Player teleported, resetting current transits"); foreach (Region allRegion in Region.AllRegions) { int num = 0; for (int i = 0; i < Region.AllRegions.Count; i++) { if (i != num) { _boolArrayStats[allRegion.Code + "Transit"][i] = true; } num++; } } } public void TrackDistance() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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 (!((Object)(object)GameState.currentBoat == (Object)null) && IsUnderway) { Vector3 globeCoords = FloatingOriginManager.instance.GetGlobeCoords(GameState.currentBoat); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(globeCoords.x, 0f, globeCoords.z); if (lastPosition == Vector3.zero) { lastPosition = val; return; } if (trackerTimer > 1) { trackerTimer--; return; } _floatStats["currentMilesSailed"] += Vector3.Distance(lastPosition, val) * 137.487f; lastPosition = val; trackerTimer = 1000; } } public void UpdateMilesText() { _floatStats["MilesSailed"] = _floatStats["currentMilesSailed"]; } public void IncrementIntStat(string statName) { if (!_intStats.ContainsKey("current" + statName)) { _intStats.Add("current" + statName, 0); } _intStats["current" + statName]++; } public void IncrementPortVisited(string port) { if (!(lastPortVisited == port)) { IncrementIntStat("PortsVisited"); lastPortVisited = port; } } public void IncrementStormsWeathered() { string name = ((Object)WeatherStorms.instance.GetCurrentStorm()).name; if (!(lastStorm == name)) { SAD_Plugin.LogDebug("Weathering " + name); IncrementIntStat("StormsWeathered"); lastStorm = name; } } public void ClearLastStorm() { if (!Utility.IsNullOrWhiteSpace(lastStorm)) { SAD_Plugin.LogDebug("Storm cleared"); lastStorm = string.Empty; } } public void UpdatePage() { UpdateStats(); UpdateTexts(); } private void UpdateStats() { if (_intStats["UnderwayDay"] > 0 || _floatStats["UnderwayTime"] > 0f) { _intStats["currentUnderwayDay"] = GameState.day - _intStats["UnderwayDay"]; _floatStats["currentUnderwayTime"] = Sun.sun.globalTime - _floatStats["UnderwayTime"]; } if (_floatStats["currentUnderwayTime"] < 0f) { _floatStats["currentUnderwayTime"] += 24f; _intStats["currentUnderwayDay"]--; } } private void UpdateTexts() { UpdateFloatTexts(); UpdateIntTexts(); UpdateTransitTexts(); } private void UpdateFloatTexts() { string[] floatStatNames = FloatStatNames; foreach (string text in floatStatNames) { switch (text) { case "UnderwayTime": _statTMs[text].text = FormatStatName(text); _statTMs["currentUnderwayTime"].text = FormatUnderwayTime(_intStats["currentUnderwayDay"], _floatStats["currentUnderwayTime"]); _statTMs["recordUnderwayTime"].text = FormatUnderwayTime(_intStats["recordUnderwayDay"], _floatStats["recordUnderwayTime"]); break; case "CargoMass": _statTMs[text].text = FormatStatName(text); _statTMs["currentCargoMass"].text = ((_floatStats["currentCargoMass"] == 0f) ? "-" : string.Format("{0:#,##0.#} lbs", _floatStats["currentCargoMass"])); _statTMs["recordCargoMass"].text = ((_floatStats["recordCargoMass"] == 0f) ? "-" : string.Format("{0:#,##0.#} lbs", _floatStats["recordCargoMass"])); break; case "TotalMass": _statTMs[text].text = FormatStatName(text); _statTMs["currentTotalMass"].text = ((_floatStats["currentTotalMass"] == 0f) ? "-" : string.Format("{0:#,##0.#} lbs", _floatStats["currentTotalMass"])); _statTMs["recordTotalMass"].text = ((_floatStats["recordTotalMass"] == 0f) ? "-" : string.Format("{0:#,##0.#} lbs", _floatStats["recordTotalMass"])); break; case "MilesSailed": _statTMs[text].text = FormatStatName(text); if (Configs.updateMilesSailed.Value == "realtime") { _statTMs["currentMilesSailed"].text = string.Format("{0:#,##0.#}", _floatStats["currentMilesSailed"]); } else { _statTMs["currentMilesSailed"].text = string.Format("{0:#,##0.#}", _floatStats["MilesSailed"]); } break; default: _statTMs[text].text = FormatStatName(text); _statTMs["current" + text].text = _floatStats["current" + text].ToString(); _statTMs["record" + text].text = _floatStats["record" + text].ToString(); break; } } } private void UpdateIntTexts() { Queue posQueue = new Queue(RandomEncounterStatYPos); string[] intStatNames = IntStatNames; foreach (string text in intStatNames) { if (!(text == "UnderwayDay")) { if (_randomEncounterStats.ContainsKey(text)) { PositionRandomEnounterStat(text, posQueue); } _statTMs[text].text = FormatStatName(text); _statTMs["current" + text].text = string.Format("{0:#,##0}", _intStats["current" + text]); } } } private void UpdateTransitTexts() { foreach (string transitCode in Region.TransitCodes) { _statTMs[transitCode].text = FormatTransitName(transitCode); _statTMs["last" + transitCode].text = FormatUnderwayTime(_intStats["last" + transitCode + "TransitDay"], _floatStats["last" + transitCode + "TransitTime"]); _statTMs["record" + transitCode].text = FormatUnderwayTime(_intStats["record" + transitCode + "TransitDay"], _floatStats["record" + transitCode + "TransitTime"]); } } private string FormatUnderwayTime(int underwayDay, float underwayTime) { if (underwayDay == 0 && underwayTime == 0f) { return "-"; } if (underwayDay > 0) { string arg = ((underwayDay == 1) ? "Day" : "Days"); return $"{underwayDay} {arg} {underwayTime:0.0} Hours"; } return $"{underwayTime:0.0} Hours"; } private string FormatStatName(string name) { if (name.Contains("Encounters")) { name = name.Replace("Encounters", "Encs"); } return Regex.Replace(name, "([a-z])([A-Z])", "$1 $2"); } private string FormatTransitName(string name) { string text = FormatStatName(name); return text.ToUpper().Insert(text.IndexOf(' '), " to"); } private void PositionRandomEnounterStat(string stat, Queue posQueue) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00b8: 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) if ((Object)(object)SAD_Plugin.RE_PluginInstance == (Object)null || !_randomEncounterStats[stat]()) { ((Component)_statTMs[stat]).gameObject.SetActive(false); } else if ((Object)(object)SAD_Plugin.RE_PluginInstance != (Object)null && _randomEncounterStats[stat]()) { ((Component)_statTMs[stat]).gameObject.SetActive(true); Vector3 localPosition = ((Component)_statTMs[stat]).transform.localPosition; ((Component)_statTMs[stat]).transform.localPosition = new Vector3(localPosition.x, posQueue.Dequeue(), localPosition.z); } } public void SetUIElems(Dictionary statTMs) { _statTMs = statTMs; } public void LoadStatsUI() { ModData.GetDictEntry("Sail-a-dex.IntStats", _intStats); ModData.GetDictEntry("Sail-a-dex.FloatStats", _floatStats); ModData.GetDictEntry("Sail-a-dex.BoolArrayStats", _boolArrayStats); IsUnderway = ModData.GetEntry("Sail-a-dex.IsUnderway"); lastPortVisited = ModData.GetEntry("Sail-a-dex.LastPortVisited"); lastStorm = ModData.GetEntry("Sail-a-dex.LastStorm"); } public void SaveStatsUI() { ModData.AddDictEntry("Sail-a-dex.IntStats", _intStats); ModData.AddDictEntry("Sail-a-dex.FloatStats", _floatStats); ModData.AddDictEntry("Sail-a-dex.BoolArrayStats", _boolArrayStats); ModData.AddEntry("Sail-a-dex.IsUnderway", IsUnderway); ModData.AddEntry("Sail-a-dex.LastPortVisited", lastPortVisited); ModData.AddEntry("Sail-a-dex.LastStorm", lastStorm); } }