Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of TheRegulars v1.0.0
Mods/TheRegulars.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.Json; using HarmonyLib; using Il2CppFishNet; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.Core.Items.Framework; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Effects; using Il2CppScheduleOne.Events; using Il2CppScheduleOne.GameTime; using Il2CppScheduleOne.ItemFramework; using Il2CppScheduleOne.Levelling; using Il2CppScheduleOne.Map; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.NPCs.Framework; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.PlayerScripts; using Il2CppScheduleOne.Product; using Il2CppScheduleOne.SpecialCustomers; using Il2CppScheduleOne.SpecialCustomers.UI; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Phone; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using TheRegulars; using TheRegulars.Data; using TheRegulars.Engine; using TheRegulars.Phone; using TheRegulars.Phone.Kit; using TheRegulars.Services; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(RegularsMod), "The Regulars", "1.0.0", "thedoc15", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("TheRegulars")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c14b50228f911f5e49af3775cc25daeb45a3f088")] [assembly: AssemblyProduct("TheRegulars")] [assembly: AssemblyTitle("TheRegulars")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 TheRegulars { public static class Guard { public static class Features { public const string FixFirstVisit = "FixFirstVisit"; public const string SleepWatchdog = "SleepWatchdog"; public const string LateJoinSync = "LateJoinSync"; public const string CoopMapPins = "CoopMapPins"; public const string Alerts = "Alerts"; public const string Tunables = "Tunables"; public const string Steering = "Steering"; public const string CallIn = "CallIn"; public const string MarkOnMap = "MarkOnMap"; public const string Snapshot = "Snapshot"; public const string Engine = "Engine"; public const string DebugDump = "DebugDump"; public const string Faces = "Faces"; } private static readonly List<string> Paused = new List<string>(); private static readonly HashSet<string> PausedSet = new HashSet<string>(StringComparer.Ordinal); private static readonly HashSet<Delegate> BrokenListeners = new HashSet<Delegate>(); private static string[] _pausedView = Array.Empty<string>(); public static IReadOnlyList<string> PausedFeatures => _pausedView; public static event Action<string> FeatureDisabled; public static bool IsPaused(string feature) { if (feature != null) { return PausedSet.Contains(feature); } return false; } public static bool Run(string feature, Action body) { if (body == null || IsPaused(feature)) { return false; } try { body(); return true; } catch (Exception ex) { Trip(feature, ex); return false; } } public static T Run<T>(string feature, Func<T> body, T fallback) { if (body == null || IsPaused(feature)) { return fallback; } try { return body(); } catch (Exception ex) { Trip(feature, ex); return fallback; } } public static void Trip(string feature, Exception ex) { string name = (string.IsNullOrEmpty(feature) ? "Unknown" : feature); try { if (!PausedSet.Add(name)) { return; } Paused.Add(name); _pausedView = Paused.ToArray(); Log.Error("\"" + name + "\" hit an error and is paused until you restart the game. The game itself keeps running normally.", ex); } catch { } RaiseEach("Guard.FeatureDisabled", Guard.FeatureDisabled, delegate(Delegate h) { ((Action<string>)h)(name); }); } internal static void RaiseEach(string eventName, Delegate multicast, Action<Delegate> invoke) { if ((object)multicast == null || invoke == null) { return; } Delegate[] invocationList; try { invocationList = multicast.GetInvocationList(); } catch { return; } foreach (Delegate obj2 in invocationList) { if ((object)obj2 == null || BrokenListeners.Contains(obj2)) { continue; } try { invoke(obj2); } catch (Exception ex) { BrokenListeners.Add(obj2); try { Log.Error("A listener of " + eventName + " (" + Describe(obj2) + ") failed and was switched off.", ex); } catch { } } } } private static string Describe(Delegate d) { try { MethodInfo method = d.Method; return ((method.DeclaringType != null) ? (method.DeclaringType.FullName + ".") : string.Empty) + method.Name; } catch { return "unknown listener"; } } } public static class ModInfo { public const string Name = "The Regulars"; public const string Version = "1.0.0"; public const string Author = "thedoc15"; public const string NexusUrl = ""; } public sealed class RegularsMod : MelonMod { public override void OnInitializeMelon() { Settings.Init(); try { ServiceHost.Init(); Steering.CanServe = Products.CanServe; Hooks.NoteRepair = History.NoteRepair; Hooks.CrewIcon = Faces.CrewIcon; Hooks.VisitCash = delegate(string id) { VisitRecord current = History.Current; return (current == null || !(current.CrewId == id)) ? (-1) : current.Cash; }; } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("Faces/products/history could not start; the fixes still run.", ex); } try { PhoneSupport.Init(); } catch (Exception ex2) { ((MelonBase)this).LoggerInstance.Error("The phone app could not start; the fixes still run.", ex2); } ((MelonBase)this).LoggerInstance.Msg("The Regulars 1.0.0 loaded"); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { if (sceneName == "Main") { TheRegulars.Engine.Engine.Start(); ServiceHost.Start(); } } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { if (sceneName == "Main") { StopAll(); } } public override void OnUpdate() { try { Settings.Tick(); } catch { } TheRegulars.Engine.Engine.Update(); } private static void StopAll() { TheRegulars.Engine.Engine.Stop(); try { ServiceHost.Stop(); } catch (Exception ex) { MelonLogger.Error("Services stop failed", ex); } } public override void OnApplicationQuit() { StopAll(); Settings.Flush(); } public override void OnDeinitializeMelon() { StopAll(); Settings.Flush(); } } public static class Settings { public static class Keys { public const string FixFirstVisit = "FixFirstVisit"; public const string SleepWatchdog = "SleepWatchdog"; public const string LateJoinSync = "LateJoinSync"; public const string CoopMapPins = "CoopMapPins"; public const string Alerts = "Alerts"; public const string FirstVisitDelay = "FirstVisitDelay"; public const string NightsBetweenVisits = "NightsBetweenVisits"; public const string GuaranteedWhenDue = "GuaranteedWhenDue"; public const string WarningNights = "WarningNights"; public const string StayNights = "StayNights"; public const string OrderSizePercent = "OrderSizePercent"; public const string SkippedCrews = "SkippedCrews"; public const string OnlyServableCrews = "OnlyServableCrews"; public const string AllowCallIn = "AllowCallIn"; public const string DebugKey = "DebugKey"; } public const string CategoryId = "TheRegulars"; public const string FileName = "TheRegulars.cfg"; public const int GameFirstVisitDelay = 7; public const int GameNightsBetweenMin = 4; public const int GameNightsBetweenMax = 8; public const int GameWarningNights = 3; public const int GameStayNights = 3; public const int GameOrderSizePercent = 100; private const long SaveDelayMs = 500L; private static MelonPreferences_Category _category; private static MelonPreferences_Entry<bool> _fixFirstVisit; private static MelonPreferences_Entry<bool> _sleepWatchdog; private static MelonPreferences_Entry<bool> _lateJoinSync; private static MelonPreferences_Entry<bool> _coopMapPins; private static MelonPreferences_Entry<bool> _alerts; private static MelonPreferences_Entry<int> _firstVisitDelay; private static MelonPreferences_Entry<int> _nightsBetweenVisits; private static MelonPreferences_Entry<bool> _guaranteedWhenDue; private static MelonPreferences_Entry<int> _warningNights; private static MelonPreferences_Entry<int> _stayNights; private static MelonPreferences_Entry<int> _orderSizePercent; private static MelonPreferences_Entry<string> _skippedCrews; private static MelonPreferences_Entry<bool> _onlyServableCrews; private static MelonPreferences_Entry<bool> _allowCallIn; private static MelonPreferences_Entry<bool> _debugKey; private static string[] _skippedView = Array.Empty<string>(); private static readonly Stopwatch Clock = Stopwatch.StartNew(); private static bool _dirty; private static long _saveDueMs; private static int _batchDepth; private static bool _batchChanged; public static bool IsLoaded => _category != null; public static bool FixFirstVisit { get { return Get(_fixFirstVisit, fallback: true); } set { Set(_fixFirstVisit, value); } } public static bool SleepWatchdog { get { return Get(_sleepWatchdog, fallback: true); } set { Set(_sleepWatchdog, value); } } public static bool LateJoinSync { get { return Get(_lateJoinSync, fallback: true); } set { Set(_lateJoinSync, value); } } public static bool CoopMapPins { get { return Get(_coopMapPins, fallback: true); } set { Set(_coopMapPins, value); } } public static bool Alerts { get { return Get(_alerts, fallback: true); } set { Set(_alerts, value); } } public static int FirstVisitDelay { get { return Get(_firstVisitDelay, 0); } set { Set(_firstVisitDelay, ClampOverride(value, 14)); } } public static int NightsBetweenVisits { get { return Get(_nightsBetweenVisits, 0); } set { Set(_nightsBetweenVisits, ClampOverride(value, 14)); } } public static bool GuaranteedWhenDue { get { return Get(_guaranteedWhenDue, fallback: false); } set { Set(_guaranteedWhenDue, value); } } public static int WarningNights { get { return Get(_warningNights, 0); } set { Set(_warningNights, ClampOverride(value, 7)); } } public static int StayNights { get { return Get(_stayNights, 0); } set { Set(_stayNights, ClampOverride(value, 7)); } } public static int OrderSizePercent { get { return Get(_orderSizePercent, 100); } set { Set(_orderSizePercent, NormalizePercent(value)); } } public static string SkippedCrews { get { return Get(_skippedCrews, string.Empty); } set { Set(_skippedCrews, NormalizeCsv(value)); } } public static bool OnlyServableCrews { get { return Get(_onlyServableCrews, fallback: false); } set { Set(_onlyServableCrews, value); } } public static bool AllowCallIn { get { return Get(_allowCallIn, fallback: true); } set { Set(_allowCallIn, value); } } public static bool DebugKey { get { return Get(_debugKey, fallback: false); } set { Set(_debugKey, value); } } public static IReadOnlyList<string> SkippedCrewIds => _skippedView; public static event Action Changed; public static bool IsCrewSkipped(string crewId) { if (string.IsNullOrEmpty(crewId)) { return false; } string[] skippedView = _skippedView; for (int i = 0; i < skippedView.Length; i++) { if (string.Equals(skippedView[i], crewId, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static void SetCrewSkipped(string crewId, bool skipped) { if (string.IsNullOrWhiteSpace(crewId)) { return; } string item = crewId.Trim().ToLowerInvariant(); List<string> list = new List<string>(_skippedView); bool flag = list.Contains(item); if (skipped && !flag) { list.Add(item); } else { if (!(!skipped && flag)) { return; } list.Remove(item); } SkippedCrews = string.Join(",", list); } public static bool IsHostOnly(string key) { switch (key) { case "CoopMapPins": case "Alerts": return false; case "AllowCallIn": case "FixFirstVisit": case "SleepWatchdog": case "WarningNights": case "LateJoinSync": case "SkippedCrews": case "GuaranteedWhenDue": case "OnlyServableCrews": case "FirstVisitDelay": case "NightsBetweenVisits": case "StayNights": case "OrderSizePercent": return true; default: return false; } } public static void ResetToGame() { _batchDepth++; try { FirstVisitDelay = 0; NightsBetweenVisits = 0; GuaranteedWhenDue = false; WarningNights = 0; StayNights = 0; OrderSizePercent = 100; SkippedCrews = string.Empty; OnlyServableCrews = false; } finally { _batchDepth--; } if (_batchDepth == 0 && _batchChanged) { _batchChanged = false; RaiseChanged(); } } public static void Init() { if (_category != null) { return; } try { string text = Path.Combine(MelonEnvironment.UserDataDirectory, "TheRegulars.cfg"); bool num = File.Exists(text); _category = MelonPreferences.CreateCategory("TheRegulars", "The Regulars"); _category.SetFilePath(text, true, false); _fixFirstVisit = _category.CreateEntry<bool>("FixFirstVisit", true, "Fix the first visit", "Repairs the special-customer visit the game breaks on new saves (the \"Hippies\" name bug). Host only.", false, false, (ValueValidator)null, (string)null); _sleepWatchdog = _category.CreateEntry<bool>("SleepWatchdog", true, "Sleep watchdog", "If the game silently skips special customers on a night, move them along anyway. Host only.", false, false, (ValueValidator)null, (string)null); _lateJoinSync = _category.CreateEntry<bool>("LateJoinSync", true, "Sync late joiners", "Tell players who join mid-game where the special customers are at. Host only.", false, false, (ValueValidator)null, (string)null); _coopMapPins = _category.CreateEntry<bool>("CoopMapPins", true, "Map pin for co-op players", "Show the crew's camp on your map when you are not the host (the game only gives the host a pin).", false, false, (ValueValidator)null, (string)null); _alerts = _category.CreateEntry<bool>("Alerts", true, "Alerts", "Game notifications when a crew is coming, arrives, has its last night, or leaves.", false, false, (ValueValidator)null, (string)null); _firstVisitDelay = _category.CreateEntry<int>("FirstVisitDelay", 0, "First visit delay", "Sleeps before the first crew can be picked on a new save. 0 = game (7), else 1 to 14. Host only.", false, false, (ValueValidator)null, (string)null); _nightsBetweenVisits = _category.CreateEntry<int>("NightsBetweenVisits", 0, "Nights between visits", "Sleeps after a crew leaves before the next pick. 0 = game (4 to 8), else 1 to 14. Host only.", false, false, (ValueValidator)null, (string)null); _guaranteedWhenDue = _category.CreateEntry<bool>("GuaranteedWhenDue", false, "Skip the luck roll", "After the wait, the game only has a 25% chance each night to pick a crew (+10% per miss). On = one comes the first night. Host only.", false, false, (ValueValidator)null, (string)null); _warningNights = _category.CreateEntry<int>("WarningNights", 0, "Warning nights", "Sleeps between \"coming to town\" and arrival. 0 = game (3), else 1 to 7. Host only.", false, false, (ValueValidator)null, (string)null); _stayNights = _category.CreateEntry<int>("StayNights", 0, "Stay nights", "Nights a crew stays in town. 0 = game (3), else 1 to 7. Host only.", false, false, (ValueValidator)null, (string)null); _orderSizePercent = _category.CreateEntry<int>("OrderSizePercent", 100, "Order size", "How much crews buy per day, in percent of the game's amount. 50 to 300 in steps of 25. Host only.", false, false, (ValueValidator)null, (string)null); _skippedCrews = _category.CreateEntry<string>("SkippedCrews", string.Empty, "Skipped crews", "Comma-separated crew ids the game should not pick (bikers, businessmen, hippies, partybus). Host only.", false, false, (ValueValidator)null, (string)null); _onlyServableCrews = _category.CreateEntry<bool>("OnlyServableCrews", false, "Only crews I can serve", "Skip crews whose drugs you can't make yet. Host only.", false, false, (ValueValidator)null, (string)null); _allowCallIn = _category.CreateEntry<bool>("AllowCallIn", true, "Call-ins and send-aways", "Allow \"Call them in\" and \"Send them away\" in the phone app. Host only.", false, false, (ValueValidator)null, (string)null); _debugKey = _category.CreateEntry<bool>("DebugKey", false, "Debug dump key (F10)", "Press F10 in game to write a status report to MelonLoader/Latest.log (only needed for bug reports).", false, false, (ValueValidator)null, (string)null); Sanitize(); if (!num || _dirty) { SaveNow(); } } catch (Exception ex) { Log.Error("Settings could not be loaded; the game's own behaviour is used.", ex); } } public static void Tick() { if (_dirty && Clock.ElapsedMilliseconds >= _saveDueMs) { SaveNow(); } } public static void Flush() { if (_dirty) { SaveNow(); } } private static T Get<T>(MelonPreferences_Entry<T> entry, T fallback) { try { return (entry != null) ? entry.Value : fallback; } catch { return fallback; } } private static void Set<T>(MelonPreferences_Entry<T> entry, T value) { if (entry != null && !EqualityComparer<T>.Default.Equals(entry.Value, value)) { entry.Value = value; if ((object)entry == _skippedCrews) { RebuildSkippedView(); } MarkDirty(); if (_batchDepth > 0) { _batchChanged = true; } else { RaiseChanged(); } } } private static void MarkDirty() { _dirty = true; _saveDueMs = Clock.ElapsedMilliseconds + 500; } private static void SaveNow() { _dirty = false; try { MelonPreferences_Category category = _category; if (category != null) { category.SaveToFile(false); } } catch (Exception ex) { Log.Error("Settings could not be saved to UserData/TheRegulars.cfg.", ex); } } private static void RaiseChanged() { Guard.RaiseEach("Settings.Changed", Settings.Changed, delegate(Delegate h) { ((Action)h)(); }); } private static void Sanitize() { SanitizeInt(_firstVisitDelay, ClampOverride(_firstVisitDelay.Value, 14)); SanitizeInt(_nightsBetweenVisits, ClampOverride(_nightsBetweenVisits.Value, 14)); SanitizeInt(_warningNights, ClampOverride(_warningNights.Value, 7)); SanitizeInt(_stayNights, ClampOverride(_stayNights.Value, 7)); SanitizeInt(_orderSizePercent, NormalizePercent(_orderSizePercent.Value)); string text = NormalizeCsv(_skippedCrews.Value); if (!string.Equals(text, _skippedCrews.Value, StringComparison.Ordinal)) { _skippedCrews.Value = text; MarkDirty(); } RebuildSkippedView(); } private static void SanitizeInt(MelonPreferences_Entry<int> entry, int sane) { if (entry.Value != sane) { entry.Value = sane; MarkDirty(); } } private static int ClampOverride(int value, int max) { if (value <= 0) { return 0; } if (value <= max) { return value; } return max; } private static int NormalizePercent(int value) { int num = (int)Math.Round((double)value / 25.0, MidpointRounding.AwayFromZero) * 25; if (num < 50) { return 50; } if (num <= 300) { return num; } return 300; } private static string NormalizeCsv(string csv) { if (string.IsNullOrWhiteSpace(csv)) { return string.Empty; } IEnumerable<string> values = (from s in csv.Split(new char[6] { ',', ';', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) select s.Trim().ToLowerInvariant() into s where s.Length > 0 select s).Distinct<string>(StringComparer.Ordinal); return string.Join(",", values); } private static void RebuildSkippedView() { string text = Get(_skippedCrews, string.Empty); _skippedView = (string.IsNullOrEmpty(text) ? Array.Empty<string>() : text.Split(',')); } } } namespace TheRegulars.Services { public static class Faces { private static Sprite _vanIconCache; private static bool _vanIconLookupFailed; public static event Action<string> Updated; internal static void Init() { PurgeOldRenderCache(); } internal static void Start() { } internal static void Stop() { _vanIconCache = null; _vanIconLookupFailed = false; } public static Sprite Get(string npcId) { return null; } public static Sprite CrewIcon(string crewId) { return VanIcon(); } private static Sprite VanIcon() { if ((Object)(object)_vanIconCache != (Object)null) { return _vanIconCache; } if (_vanIconLookupFailed) { return null; } try { IncomingSpecialCustomerInfoPopup val = Object.FindObjectOfType<IncomingSpecialCustomerInfoPopup>(); if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val)) { Image groupIconImage = val._groupIconImage; if ((Object)(object)groupIconImage != (Object)null && Object.op_Implicit((Object)(object)groupIconImage) && (Object)(object)groupIconImage.sprite != (Object)null) { _vanIconCache = groupIconImage.sprite; return _vanIconCache; } } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] Faces: van icon lookup failed: " + ex.Message); } _vanIconLookupFailed = true; return null; } private static void PurgeOldRenderCache() { try { string path = Path.Combine(MelonEnvironment.UserDataDirectory, "TheRegulars"); int num = PurgeCacheFolder(Path.Combine(path, "faces")) + PurgeCacheFolder(Path.Combine(path, "faces-v2")); if (num > 0) { MelonLogger.Msg($"[Faces] purged {num} stale render(s) from the old runtime-render cache."); } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] Faces: could not purge the old faces cache: " + ex.Message); } } private static int PurgeCacheFolder(string dir) { if (!Directory.Exists(dir)) { return 0; } string[] files = Directory.GetFiles(dir, "*.png"); string[] array = files; for (int i = 0; i < array.Length; i++) { File.Delete(array[i]); } if (Directory.GetFileSystemEntries(dir).Length == 0) { Directory.Delete(dir); } return files.Length; } } public sealed class VisitRecord { public string CrewId; public int ArrivedDay; public int LeftDay; public int Deals; public int Units; public long Cash; } public static class History { public sealed class Document { public int Version = 1; public List<VisitRecord> Visits = new List<VisitRecord>(); public VisitRecord Current; public int RepairsThisSave; } private const float DebounceSeconds = 2f; private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions { WriteIndented = true, IncludeFields = true }; private static Document _doc; private static string _saveKey; private static bool _loggedCorrupt; private static object _tickToken; private static float _dirtySecondsRemaining = -1f; public static IReadOnlyList<VisitRecord> Visits { get { try { EnsureLoaded(); return _doc.Visits; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.Visits threw: " + ex.Message); return Array.Empty<VisitRecord>(); } } } public static VisitRecord Current { get { try { EnsureLoaded(); return _doc.Current; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.Current threw: " + ex.Message); return null; } } } public static int RepairsThisSave { get { try { EnsureLoaded(); return _doc.RepairsThisSave; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.RepairsThisSave threw: " + ex.Message); return 0; } } } public static event Action Changed; internal static void Start() { CrewEvents.Arrived += OnArrived; CrewEvents.Left += OnLeft; CrewEvents.Deal += OnDeal; CrewEvents.SceneReady += OnSceneReady; if (_tickToken == null) { try { _tickToken = MelonCoroutines.Start(TickLoop()); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: could not start the flush timer: " + ex.Message); } } } internal static void Stop() { CrewEvents.Arrived -= OnArrived; CrewEvents.Left -= OnLeft; CrewEvents.Deal -= OnDeal; CrewEvents.SceneReady -= OnSceneReady; if (_tickToken != null) { try { MelonCoroutines.Stop(_tickToken); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: error stopping the flush timer: " + ex.Message); } _tickToken = null; } SafeFlush(); _doc = null; _saveKey = null; _loggedCorrupt = false; _dirtySecondsRemaining = -1f; } public static long TotalFrom(string crewId) { try { EnsureLoaded(); if (string.IsNullOrEmpty(crewId)) { return 0L; } long num = 0L; foreach (VisitRecord visit in _doc.Visits) { if (string.Equals(visit.CrewId, crewId, StringComparison.OrdinalIgnoreCase)) { num += visit.Cash; } } if (_doc.Current != null && string.Equals(_doc.Current.CrewId, crewId, StringComparison.OrdinalIgnoreCase)) { num += _doc.Current.Cash; } return num; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.TotalFrom threw: " + ex.Message); return 0L; } } public static void NoteRepair() { try { EnsureLoaded(); _doc.RepairsThisSave++; MarkDirty(); RaiseChanged(); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.NoteRepair threw: " + ex.Message); } } private static void OnArrived(string crewId) { try { if (!string.IsNullOrEmpty(crewId)) { EnsureLoaded(); if (_doc.Current != null && !string.Equals(_doc.Current.CrewId, crewId, StringComparison.OrdinalIgnoreCase)) { CloseCurrent(unknownLeftDay: true); } if (_doc.Current == null) { _doc.Current = new VisitRecord { CrewId = crewId, ArrivedDay = CurrentGameDay(), LeftDay = -1 }; MarkDirty(); RaiseChanged(); } } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: Arrived handler threw: " + ex.Message); } } private static void OnLeft(string crewId) { try { EnsureLoaded(); if (_doc.Current != null && (string.IsNullOrEmpty(crewId) || string.Equals(_doc.Current.CrewId, crewId, StringComparison.OrdinalIgnoreCase))) { CloseCurrent(unknownLeftDay: false); MarkDirty(); RaiseChanged(); } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: Left handler threw: " + ex.Message); } } private static void OnDeal(DealInfo deal) { try { if (deal != null && deal.BySelf) { EnsureLoaded(); if (_doc.Current == null) { _doc.Current = new VisitRecord { CrewId = deal.CrewId, ArrivedDay = -1, LeftDay = -1 }; } else if (!string.Equals(_doc.Current.CrewId, deal.CrewId, StringComparison.OrdinalIgnoreCase)) { return; } _doc.Current.Deals++; _doc.Current.Units += deal.Units; _doc.Current.Cash += deal.Cash; MarkDirty(); RaiseChanged(); } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: Deal handler threw: " + ex.Message); } } private static void OnSceneReady() { try { EnsureLoaded(); Snapshot now = Crews.Now; if (now != null && now.Phase == CrewPhase.InTown && !string.IsNullOrEmpty(now.ActiveCrewId)) { if (_doc.Current != null && !string.Equals(_doc.Current.CrewId, now.ActiveCrewId, StringComparison.OrdinalIgnoreCase)) { CloseCurrent(unknownLeftDay: true); } if (_doc.Current == null) { _doc.Current = new VisitRecord { CrewId = now.ActiveCrewId, ArrivedDay = -1, LeftDay = -1 }; MarkDirty(); RaiseChanged(); } } } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: SceneReady handler threw: " + ex.Message); } } private static void CloseCurrent(bool unknownLeftDay) { VisitRecord current = _doc.Current; if (current != null) { current.LeftDay = (unknownLeftDay ? (-1) : CurrentGameDay()); _doc.Visits.Insert(0, current); _doc.Current = null; } } private static int CurrentGameDay() { return Crews.Now?.GameDay ?? (-1); } private static void RaiseChanged() { try { History.Changed?.Invoke(); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History.Changed handler threw: " + ex.Message); } } private static void MarkDirty() { _dirtySecondsRemaining = 2f; } private static IEnumerator TickLoop() { while (true) { yield return null; if (!(_dirtySecondsRemaining < 0f)) { _dirtySecondsRemaining -= Time.unscaledDeltaTime; if (_dirtySecondsRemaining <= 0f) { _dirtySecondsRemaining = -1f; SafeFlush(); } } } } private static void SafeFlush() { if (_doc == null || string.IsNullOrEmpty(_saveKey)) { return; } try { Directory.CreateDirectory(SavesDir()); string text = DocPath(_saveKey); string text2 = text + ".tmp"; string contents = JsonSerializer.Serialize(_doc, JsonOptions); File.WriteAllText(text2, contents); File.Move(text2, text, overwrite: true); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: write failed: " + ex.Message); } } private static void EnsureLoaded() { if (_doc == null) { string text = null; try { text = ResolveSaveKey(); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: could not resolve the active save: " + ex.Message); } if (string.IsNullOrEmpty(text)) { _saveKey = null; _doc = new Document(); } else { _saveKey = text; _doc = LoadOrCreate(text); } } } private static string ResolveSaveKey() { LoadManager instance = Singleton<LoadManager>.Instance; if ((Object)(object)instance == (Object)null || !Object.op_Implicit((Object)(object)instance)) { return null; } string text = null; SaveInfo activeSaveInfo = instance.ActiveSaveInfo; if (activeSaveInfo != null) { text = activeSaveInfo.SavePath; } if (string.IsNullOrEmpty(text)) { text = instance.LoadedGameFolderPath; } if (string.IsNullOrEmpty(text)) { return null; } string[] array = text.Replace('\\', '/').TrimEnd('/').Split('/'); string text2 = ((array.Length >= 2) ? (array[^2] + "_" + array[^1]) : ((array.Length == 1) ? array[0] : null)); if (!string.IsNullOrEmpty(text2)) { return SanitizeFileName(text2); } return null; } private static string SanitizeFileName(string name) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); StringBuilder stringBuilder = new StringBuilder(name.Length); foreach (char c in name) { stringBuilder.Append((Array.IndexOf(invalidFileNameChars, c) >= 0) ? '_' : c); } return stringBuilder.ToString(); } private static string SavesDir() { return Path.Combine(MelonEnvironment.UserDataDirectory, "TheRegulars", "saves"); } private static string DocPath(string key) { return Path.Combine(SavesDir(), key + ".json"); } private static Document LoadOrCreate(string key) { string text; try { Directory.CreateDirectory(SavesDir()); text = DocPath(key); } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] History: could not prepare the saves folder: " + ex.Message); return new Document(); } if (!File.Exists(text)) { return new Document(); } try { Document? obj = JsonSerializer.Deserialize<Document>(File.ReadAllText(text), JsonOptions) ?? throw new InvalidDataException("empty document"); Document document = obj; if (document.Visits == null) { document.Visits = new List<VisitRecord>(); } return obj; } catch (Exception ex2) { if (!_loggedCorrupt) { _loggedCorrupt = true; MelonLogger.Warning($"[TheRegulars] History: save file for '{key}' was unreadable ({ex2.Message}); backing it up as .bad and starting fresh."); } try { string text2 = text + ".bad"; if (File.Exists(text2)) { File.Delete(text2); } File.Move(text, text2); } catch (Exception ex3) { MelonLogger.Warning("[TheRegulars] History: could not back up the corrupt file: " + ex3.Message); } return new Document(); } } } public sealed class ProductMatch { public string ProductId; public string Name; public DrugKind Drug; public int Matches; public float Multiplier; public int EstPricePerUnit; public bool Accepted; } public static class Products { private sealed class Candidate { public string Id; public string Name; public DrugKind Drug; public List<string> MatchedIds; public float Multiplier; public int EstPricePerUnit; } public static IReadOnlyList<ProductMatch> BestFor(string crewId, int max) { try { CrewInfo crewInfo = ResolveCrew(crewId); if (crewInfo == null) { return Array.Empty<ProductMatch>(); } List<Candidate> list = BuildCandidates(crewInfo); SortCandidates(list); int num = ((max > 0) ? Math.Min(max, list.Count) : list.Count); List<ProductMatch> list2 = new List<ProductMatch>(num); for (int i = 0; i < num; i++) { Candidate candidate = list[i]; list2.Add(new ProductMatch { ProductId = candidate.Id, Name = candidate.Name, Drug = candidate.Drug, Matches = candidate.MatchedIds.Count, Multiplier = candidate.Multiplier, EstPricePerUnit = candidate.EstPricePerUnit, Accepted = true }); } return list2; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] Products.BestFor threw: " + ex.Message); return Array.Empty<ProductMatch>(); } } public static bool CanServe(string crewId) { try { CrewInfo crewInfo = ResolveCrew(crewId); if (crewInfo == null || crewInfo.Drugs == null || crewInfo.Drugs.Count == 0) { return true; } HashSet<DrugKind> hashSet = new HashSet<DrugKind>(crewInfo.Drugs); foreach (ProductDefinition item in DiscoveredProductDefinitions()) { if (TryDrugKind(item, out var drug) && hashSet.Contains(drug)) { return true; } } return false; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] Products.CanServe threw: " + ex.Message); return true; } } public static IReadOnlyList<string> MatchingEffectIds(string crewId) { try { CrewInfo crewInfo = ResolveCrew(crewId); if (crewInfo == null || crewInfo.Effects == null || crewInfo.Effects.Count == 0) { return Array.Empty<string>(); } List<Candidate> list = BuildCandidates(crewInfo); if (list.Count == 0) { return Array.Empty<string>(); } SortCandidates(list); Candidate candidate = list[0]; if (candidate.MatchedIds.Count == 0) { return Array.Empty<string>(); } HashSet<string> hashSet = new HashSet<string>(candidate.MatchedIds, StringComparer.OrdinalIgnoreCase); List<string> list2 = new List<string>(); foreach (EffectInfo effect in crewInfo.Effects) { if (effect != null && !string.IsNullOrEmpty(effect.Id) && hashSet.Contains(effect.Id)) { list2.Add(effect.Id); } } return list2; } catch (Exception ex) { MelonLogger.Warning("[TheRegulars] Products.MatchingEffectIds threw: " + ex.Message); return Array.Empty<string>(); } } private static CrewInfo ResolveCrew(string crewId) { if (!string.IsNullOrEmpty(crewId)) { return Crews.Get(crewId); } return null; } private static List<Candidate> BuildCandidates(CrewInfo crew) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (crew.Effects != null) { foreach (EffectInfo effect in crew.Effects) { if (effect != null && !string.IsNullOrEmpty(effect.Id)) { hashSet.Add(effect.Id); } } } HashSet<DrugKind> hashSet2 = ((crew.Drugs != null) ? new HashSet<DrugKind>(crew.Drugs) : new HashSet<DrugKind>()); List<Candidate> list = new List<Candidate>(); foreach (ProductDefinition item in DiscoveredProductDefinitions()) { if (!TryDrugKind(item, out var drug) || !hashSet2.Contains(drug)) { continue; } List<string> list2 = new List<string>(); List<Effect> properties = ((PropertyItemDefinition)item).Properties; if (properties != null) { Enumerator<Effect> enumerator3 = properties.GetEnumerator(); while (enumerator3.MoveNext()) { Effect current3 = enumerator3.Current; if (!((Object)(object)current3 == (Object)null) && Object.op_Implicit((Object)(object)current3)) { string iD = current3.ID; if (!string.IsNullOrEmpty(iD) && hashSet.Contains(iD)) { list2.Add(iD); } } } } float num = 1f + 0.4f * (float)list2.Count; int estPricePerUnit = (int)Math.Round(item.MarketValue * num, MidpointRounding.AwayFromZero); list.Add(new Candidate { Id = ((BaseItemDefinition)item).ID, Name = ((BaseItemDefinition)item).Name, Drug = drug, MatchedIds = list2, Multiplier = num, EstPricePerUnit = estPricePerUnit }); } return list; } private static void SortCandidates(List<Candidate> candidates) { candidates.Sort(delegate(Candidate a, Candidate b) { int num = b.Multiplier.CompareTo(a.Multiplier); return (num == 0) ? b.EstPricePerUnit.CompareTo(a.EstPricePerUnit) : num; }); } private static bool TryDrugKind(ProductDefinition def, out DrugKind drug) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected I4, but got Unknown drug = DrugKind.Weed; if ((Object)(object)def == (Object)null || !Object.op_Implicit((Object)(object)def)) { return false; } try { drug = (DrugKind)def.DrugType; return true; } catch { return false; } } private static List<ProductDefinition> DiscoveredProductDefinitions() { List<ProductDefinition> list = new List<ProductDefinition>(); ProductManager instance = NetworkSingleton<ProductManager>.Instance; if ((Object)(object)instance == (Object)null || !Object.op_Implicit((Object)(object)instance)) { return list; } List<ProductDefinition> discoveredProducts = ProductManager.DiscoveredProducts; if (discoveredProducts == null) { return list; } Enumerator<ProductDefinition> enumerator = discoveredProducts.GetEnumerator(); while (enumerator.MoveNext()) { ProductDefinition current = enumerator.Current; if ((Object)(object)current != (Object)null && Object.op_Implicit((Object)(object)current)) { list.Add(current); } } return list; } } public static class ServiceHost { private static bool _started; public static void Init() { Faces.Init(); } public static void Start() { if (!_started) { _started = true; Faces.Start(); History.Start(); } } public static void Stop() { if (_started) { _started = false; History.Stop(); Faces.Stop(); } } } } namespace TheRegulars.Phone { internal static class AppLog { private sealed class ErrorState { internal int Suppressed; internal float NextSummaryAt; } private const float SummaryInterval = 60f; private static readonly Dictionary<string, ErrorState> Errors = new Dictionary<string, ErrorState>(StringComparer.Ordinal); internal static void Info(string message) { MelonLogger.Msg("[Phone] " + message); } internal static void Warn(string message) { MelonLogger.Warning("[Phone] " + message); } internal static void Error(string key, Exception ex) { float num = SafeNow(); if (!Errors.TryGetValue(key, out var value)) { Errors[key] = new ErrorState { NextSummaryAt = num + 60f }; MelonLogger.Error("[Phone] " + key + " failed: " + ex); return; } value.Suppressed++; if (num >= value.NextSummaryAt) { MelonLogger.Error($"[Phone] {key} failed {value.Suppressed} more time(s) in the last minute. Latest: {ex.GetType().Name}: {ex.Message}"); value.Suppressed = 0; value.NextSummaryAt = num + 60f; } } internal static bool Guard(string key, Action action) { try { action(); return true; } catch (Exception ex) { Error(key, ex); return false; } } private static float SafeNow() { try { return Time.realtimeSinceStartup; } catch { return 0f; } } } internal sealed class AppShell { private sealed class PageSlot { internal IAppPage Page; internal RectTransform Root; internal CanvasGroup Group; internal ScrollRect Scroll; internal RectTransform Content; internal bool Built; } private sealed class TabSlot { internal TabId Id; internal string Label; internal string IconName; internal Func<IAppPage> RootFactory; internal readonly List<PageSlot> Stack = new List<PageSlot>(4); internal Button NavButton; internal Image NavIcon; internal TextMeshProUGUI NavLabel; } private enum NavAnim { TabSwitch, Push, Pop } private const float FallbackWidth = 360f; private const float FallbackHeight = 640f; private const float ReferenceWidth = 360f; private readonly Func<bool> _isOpen; private readonly List<TabSlot> _tabs = new List<TabSlot>(4); private TabSlot _currentTab; private RectTransform _root; private RectTransform _topBarRow; private Button _backButton; private TextMeshProUGUI _title; private Chip _infoChip; private RectTransform _contentHost; private RectTransform _tabBarRow; private Overlay _overlay; private object _loopToken; private bool _alive; private bool _wasOpen; private bool _refreshRequested; private float _refreshTimer; internal static AppShell Current { get; private set; } internal float Width { get; private set; } = 360f; internal float Height { get; private set; } = 640f; private float ContainerWidth { get; set; } = 360f; private float ContainerHeight { get; set; } = 640f; internal RectTransform OverlayLayer => _overlay?.Layer; internal Overlay OverlayHost => _overlay; internal bool IsOpen => _wasOpen; internal bool CanGoBack { get { if (_currentTab != null) { return _currentTab.Stack.Count > 1; } return false; } } internal TabId CurrentTab => _currentTab?.Id ?? TabId.Overview; private AppShell(Func<bool> isOpen) { _isOpen = isOpen; } internal static void Build(GameObject container, Func<bool> isOpen) { Shutdown(); AppShell appShell = (Current = new AppShell(isOpen)); try { appShell.BuildUi(container); appShell.StartLoop(); } catch { Current = null; appShell.Dispose(); throw; } } internal static void Shutdown() { AppShell current = Current; Current = null; current?.Dispose(); } private void Dispose() { _alive = false; if (_loopToken != null) { try { MelonCoroutines.Stop(_loopToken); } catch (Exception ex) { AppLog.Error("loop.stop", ex); } _loopToken = null; } PageSlot pageSlot = CurrentSlot(); if (_wasOpen && pageSlot != null && pageSlot.Built) { AppLog.Guard("page.hide", pageSlot.Page.OnHide); } if (_overlay != null) { AppLog.Guard("shutdown.overlay", _overlay.Destroy); } Tween.Clear(); ControlLoop.Reset(); Ui.Reset(); if (!Ui.Dead((Object)(object)_root)) { try { Object.Destroy((Object)(object)((Component)_root).gameObject); } catch { } } _tabs.Clear(); _currentTab = null; _root = null; _topBarRow = null; _backButton = null; _title = null; _infoChip = null; _contentHost = null; _tabBarRow = null; _overlay = null; _wasOpen = false; } private void StartLoop() { _alive = true; _loopToken = MelonCoroutines.Start(Loop()); } private IEnumerator Loop() { while (_alive) { yield return null; if (!_alive) { break; } if (Ui.Dead((Object)(object)_root)) { _loopToken = null; if (Current == this) { Shutdown(); } else { Dispose(); } break; } bool flag; try { flag = _isOpen(); } catch { flag = false; } try { if (flag) { if (!_wasOpen) { _wasOpen = true; OnOpened(); } TickOpen(Time.unscaledDeltaTime); } else if (_wasOpen) { _wasOpen = false; OnClosed(); } } catch (Exception ex) { AppLog.Error("loop", ex); } } } private void OnOpened() { _refreshTimer = 0f; _refreshRequested = false; Remeasure(); PageSlot pageSlot = CurrentSlot(); if (pageSlot != null && pageSlot.Built) { AppLog.Guard("page.show", pageSlot.Page.OnShow); } _overlay?.RefreshSheet(); } private void OnClosed() { _overlay?.OnAppClosed(); TextField.ReleaseTyping(); Tween.CompleteAll(); ControlLoop.OnAppClosed(); PageSlot pageSlot = CurrentSlot(); if (pageSlot != null && pageSlot.Built) { AppLog.Guard("page.hide", pageSlot.Page.OnHide); } } private void TickOpen(float dt) { Tween.Tick(dt); ControlLoop.Tick(dt); _overlay?.Tick(dt); _refreshTimer += dt; if (_refreshTimer >= 1f || _refreshRequested) { _refreshTimer = 0f; _refreshRequested = false; RefreshVisible(); } } private void RefreshVisible() { PageSlot pageSlot = CurrentSlot(); if (pageSlot != null && pageSlot.Built) { AppLog.Guard("page.refresh", pageSlot.Page.Refresh); } _overlay?.RefreshSheet(); } internal void Push(IAppPage page) { if (_currentTab != null && page != null) { _overlay?.CloseDropdown(); _overlay?.CloseSheet(); HideCurrentSlot(); _currentTab.Stack.Add(new PageSlot { Page = page }); ShowTopOfStack(NavAnim.Push); } } internal void Pop() { if (CanGoBack) { _overlay?.CloseDropdown(); _overlay?.CloseSheet(); HideCurrentSlot(); PageSlot slot = _currentTab.Stack[_currentTab.Stack.Count - 1]; _currentTab.Stack.RemoveAt(_currentTab.Stack.Count - 1); DestroySlot(slot); ShowTopOfStack(NavAnim.Pop); } } internal void SelectTab(TabId id) { TabSlot tabSlot = _tabs.Find((TabSlot t) => t.Id == id); if (tabSlot == null) { return; } _overlay?.CloseDropdown(); _overlay?.CloseSheet(); if (tabSlot == _currentTab) { if (tabSlot.Stack.Count > 1) { PopToRoot(tabSlot); } else { ScrollToTop((tabSlot.Stack.Count > 0) ? tabSlot.Stack[0] : null); } return; } HideCurrentSlot(); _currentTab = tabSlot; if (tabSlot.Stack.Count == 0) { tabSlot.Stack.Add(new PageSlot { Page = tabSlot.RootFactory() }); } ShowTopOfStack(NavAnim.TabSwitch); } internal bool HandleBack() { if (_overlay == null) { return false; } if (_overlay.HasDropdown) { _overlay.CloseDropdown(); return true; } if (_overlay.HasSheet) { _overlay.CloseSheet(); return true; } if (CanGoBack) { Pop(); return true; } return false; } internal void OpenSheet(IAppSheet sheet) { _overlay?.OpenSheet(sheet); } internal void CloseSheet() { _overlay?.CloseSheet(); } internal void OpenConfirm(string title, string body, string confirmLabel, Action onConfirm, string cancelLabel = "Cancel", bool danger = false) { _overlay?.OpenConfirm(title, body, confirmLabel, onConfirm, cancelLabel, danger); } internal void Toast(string text, ToastKind kind = ToastKind.Info) { if (_wasOpen) { _overlay?.Toast(text, kind); } } internal void RefreshNow() { _refreshRequested = true; } internal void SetInfoChip(string text) { _infoChip?.SetText(text ?? string.Empty); } internal void RunGuarded(string key, Action action) { AppLog.Guard(key, action); } private void BuildUi(GameObject container) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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) RectTransform component = container.GetComponent<RectTransform>(); if (Ui.Dead((Object)(object)component)) { throw new InvalidOperationException("The phone kit's app container has no RectTransform."); } Canvas val = FindRootCanvas((Transform)(object)component); if (!Ui.Dead((Object)(object)val)) { Sprites.Configure(val.referencePixelsPerUnit); } Canvas.ForceUpdateCanvases(); Measure(component); AppLog.Info($"container {ContainerWidth:0}x{ContainerHeight:0}"); _root = Ui.Node("TheRegularsApp", (Transform)(object)component); _root.anchorMin = new Vector2(0.5f, 0.5f); _root.anchorMax = new Vector2(0.5f, 0.5f); _root.pivot = new Vector2(0.5f, 0.5f); _root.anchoredPosition = Vector2.zero; ApplyRootScale(); Ui.Img((Component)(object)_root, Theme.Bg, null, raycast: true); Ui.ClipChildren(_root, showGraphic: true); BuildTopBar(); BuildTabBar(); BuildContentHost(); _overlay = new Overlay(this, _root); RegisterTabs(); SelectInitialTab(); } private void ApplyRootScale() { //IL_0062: 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) Width = 360f; Height = ((ContainerWidth > 1f) ? (360f * (ContainerHeight / ContainerWidth)) : 640f); Theme.SetContainerWidth(ContainerWidth); if (!Ui.Dead((Object)(object)_root)) { _root.sizeDelta = new Vector2(Width, Height); float num = ((ContainerWidth > 1f) ? (ContainerWidth / 360f) : 1f); ((Transform)_root).localScale = new Vector3(num, num, 1f); } } private void BuildTopBar() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0066: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_01a6: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Ui.Node("TopBar", (Transform)(object)_root); val.anchorMin = new Vector2(0f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(0.5f, 1f); val.sizeDelta = new Vector2(0f, 56f); val.anchoredPosition = Vector2.zero; Ui.Img((Component)(object)val, Theme.Bg); RectTransform obj = Ui.Node("Divider", (Transform)(object)val); obj.anchorMin = new Vector2(0f, 0f); obj.anchorMax = new Vector2(1f, 0f); obj.pivot = new Vector2(0.5f, 0f); obj.sizeDelta = new Vector2(0f, 1f); Ui.Img((Component)(object)obj, Theme.Border); _topBarRow = Ui.HStack((Transform)(object)val, 8f, (TextAnchor)3); Ui.Stretch(_topBarRow); Ui.Pad(_topBarRow, 16, 16, 0, 0); _backButton = Ui.IconButton((Transform)(object)_topBarRow, "chevron-left", Pop, Theme.Text2); Ui.SetActive((Component)(object)_backButton, active: false); _title = Ui.Text((Transform)(object)_topBarRow, string.Empty, 22f, Theme.Text, bold: true, (TextAlignmentOptions)513); Ui.Fill((Component)(object)_title); _infoChip = Ui.Chip((Transform)(object)_topBarRow, "—", Theme.Text2); } private void BuildTabBar() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0066: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Expected O, but got Unknown RectTransform val = Ui.Node("TabBar", (Transform)(object)_root); val.anchorMin = new Vector2(0f, 0f); val.anchorMax = new Vector2(1f, 0f); val.pivot = new Vector2(0.5f, 0f); val.sizeDelta = new Vector2(0f, 64f); val.anchoredPosition = Vector2.zero; Ui.Img((Component)(object)val, Theme.Card); RectTransform obj = Ui.Node("Divider", (Transform)(object)val); obj.anchorMin = new Vector2(0f, 1f); obj.anchorMax = new Vector2(1f, 1f); obj.pivot = new Vector2(0.5f, 1f); obj.sizeDelta = new Vector2(0f, 1f); Ui.Img((Component)(object)obj, Theme.Border); _tabBarRow = Ui.Node("Buttons", (Transform)(object)val); Ui.Stretch(_tabBarRow); HorizontalLayoutGroup obj2 = ((Component)_tabBarRow).gameObject.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)obj2).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = true; ((LayoutGroup)obj2).padding = new RectOffset(0, 0, 6, 8); } private void BuildContentHost() { _contentHost = Ui.Node("Content", (Transform)(object)_root); Ui.Stretch(_contentHost, 0f, 0f, 56f, 64f); } private void RegisterTabs() { RegisterTab(TabId.Overview, "Overview", "dashboard", () => new OverviewPage()); RegisterTab(TabId.Crews, "Crews", "users", () => new CrewsPage()); RegisterTab(TabId.Calendar, "Calendar", "calendar", () => new CalendarPage()); RegisterTab(TabId.Settings, "Settings", "adjustments", () => new SettingsPage()); } private void RegisterTab(TabId id, string label, string icon, Func<IAppPage> rootFactory) { TabSlot tabSlot = new TabSlot { Id = id, Label = label, IconName = icon, RootFactory = rootFactory }; _tabs.Add(tabSlot); BuildTabButton(tabSlot); } private void BuildTabButton(TabSlot tab) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Ui.VStack((Transform)(object)_tabBarRow, 2f); ((Object)val).name = "Tab_" + tab.Id; VerticalLayoutGroup component = ((Component)val).gameObject.GetComponent<VerticalLayoutGroup>(); ((LayoutGroup)component).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = false; Image targetGraphic = Ui.Img((Component)(object)val, Theme.Clear, Sprites.Rounded(12), raycast: true); tab.NavIcon = Ui.Icon((Transform)(object)val, tab.IconName, 22f, Theme.Text2); tab.NavLabel = Ui.Text((Transform)(object)val, tab.Label, 11f, Theme.Text2, bold: false, (TextAlignmentOptions)514); Button val2 = ((Component)val).gameObject.AddComponent<Button>(); ((Selectable)val2).targetGraphic = (Graphic)(object)targetGraphic; Ui.Tint((Selectable)(object)val2, Theme.Clear, Theme.HoverWash, Theme.PressWash); TabId id = tab.Id; Ui.OnClick(val2, delegate { SelectTab(id); }, "tab." + id); ControlLoop.RegisterPress((Selectable)(object)val2, (Transform)(object)val); tab.NavButton = val2; } private void SelectInitialTab() { if (_tabs.Count != 0) { _currentTab = _tabs[0]; _currentTab.Stack.Add(new PageSlot { Page = _currentTab.RootFactory() }); ShowTopOfStack(NavAnim.TabSwitch); } } private void BuildPage(PageSlot slot) { slot.Root = Ui.Node("Page", (Transform)(object)_contentHost); Ui.Stretch(slot.Root); slot.Group = ((Component)slot.Root).gameObject.AddComponent<CanvasGroup>(); slot.Content = Ui.ScrollPage((Transform)(object)slot.Root, out slot.Scroll); PageSlot captured = slot; AppLog.Guard("page.build", delegate { captured.Page.Build(captured.Content, this); }); slot.Built = true; } private PageSlot CurrentSlot() { if (_currentTab == null || _currentTab.Stack.Count <= 0) { return null; } return _currentTab.Stack[_currentTab.Stack.Count - 1]; } private void HideCurrentSlot() { PageSlot pageSlot = CurrentSlot(); if (pageSlot != null && pageSlot.Built && !Ui.Dead((Object)(object)pageSlot.Root)) { if (_wasOpen) { AppLog.Guard("page.hide", pageSlot.Page.OnHide); } Ui.SetActive((Component)(object)pageSlot.Root, active: false); } } private void ShowTopOfStack(NavAnim anim) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) PageSlot pageSlot = CurrentSlot(); if (pageSlot != null && !Ui.Dead((Object)(object)_contentHost)) { if (!pageSlot.Built) { BuildPage(pageSlot); } Ui.SetActive((Component)(object)pageSlot.Root, active: true); ((Transform)pageSlot.Root).SetAsLastSibling(); UpdateChrome(pageSlot); UpdateTabBarSelection(); float num = anim switch { NavAnim.Pop => 0f - Width, NavAnim.Push => Width, _ => 0f, }; float duration = ((anim == NavAnim.TabSwitch) ? 0.16f : 0.18f); pageSlot.Root.anchoredPosition = new Vector2(num, 0f); if (anim == NavAnim.TabSwitch) { pageSlot.Group.alpha = 0f; Tween.Alpha(pageSlot.Group, 1f, duration); } else { pageSlot.Group.alpha = 1f; } Tween.Position(pageSlot.Root, Vector2.zero, duration); if (_wasOpen) { AppLog.Guard("page.show", pageSlot.Page.OnShow); } } } private void PopToRoot(TabSlot tab) { HideCurrentSlot(); while (tab.Stack.Count > 1) { PageSlot slot = tab.Stack[tab.Stack.Count - 1]; tab.Stack.RemoveAt(tab.Stack.Count - 1); DestroySlot(slot); } ShowTopOfStack(NavAnim.Pop); } private void DestroySlot(PageSlot slot) { if (slot != null && !Ui.Dead((Object)(object)slot.Root)) { Object.Destroy((Object)(object)((Component)slot.Root).gameObject); } } private void UpdateChrome(PageSlot slot) { if (!Ui.Dead((Object)(object)_title)) { ((TMP_Text)_title).text = slot.Page.Title ?? string.Empty; } Ui.SetActive((Component)(object)_backButton, CanGoBack); } private void UpdateTabBarSelection() { //IL_002a: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) foreach (TabSlot tab in _tabs) { bool flag = tab == _currentTab; Color color = (flag ? Theme.Gold : Theme.Text2); if (!Ui.Dead((Object)(object)tab.NavIcon)) { ((Graphic)tab.NavIcon).color = color; } if (!Ui.Dead((Object)(object)tab.NavLabel)) { ((Graphic)tab.NavLabel).color = color; ((TMP_Text)tab.NavLabel).fontStyle = (FontStyles)(flag ? 1 : 0); } } } private void ScrollToTop(PageSlot slot) { //IL_003a: 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) if (slot != null && !Ui.Dead((Object)(object)slot.Scroll) && !Ui.Dead((Object)(object)slot.Scroll.content)) { RectTransform content = slot.Scroll.content; slot.Scroll.StopMovement(); Tween.Position(content, new Vector2(content.anchoredPosition.x, 0f), 0.22f); } } private void Remeasure() { RectTransform val = (RectTransform)(Ui.Dead((Object)(object)_root) ? null : /*isinst with value type is only supported in some contexts*/); if (!Ui.Dead((Object)(object)val)) { float containerWidth = ContainerWidth; float containerHeight = ContainerHeight; Measure(val); if (!(Mathf.Abs(containerWidth - ContainerWidth) < 1f) || !(Mathf.Abs(containerHeight - ContainerHeight) < 1f)) { AppLog.Info($"container resized to {ContainerWidth:0}x{ContainerHeight:0}"); ApplyRootScale(); } } } private void Measure(RectTransform host) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Rect rect = host.rect; bool flag = ((Rect)(ref rect)).width > 1f && ((Rect)(ref rect)).height > 1f; ContainerWidth = (flag ? ((Rect)(ref rect)).width : 360f); ContainerHeight = (flag ? ((Rect)(ref rect)).height : 640f); } private static Canvas FindRootCanvas(Transform start) { Canvas result = null; Transform val = start; int num = 0; while (!Ui.Dead((Object)(object)val) && num++ < 64) { Canvas component = ((Component)val).GetComponent<Canvas>(); if (!Ui.Dead((Object)(object)component)) { result = component; } val = val.parent; } return result; } } internal sealed class CalendarPage : IAppPage { private sealed class VisitRow { internal RectTransform Root; internal PageKit.FaceSlot Face; internal TextMeshProUGUI Days; internal TextMeshProUGUI Deals; } private RectTransform _timelineCard; private LiveText _mainLine; private RectTransform _likelyHost; private readonly List<TextMeshProUGUI> _likelyRows = new List<TextMeshProUGUI>(); private int _lastLikelyCount = -1; private RectTransform _visitsHost; private RectTransform _visitsEmpty; private readonly List<VisitRow> _visitRows = new List<VisitRow>(); private int _lastVisitCount = -1; public string Title => "Calendar"; public void Build(RectTransform content, AppShell shell) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) PageKit.EnsureLiveRefreshWired(); _timelineCard = Ui.CardFrame((Transform)(object)content); ((Object)_timelineCard).name = "Timeline"; _mainLine = new LiveText(Ui.Wrap(Ui.Text((Transform)(object)_timelineCard, string.Empty, 16f, Theme.Text, bold: true, (TextAlignmentOptions)513))); _likelyHost = Ui.VStack((Transform)(object)_timelineCard, 6f); Ui.SectionLabel((Transform)(object)content, "Past visits"); _visitsHost = Ui.VStack((Transform)(object)content, 12f); ((Object)_visitsHost).name = "PastVisits"; _visitsEmpty = Ui.EmptyState((Transform)(object)content, "calendar", "No visits yet", "Your first crew visit will show up here."); Refresh(); } public void OnShow() { Refresh(); } public void OnHide() { } public void Refresh() { Snapshot now = Crews.Now; RefreshTimeline(now); RefreshPastVisits(); } private void RefreshTimeline(Snapshot s) { if (s.Phase == CrewPhase.Unknown) { _mainLine.Set("Sleep once to sync with the host", flash: true); SetLikelyCount(0); return; } switch (s.Phase) { case CrewPhase.Quiet: if (!s.IsHost || s.SleepsUntilRolls < 0) { _mainLine.Set("Sleep once to sync with the host", flash: true); SetLikelyCount(0); } else { _mainLine.Set(PageKit.CalendarQuietLine(s), flash: true); RefreshLikelyNext(s); } break; case CrewPhase.Coming: _mainLine.Set((s.SleepsLeft < 0) ? "Sleep once to sync with the host" : ("Arrive in " + Fmt.Count(s.SleepsLeft, "sleep")), flash: true); SetLikelyCount(0); break; case CrewPhase.InTown: _mainLine.Set((s.SleepsLeft < 0) ? "Sleep once to sync with the host" : ("Leave in " + Fmt.Count(s.SleepsLeft, "night")), flash: true); SetLikelyCount(0); break; default: _mainLine.Set("Sleep once to sync with the host", flash: true); SetLikelyCount(0); break; } } private void RefreshLikelyNext(Snapshot s) { IReadOnlyList<(string, float)> likelyNext = s.LikelyNext; SetLikelyCount(likelyNext.Count); for (int i = 0; i < likelyNext.Count; i++) { (string, float) tuple = likelyNext[i]; string text = Crews.Get(tuple.Item1)?.Name ?? Fmt.Humanize(tuple.Item1); ((TMP_Text)_likelyRows[i]).text = text + " — " + Mathf.RoundToInt(Mathf.Clamp01(tuple.Item2) * 100f) + "%"; } } private void SetLikelyCount(int count) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (count != _lastLikelyCount) { _lastLikelyCount = count; foreach (TextMeshProUGUI likelyRow in _likelyRows) { if (!Ui.Dead((Object)(object)likelyRow)) { Object.Destroy((Object)(object)((Component)likelyRow).gameObject); } } _likelyRows.Clear(); for (int i = 0; i < count; i++) { _likelyRows.Add(Ui.Text((Transform)(object)_likelyHost, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513)); } } Ui.SetActive((Component)(object)_likelyHost, count > 0); } private void RefreshPastVisits() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList<VisitRecord> visits = History.Visits; Ui.SetActive((Component)(object)_visitsEmpty, visits.Count == 0); Ui.SetActive((Component)(object)_visitsHost, visits.Count > 0); if (visits.Count != _lastVisitCount) { _lastVisitCount = visits.Count; RebuildVisitRows(visits); } for (int i = 0; i < visits.Count && i < _visitRows.Count; i++) { VisitRecord visitRecord = visits[i]; VisitRow visitRow = _visitRows[i]; CrewInfo crewInfo = Crews.Get(visitRecord.CrewId); Color color = ((crewInfo != null) ? Theme.Accent(crewInfo.Color).Text : Theme.DefaultAccent.Text); visitRow.Face.Refresh(crewInfo?.Leader?.NpcId, color, visitRecord.CrewId); ((TMP_Text)visitRow.Days).text = DaySpan(visitRecord.ArrivedDay, visitRecord.LeftDay); ((TMP_Text)visitRow.Deals).text = Fmt.Count(visitRecord.Deals, "deal") + " · " + Fmt.Money(visitRecord.Cash); } } private static string DaySpan(int arrived, int left) { if (arrived >= 0 && left >= 0) { return "Day " + arrived + "–" + left; } if (arrived >= 0) { return "Since day " + arrived; } if (left >= 0) { return "Through day " + left; } return "A past visit"; } private void RebuildVisitRows(IReadOnlyList<VisitRecord> visits) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_016c: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) foreach (VisitRow visitRow2 in _visitRows) { if (!Ui.Dead((Object)(object)visitRow2.Root)) { Object.Destroy((Object)(object)((Component)visitRow2.Root).gameObject); } } _visitRows.Clear(); for (int i = 0; i < visits.Count; i++) { VisitRecord visitRecord = visits[i]; CrewInfo crewInfo = Crews.Get(visitRecord.CrewId); RectTransform val = Ui.HStack((Transform)(object)_visitsHost, 12f, (TextAnchor)3); ((Object)val).name = "Visit"; Ui.Pad(val, 14, 14, 10, 10); Ui.Img((Component)(object)val, Theme.Card, Sprites.Rounded(16)); Ui.AddOutline(val, 16, Theme.Border); VisitRow visitRow = new VisitRow { Root = val, Face = PageKit.FaceSlot.Build((Transform)(object)val, crewInfo?.Leader?.NpcId, visitRecord.CrewId, Theme.DefaultAccent.Text, 36f) }; RectTransform val2 = Ui.VStack((Transform)(object)val, 2f); Ui.Fill((Component)(object)val2); Ui.Text((Transform)(object)val2, crewInfo?.Name ?? Fmt.Humanize(visitRecord.CrewId), 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); visitRow.Days = Ui.Text((Transform)(object)val2, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); visitRow.Deals = Ui.Text((Transform)(object)val, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)516); _visitRows.Add(visitRow); } } } internal sealed class CrewDetailPage : IAppPage { private sealed class MatchRow { internal readonly RectTransform Root; private readonly TextMeshProUGUI _name; private readonly TextMeshProUGUI _effects; private readonly TextMeshProUGUI _priceLine; private MatchRow(RectTransform root, TextMeshProUGUI name, TextMeshProUGUI effects, TextMeshProUGUI priceLine) { Root = root; _name = name; _effects = effects; _priceLine = priceLine; } internal static MatchRow Build(Transform parent) { //IL_0025: 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_0079: Unknown result type (might be due to invalid IL or missing references) RectTransform obj = Ui.VStack(parent, 2f); ((Object)obj).name = "Match"; TextMeshProUGUI name = Ui.Text((Transform)(object)obj, string.Empty, 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); RectTransform obj2 = Ui.HStack((Transform)(object)obj, 6f, (TextAnchor)3); ((Object)obj2).name = "Line2"; TextMeshProUGUI val = Ui.Text((Transform)(object)obj2, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); Ui.Fill((Component)(object)val); TextMeshProUGUI priceLine = Ui.Text((Transform)(object)obj2, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)516); return new MatchRow(obj, name, val, priceLine); } internal void Set(ProductMatch m, int effectTotal) { ((TMP_Text)_name).text = m.Name; ((TMP_Text)_effects).text = m.Matches + " of " + effectTotal + " bonus effects"; ((TMP_Text)_priceLine).text = Fmt.Times(m.Multiplier) + " · ~" + Fmt.Money(m.EstPricePerUnit) + "/unit"; } } private readonly string _crewId; private CrewInfo _crew; private AppShell _shell; private PageKit.FaceSlot _headerFace; private TextMeshProUGUI _headerName; private TextMeshProUGUI _headerRole; private Chip _visitsChip; private RectTransform _visitCard; private RectTransform _budgetKnownGroup; private LiveNumber _budgetLeft; private LiveNumber _budgetTotal; private ProgressBar _budgetBar; private TextMeshProUGUI _budgetSyncingText; private TextMeshProUGUI _nightsLeftText; private TextMeshProUGUI _salesThisVisitText; private List<(string EffectId, Chip Chip, Image Check)> _effectChips; private RectTransform _matchesHost; private MatchRow[] _matchesRows; private TextMeshProUGUI _matchesFootnote; private RectTransform _matchesEmpty; private TextMeshProUGUI _visitsStat; private TextMeshProUGUI _lastVisitStat; private TextMeshProUGUI _totalStat; private Button _mapButton; private Button _actionButton; private Button _sendAwayButton; private TextMeshProUGUI _actionHintText; private const int MaxBestMatches = 3; private readonly List<PageKit.PersonFaceSlot> _memberFaces = new List<PageKit.PersonFaceSlot>(); public string Title => _crew?.Name ?? "Crew"; internal CrewDetailPage(string crewId) { _crewId = crewId; } public void Build(RectTransform content, AppShell shell) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) PageKit.EnsureLiveRefreshWired(); _shell = shell; _crew = Crews.Get(_crewId); if (_crew == null) { Ui.EmptyState((Transform)(object)content, "alert", "This crew isn't available", "Try opening it again from Crews."); return; } (Color, Color, Color) accent = Theme.Accent(_crew.Color); BuildHeader((Transform)(object)content, accent); BuildVisitCard((Transform)(object)content, accent); BuildBuyAndEffects((Transform)(object)content, accent); BuildBestMatches((Transform)(object)content); BuildMembers((Transform)(object)content, accent); BuildHistory((Transform)(object)content); BuildButtons((Transform)(object)content, accent); Refresh(); } public void OnShow() { Refresh(); } public void OnHide() { } public void Refresh() { //IL_0039: 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) if (_crew != null) { Snapshot now = Crews.Now; bool inTown = now.Phase == CrewPhase.InTown && string.Equals(now.ActiveCrewId, _crew.Id, StringComparison.OrdinalIgnoreCase); (Color, Color, Color) accent = Theme.Accent(_crew.Color); _headerFace.Refresh(_crew.Leader?.NpcId, accent.Item1, _crew.Id); CrewHistory crewHistory = PageKit.FindHistory(now, _crew.Id); Ui.SetActive((IControl)_visitsChip, crewHistory != null && crewHistory.Visits > 0); if (crewHistory != null && crewHistory.Visits > 0) { _visitsChip.SetText(Fmt.Count(crewHistory.Visits, "visit")); } RefreshVisitCard(now, inTown, accent); RefreshEffects(); RefreshBestMatches(); RefreshMemberFaces(); RefreshHistory(now); RefreshButtons(inTown); } } private void BuildHeader(Transform parent, (Color Text, Color Tint, Color Outline) accent) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Ui.HStack(parent, 12f, (TextAnchor)3); ((Object)val).name = "Header"; _headerFace = PageKit.FaceSlot.Build((Transform)(object)val, _crew.Leader?.NpcId, _crew.Id, accent.Text, 80f); RectTransform val2 = Ui.VStack((Transform)(object)val, 4f); Ui.Fill((Component)(object)val2); _headerName = Ui.Text((Transform)(object)val2, _crew.Leader?.FullName ?? _crew.Name, 18f, Theme.Text, bold: true, (TextAlignmentOptions)513); _headerRole = Ui.Text((Transform)(object)val2, "Leader · deals with you", 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); _visitsChip = PageKit.SoloChip((Transform)(object)val2, string.Empty, Theme.Text2); Ui.SetActive((IControl)_visitsChip, active: false); } private void BuildVisitCard(Transform parent, (Color Text, Color Tint, Color Outline) accent) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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_01bb: Unknown result type (might be due to invalid IL or missing references) _visitCard = Ui.CardFrame(parent); ((Object)_visitCard).name = "VisitCard"; _budgetKnownGroup = Ui.VStack((Transform)(object)_visitCard, 6f); RectTransform parent2 = Ui.HStack((Transform)(object)_budgetKnownGroup, 6f, (TextAnchor)3); Ui.Fill((Component)(object)Ui.Text((Transform)(object)parent2, "Left to buy today", 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513)); TextMeshProUGUI label = Ui.Text((Transform)(object)parent2, "0", 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); _budgetLeft = new LiveNumber(label, (int v) => v.ToString()); Ui.Text((Transform)(object)parent2, " of ", 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); TextMeshProUGUI label2 = Ui.Text((Transform)(object)parent2, "0", 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); _budgetTotal = new LiveNumber(label2, (int v) => v.ToString()); _budgetBar = Ui.Progress((Transform)(object)_budgetKnownGroup, 0f, accent.Text, 6f); _budgetSyncingText = Ui.Text((Transform)(object)_visitCard, "Syncing today's numbers with the host...", 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); Ui.Wrap(Ui.Text((Transform)(object)_visitCard, "Refills when you sleep · the last pack still pays in full", 12f, Theme.Text3, bold: false, (TextAlignmentOptions)513)); _nightsLeftText = Ui.Text((Transform)(object)_visitCard, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); _salesThisVisitText = Ui.Text((Transform)(object)_visitCard, string.Empty, 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); Ui.SetActive((Component)(object)_visitCard, active: false); } private void RefreshVisitCard(Snapshot s, bool inTown, (Color Text, Color Tint, Color Outline) accent) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) Ui.SetActive((Component)(object)_visitCard, inTown); if (inTown) { bool flag = s.BudgetToday >= 0; Ui.SetActive((Component)(object)_budgetKnownGroup, flag); Ui.SetActive((Component)(object)_budgetSyncingText, !flag); if (flag) { int budgetToday = s.BudgetToday; int num = Mathf.Clamp(s.BudgetLeftToday, 0, budgetToday); _budgetLeft.Set(num); _budgetTotal.Set(budgetToday); _budgetBar.Set((budgetToday > 0) ? ((float)num / (float)budgetToday) : 0f, accent.Text); } ((TMP_Text)_nightsLeftText).text = PageKit.NightsLeftLine(s.SleepsLeft); long num2 = ((History.Current != null && string.Equals(History.Current.CrewId, _crew.Id, StringComparison.OrdinalIgnoreCase)) ? History.Current.Cash : 0); ((TMP_Text)_salesThisVisitText).text = "Your sales this visit · " + Fmt.Money(num2); } } private void BuildBuyAndEffects(Transform parent, (Color Text, Color Tint, Color Outline) accent) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) RectTransform parent2 = Ui.Card(parent, "They buy"); List<string> list = new List<string>(_crew.Drugs.Count); foreach (DrugKind drug in _crew.Drugs) { list.Add(PageKit.DrugName(drug)); } RectTransform parent3 = Ui.HStack((Transform)(object)parent2, 6f, (TextAnchor)3); foreach (string item in list) { Ui.Chip((Transform)(object)parent3, item, accent.Text); } Ui.SectionLabel((Transform)(object)parent2, "Bonus effects · +40% each"); List<string> list2 = new List<string>(_crew.Effects.Count); foreach (EffectInfo effect in _crew.Effects) { list2.Add(effect.Name); } float maxWidth = ((AppShell.Current != null) ? (AppShell.Current.Width - 32f - 32f) : 328f); List<(Chip, Image)> list3 = PageKit.ChipWrap((Transform)(object)parent2, maxWidth, list2); _effectChips = new List<(string, Chip, Image)>(list3.Count); for (int i = 0; i < list3.Count && i < _crew.Effects.Count; i++) { _effectChips.Add((_crew.Effects[i].Id, list3[i].Item1, list3[i].Item2)); } } private void RefreshEffects() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) if (_effectChips == null) { return; } HashSet<string> hashSet = new HashSet<string>(Products.MatchingEffectIds(_crew.Id), StringComparer.OrdinalIgnoreCase); (Color, Color, Color) tuple = Theme.Accent(_crew.Color); foreach (var effectChip in _effectChips) { bool flag = hashSet.Contains(effectChip.EffectId); string text = FindEffect(effectChip.EffectId)?.Name ?? Fmt.Humanize(effectChip.EffectId); Color color = (flag ? tuple.Item1 : Theme.Text2); effectChip.Chip.Set(text, color); Ui.SetActive((Component)(object)effectChip.Check, flag); if (!Ui.Dead((Object)(object)effectChip.Check)) { ((Graphic)effectChip.Check).color = color; } } } private EffectInfo FindEffect(string id) { foreach (EffectInfo effect in _crew.Effects) { if (string.Equals(effect.Id, id, StringComparison.OrdinalIgnoreCase)) { return effect; } } return null; } private void BuildBestMatches(Transform parent) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) RectTransform parent2 = Ui.Card(parent, "Your best matches"); _matchesHost = Ui.VStack((Transform)(object)parent2, 8f); _matchesRows = new MatchRow[3]; for (int i = 0; i < 3; i++) { _matchesRows[i] = MatchRow.Build((Transform)(object)_matchesHost); } _matchesFootnote = Ui.Text((Transform)(object)parent2, "Prices at standard quality", 11f, Theme.Text3, bold: false, (TextAlignmentOptions)513); _matchesEmpty = Ui.EmptyState((Transform)(object)parent2, "package", "No matching products yet", "Discover a " + PageKit.DrugListLower(_crew.Drugs) + " product to sell to them."); RefreshBestMatches(); } private void RefreshBestMatches() { IReadOnlyList<ProductMatch> readOnlyList = Products.BestFor(_crew.Id, 3); Ui.SetActive((Component)(object)_matchesHost, readOnlyList.Count > 0); Ui.SetActive((Component)(object)_matchesFootnote, readOnlyList.Count > 0); Ui.SetActive((Component)(object)_matchesEmpty, readOnlyList.Count == 0); for (int i = 0; i < _matchesRows.Length; i++) { bool flag = i < readOnlyList.Count; Ui.SetActive((Component)(object)_matchesRows[i].Root, flag); if (flag) { _matchesRows[i].Set(readOnlyList[i], _crew.Effects.Count); } } } private void BuildMembers(Transform parent, (Color Text, Color Tint, Color Outline) accent) { RectTransform parent2 = Ui.VStack((Transform)(object)Ui.Card(parent, "The crew"), 8f); AddMemberRow((Transform)(object)parent2, _crew.Leader, accent, "Leader"); foreach (TheRegulars.Data.MemberInfo member in _crew.Members) { AddMemberRow((Transform)(object)parent2, member, accent, null); } } private void AddMemberRow(Transform parent, TheRegulars.Data.MemberInfo member, (Color Text, Color Tint, Color Outline) accent, string role) { //IL_0029: 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_0088: Unknown result type (might be due to invalid IL or missing references) if (member != null) { RectTransform obj = Ui.HStack(parent, 8f, (TextAnchor)3); ((Object)obj).name = "Member"; PageKit.PersonFaceSlot item = PageKit.PersonFaceSlot.Build((Transform)(object)obj, member.NpcId, member.FullName, accent.Text, 36f); _memberFaces.Add(item); RectTransform val = Ui.VStack((Transform)(object)obj, 0f); Ui.Fill((Component)(object)val); Ui.Text((Transform)(object)val, member.FullName, 15f, Theme.Text, bold: false, (TextAlignmentOptions)513); if (!string.IsNullOrEmpty(role)) { Ui.Text((Transform)(object)val, role, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); } } } private void RefreshMemberFaces() { for (int i = 0; i < _memberFaces.Count; i++) { _memberFaces[i].Refresh(); } } private void BuildHistory(Transform parent) { RectTransform parent2 = Ui.Card(parent, "History"); _visitsStat = PageKit.StatRow((Transform)(object)parent2, "Visits"); _lastVisitStat = PageKit.StatRow((Transform)(object)parent2, "Last visit"); _totalStat = PageKit.StatRow((Transform)(object)parent2, "Total earned (your sales)"); } private void RefreshHistory(Snapshot s) { CrewHistory crewHistory = PageKit.FindHistory(s, _crew.Id); if (!s.IsHost) { ((TMP_Text)_visitsStat).text = "—"; ((TMP_Text)_lastVisitStat).text = "Only your host can see their history."; } else if (crewHistory == null || crewHistory.Visits <= 0) { ((TMP_Text)_visitsStat).text = "0"; ((TMP_Text)_lastVisitStat).text = "Never visited"; } else { ((TMP_Text)_visitsStat).text = crewHistory.Visits.ToString(); ((TMP_Text)_lastVisitStat).text = ((crewHistory.NightsSinceVisit == 0) ? "Last night" : (Fmt.Count(Math.Max(0, crewHistory.NightsSinceVisit), "night") + " ago")); } ((TMP_Text)_totalStat).text = Fmt.Money(History.TotalFrom(_crew.Id)); } private void BuildButtons(Transform parent, (Color Text, Color Tint, Color Outline) accent) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Ui.HStack(parent, 8f, (TextAnchor)3); ((Object)val).name = "Actions"; _mapButton = Ui.Button((Transform)(object)val, "Show on map", ButtonStyle.Secondary, OnShowOnMap, "map-pin"); Ui.Size((Component)(object)_mapButton, -1f, -1f, 1f); Ui.SetActive((Component)(object)_mapButton, active: false); _actionButton = Ui.Button((Transform)(object)val, "Call them in", ButtonStyle.Primary, OnActionButtonTapped, "phone-call"); Ui.Size((Component)(object)_actionButton, -1f, -1f, 1f); _sendAwayButton = Ui.Button((Transform)(object)val, "Send them away", ButtonStyle.Secondary, OnSendThemAwayTapped, "x"); Ui.Size((Component)(object)_sendAwayButton, -1f, -1f, 1f); Ui.SetActive((Component)(object)_sendAwayButton, active: false); _actionHintText = Ui.Wrap(Ui.Text(parent, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513)); ((Object)_actionHintText).name = "ActionHint"; Ui.SetActive((Component)(object)_actionHintText, active: false); } private void RefreshButtons(bool inTown) { Snapshot now = Crews.Now; bool flag = string.Equals(now.ActiveCrewId, _crew.Id, StringComparison.OrdinalIgnoreCase); bool flag2 = !inTown && now.Phase == CrewPhase.Coming && flag; Ui.SetActive((Component)(object)_mapButton, inTown); Ui.SetActive((Component)(object)_sendAwayButton, inTown); Ui.SetActive((Component)(object)_actionButton, !inTown); if (!inTown) { Ui.SetButtonText(_actionButton, flag2 ? "Bring them sooner" : "Call them in"); } bool flag3; string reason; if (now.IsHost) { flag3 = ((!inTown) ? CrewActions.CanCallIn(_crew.Id, out reason) : CrewActions.CanSendAway(out reason)); } else { flag3 = false; reason = "Host only"; } Ui.SetInteractable((Component)(object)(inTown ? _sendAwayButton : _actionButton), flag3, reason); bool flag4 = !flag3 && !string.IsNullOrEmpty(reason); Ui.SetActive((Component)(object)_actionHintText, flag4); if (flag4) { ((TMP_Text)_actionHintText).text = reason; } } private void OnShowOnMap() { _shell.RunGuarded("crewdetail.markonmap", delegate { ActionResult actionResult = CrewActions.MarkOnMap(_crew.Id); _shell.Toast(actionResult.Message, actionResult.Ok ? ToastKind.Success : ToastKind.Warn); }); } private void OnActionButtonTapped() { _shell.RunGuarded("crewdetail.callin.confirm", delegate { Snapshot now = Crews.Now; int num; string text; if (now.Phase == CrewPhase.Coming) { num = (string.Equals(now.ActiveCrewId, _crew.Id, StringComparison.OrdinalIgnoreCase) ? 1 : 0); if (num != 0) { text = "Bring the " + _crew.Name + " sooner?"; goto IL_0062; } } else { num = 0; } text = "Call the " + _crew.Name + " in?"; goto IL_0062; IL_0062: string title = text; string confirmLabel = ((num != 0) ? "Bring them sooner" : "Call them in"); _shell.OpenConfirm(title, "They arrive after your next sleep.", confirmLabel, ConfirmCallIn); }); } private void ConfirmCallIn() { _shell.RunGuarded("crewdetail.callin", delegate { ActionResult actionResult = CrewActions.CallIn(_crew.Id); _shell.Toast(actionResult.Message, actionResult.Ok ? ToastKind.Success : ToastKind.Warn); }); } private void OnSendThemAwayTapped() { _shell.RunGuarded("crewdetail.sendaway.confirm", delegate { _shell.OpenConfirm("Send the " + _crew.Name + " away?", "They leave when you sleep. Anything you sell them today still counts.", "Send away", ConfirmSendAway); }); } private void ConfirmSendAway() { _shell.RunGuarded("crewdetail.sendaway", delegate { ActionResult actionResult = CrewActions.SendAway(); _shell.Toast(actionResult.Message, actionResult.Ok ? ToastKind.Success : ToastKind.Warn); }); } } internal sealed class CrewsPage : IAppPage { private sealed class Row { internal RectTransform Root; internal string CrewId; internal PageKit.FaceSlot Face; internal TextMeshProUGUI Name; internal TextMeshProUGUI Status; } private AppShell _shell; private RectTransform _host; private RectTransform _emptyState; private readonly List<Row> _rows = new List<Row>(); private int _lastCount = -1; public string Title => "Crews"; public void Build(RectTransform content, AppShell shell) { PageKit.EnsureLiveRefreshWired(); _shell = shell; _host = Ui.VStack((Transform)(object)content, 12f); ((Object)_host).name = "CrewRows"; _emptyState = Ui.EmptyState((Transform)(object)content, "users", "No crews yet", "The game hasn't loaded them in yet."); Refresh(); } public void OnShow() { Refresh(); } public void OnHide() { } public void Refresh() { //IL_007c: 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_00d8: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList<CrewInfo> all = Crews.All; Ui.SetActive((Component)(object)_emptyState, all.Count == 0); Ui.SetActive((Component)(object)_host, all.Count > 0); if (all.Count != _lastCount) { _lastCount = all.Count; Rebuild(all); } Snapshot now = Crews.Now; for (int i = 0; i < _rows.Count; i++) { Row row = _rows[i]; CrewInfo crewInfo = Crews.Get(row.CrewId); if (crewInfo != null) { (Color, Color, Color) tuple = Theme.Accent(crewInfo.Color); row.Face.Refresh(crewInfo.Leader?.NpcId, tuple.Item1, crewInfo.Id); (string, Color) tuple2 = PageKit.CrewRowStatus(now, crewInfo); ((TMP_Text)row.Status).text = tuple2.Item1; ((Graphic)row.Status).color = tuple2.Item2; } } } private void Rebuild(IReadOnlyList<CrewInfo> all) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown //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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) foreach (Row row2 in _rows) { if (!Ui.Dead((Object)(object)row2.Root)) { Object.Destroy((Object)(object)((Component)row2.Root).gameObject); } } _rows.Clear(); for (int i = 0; i < all.Count; i++) { CrewInfo crewInfo = all[i]; string crewId = crewInfo.Id; RectTransform val = Ui.Row((Transform)(object)_host, delegate { _shell.RunGuarded("crews.opencrew", delegate { _shell.Push(new CrewDetailPage(crewId)); }); }, 56f, chevron: true, "crews.row"); Row row = new Row { Root = (RectTransform)((Transform)val).parent, CrewId = crewId, Face = PageKit.FaceSlot.Build((Transform)(object)val, crewInfo.Leader?.NpcId, crewId, Theme.Accent(crewInfo.Color).Text, 44f) }; RectTransform val2 = Ui.VStack((Transform)(object)val, 2f); Ui.Fill((Component)(object)val2); row.Name = Ui.Text((Transform)(object)val2, crewInfo.Name, 15f, Theme.Text, bold: true, (TextAlignmentOptions)513); row.Status = Ui.Text((Transform)(object)val2, string.Empty, 13f, Theme.Text2, bold: false, (TextAlignmentOptions)513); _rows.Add(row); } } } internal enum TabId { Overview, Crews, Calendar, Settings } internal interface IAppPage { string Title { get; } void Build(RectTransform content, AppShell shell); void OnShow(); void Refresh(); void OnHide(); } internal interface IAppSheet { string Title { get; } void Build(RectTransform body, AppShell shell); void Refresh(); void OnClose(); } internal sealed class OverviewPage : IAppPage { private sealed class CrewRowUi { internal RectTransform Root; internal PageKit.FaceSlot Face; internal TextMeshProUGUI Name; internal TextMeshProUGUI Status; } private AppShell _shell; private RectTransform _bannerRow; private TextMeshProUGUI _bannerText; private Image _bannerIcon; private bool _bannerDismissed; private string _bannerShownFor; private RectTransform _heroFaceHost; private PageKit.FaceSlot _heroFace; private Chip _heroStatusChip; private TextMeshProUGUI _heroName; private TextMeshProUGUI _heroSub; private LiveText _heroCountdownLabel; private LiveText _heroCountdownBig; private TextMeshProUGUI _heroChanceSuffix; private TextMeshProUGUI _insetBuyCaption; private TextMeshProUGUI _insetBuyValue; private TextMeshProUGUI _insetDayCaption; private TextMeshProUGUI _insetDayValue; private RectTransform _insetRow; private Button _heroButton; private Action _heroAction = delegate { }; private readonly Dictionary<string, CrewRowUi> _otherRows = new Dictionary<string, CrewRowUi>(StringComparer.Ordinal); private RectTransform _otherRowsHost; private RectTransform _otherRowsLabel; private int _lastCrewCount = -1; public string Title => "Overview"; public void Build(RectTransform content, AppShell shell) { PageKit.EnsureLiveRefreshWired(); _shell = shell; BuildBanner((Transform)(object)content); BuildHero((Transform)(object)content); _otherRowsLabel = Ui.SectionLabel((Transform)(object)content, "All crews"); _otherRowsHost = Ui.VStack((Transform)(object)content, 12f); ((Object)_otherRowsHost).name = "OtherCrews"; Refresh(); } public void OnShow() { Refresh(); } public void OnHide() { } public void Refresh() { Snapshot now = Crews.Now; RefreshBanner(now); RefreshHero(now); RefreshOtherCrews(now); } private void BuildBanner(Transform parent) { //IL_003b: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) _bannerRow = Ui.HStack(parent, 10f, (TextAnchor)3); ((Object)_bannerRow).name = "Banner"; Ui.Pad(_bannerRow, 14, 10, 10, 10); Ui.Img((Component)(object)_bannerRow, Theme.Card2, Sprites.Rounded(16), raycast: true); Ui.AddOutline(_bannerRow, 16, Theme.Border); _bannerIcon = Ui.Icon((Transform)(object)_bannerRow, "info", 16f, Theme.Text2); _bannerText = Ui.Wrap(Ui.Text((Transform)(object)_bannerRow, string.Empty, 13f, Theme.