Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate-beta"
Decompiled source of EmployeeManager v1.5.4
EmployeeManager.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using Il2CppFishNet.Object; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Employees; using Il2CppScheduleOne.Messaging; using Il2CppScheduleOne.Money; using Il2CppScheduleOne.NPCs; using Il2CppScheduleOne.ObjectScripts; using Il2CppScheduleOne.Property; using Il2CppScheduleOne.Storage; using Il2CppScheduleOne.UI; using Il2CppScheduleOne.UI.Phone.ContactsApp; using Il2CppScheduleOne.UI.Phone.Messages; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using SharedModUtils; using TestBot; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Mod), "Employee Manager", "1.5.4", "Akermi", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("EmployeeManager")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+288f51365ff6c248a4c8d2c77ae4305de84aec86")] [assembly: AssemblyProduct("EmployeeManager")] [assembly: AssemblyTitle("EmployeeManager")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } public static class BotManagerStaticUtils { public static Transform[] GetIdleTransformsForProperty(string propertyName, int count) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Transform[] array = (Transform[])(object)new Transform[count]; if (propertyName.Contains("Barn")) { float num = 176.6752f; float num2 = -18f; float num3 = 0.5f; float num4 = 1.2f; int num5 = 5; for (int i = 0; i < count; i++) { int num6 = i / num5; int num7 = i % num5; float num8 = num + (float)num7 * num4; float num9 = num2 + (float)num6 * num4; GameObject val = new GameObject($"IdlePoint_{i}_{propertyName}"); val.transform.position = new Vector3(num8, num3, num9); array[i] = val.transform; } } return array; } } public static class EmployeeConfigManager { public static Dictionary<string, int> PropertyCapacities = new Dictionary<string, int>(); private static readonly string ConfigPath = Path.Combine(MelonEnvironment.UserDataDirectory, "Mods", "Configs", "employee_config.json"); private static string NormalizeName(string name) { return name?.Replace(" ", "").Trim().ToLowerInvariant(); } public static void LoadConfig() { try { if (!File.Exists(ConfigPath)) { Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath)); MelonLogger.Msg("[EmployeeManager] No config found. Starting fresh. " + ConfigPath); return; } Dictionary<string, int> obj = JsonConvert.DeserializeObject<Dictionary<string, int>>(File.ReadAllText(ConfigPath)) ?? new Dictionary<string, int>(); PropertyCapacities = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> item in obj) { string key = NormalizeName(item.Key); if (!PropertyCapacities.ContainsKey(key)) { PropertyCapacities[key] = item.Value; } } MelonLogger.Msg($"[EmployeeManager] Loaded {PropertyCapacities.Count} capacities."); } catch (Exception ex) { MelonLogger.Msg("[EmployeeManager] Failed to load config: " + ex.Message); PropertyCapacities = new Dictionary<string, int>(); } } public static void SaveConfig() { try { Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath)); string contents = JsonConvert.SerializeObject((object)PropertyCapacities, (Formatting)1); File.WriteAllText(ConfigPath, contents); MelonLogger.Msg("[EmployeeManager] Config saved."); } catch (Exception ex) { MelonLogger.Error("[EmployeeManager] Failed to save config: " + ex.Message); } } public static int GetCapacity(string propertyName, int fallback = 10) { string key = NormalizeName(propertyName); if (!PropertyCapacities.TryGetValue(key, out var value)) { return fallback; } return value; } public static void SetCapacity(string propertyName, int value) { string text = NormalizeName(propertyName); if (string.IsNullOrWhiteSpace(text)) { MelonLogger.Msg("[EmployeeManager] Skipped saving capacity for unnamed property."); return; } PropertyCapacities[text] = value; MelonLogger.Msg($"[EmployeeManager] Saved capacity for {propertyName}: {value}"); } public static bool HasCapacity(string propertyName) { string text = NormalizeName(propertyName); if (!string.IsNullOrWhiteSpace(text)) { return PropertyCapacities.ContainsKey(text); } return false; } } namespace SharedModUtils { public static class WageUtils { public static bool TryPayAllUnpaidEmployees(EmployeeManager employeeManager, out float totalCost, out string error) { totalCost = 0f; error = null; if ((Object)(object)employeeManager == (Object)null) { error = "Employee manager is not available."; return false; } for (int i = 0; i < employeeManager.AllEmployees._size; i++) { Employee val = employeeManager.AllEmployees[i]; if (!val.PaidForToday) { totalCost += val.DailyWage; } } float cashBalance = NetworkSingleton<MoneyManager>.instance.cashBalance; if (totalCost > cashBalance) { error = $"Wages (${totalCost}) exceed bank balance (${cashBalance})."; return false; } for (int j = 0; j < employeeManager.AllEmployees._size; j++) { employeeManager.AllEmployees[j].PaidForToday = true; } NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - totalCost, true, false); return true; } public static float GetTotalUnpaidWages(EmployeeManager employeeMgr) { if ((Object)(object)employeeMgr == (Object)null || employeeMgr.AllEmployees == null) { return 0f; } float num = 0f; for (int i = 0; i < employeeMgr.AllEmployees._size; i++) { Employee val = employeeMgr.AllEmployees[i]; if ((Object)(object)val != (Object)null && !val.PaidForToday) { num += val.DailyWage; } } return num; } public static float GetTotalUnpaidWagesForProperty(Property prop) { float num = 0f; Enumerator<Employee> enumerator = prop.Employees.GetEnumerator(); while (enumerator.MoveNext()) { Employee current = enumerator.Current; if (!current.PaidForToday) { num += current.DailyWage; } } return num; } public static bool TryPayUnpaidEmployeesForProperty(Property prop, out float cost, out string error) { cost = GetTotalUnpaidWagesForProperty(prop); error = ""; if (cost <= 0f) { return true; } if (NetworkSingleton<MoneyManager>.Instance.cashBalance < cost) { error = "Not enough cash."; return false; } NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - cost, true, false); Enumerator<Employee> enumerator = prop.Employees.GetEnumerator(); while (enumerator.MoveNext()) { Employee current = enumerator.Current; if (!current.PaidForToday) { current.SetIsPaid(); } } return true; } } } namespace Testbot { public class Property { public static IntPtr NativeFieldInfoPtr_EmployeeCapacity; static Property() { NativeFieldInfoPtr_EmployeeCapacity = IL2CPP.GetIl2CppField(Il2CppClassPointerStore<Property>.NativeClassPtr, "EmployeeCapacity"); } } } namespace TestBot { public class BotManager { [CompilerGenerated] private sealed class <WaitForSystems>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForSystems>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private TestDialogue _dialogue; private GameObject _npcObject; private NPC _npc; private Mod _mod; private const int EmployeesPerPage = 6; [IteratorStateMachine(typeof(<WaitForSystems>d__3))] public static IEnumerator WaitForSystems() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForSystems>d__3(0); } public static BotManager Create(Mod mod) { BotManager botManager = new BotManager(); botManager.Init(); botManager._mod = mod; return botManager; } private void Init() { NPC val = null; List<NPC> nPCRegistry = NPCManager.NPCRegistry; for (int i = 0; i < nPCRegistry.Count; i++) { NPC val2 = nPCRegistry[i]; if ((Object)(object)val2 != (Object)null && val2.FirstName == "Beth") { val = val2; break; } } if (!((Object)(object)val == (Object)null)) { _npcObject = Object.Instantiate<GameObject>(((Component)val).gameObject); _npc = _npcObject.GetComponent<NPC>(); _npc.FirstName = "Employee"; _npc.LastName = "Manager"; _npc.BakedGUID = Guid.NewGuid().ToString(); _npc.IsImportant = true; _npc.ConversationCanBeHidden = false; _npc.ShowRelationshipInfo = false; _npc.MSGConversation = null; _npc.ConversationCategories = new List<EConversationCategory>(); _npc.dialogueHandler = null; _npc.MugshotSprite = ((App<ContactsApp>)(object)PlayerSingleton<ContactsApp>.Instance).AppIcon; _npcObject.SetActive(true); ((Component)_npc).gameObject.SetActive(true); _npc.Awake(); ((NetworkBehaviour)_npc).NetworkInitializeIfDisabled(); NPCManager.NPCRegistry.Add(_npc); _npc.InitializeSaveable(); _dialogue = new TestDialogue(_npc); Run(); } } private void Run() { _dialogue.SendNPCMessage("Hello!"); _dialogue.SendNPCMessage("I'm here to help you manage your employees"); _dialogue.ShowResponses(new DialogueResponse[2] { new DialogueResponse("Manage properties", "Manage properties", ShowOwnedPropertiesMenu), new DialogueResponse("Pay employees", "Pay employees", ShowPayOptions) }, 0.5f); } private Transform[] GetIdleTransformsForProperty(string propertyName, int count) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) Transform[] array = (Transform[])(object)new Transform[count]; string text = propertyName.Replace(" ", "").ToLowerInvariant(); Property val = null; Enumerator<Property> enumerator = Property.Properties.GetEnumerator(); while (enumerator.MoveNext()) { Property current = enumerator.Current; if (current.PropertyName != null && current.PropertyName.Replace(" ", "").ToLowerInvariant() == text) { val = current; break; } } if ((Object)(object)val == (Object)null || (Object)(object)val.SpawnPoint == (Object)null) { MelonLogger.Warning("[EmployeeManager] Couldn't find spawn point for property: " + propertyName); return array; } Vector3 position = val.SpawnPoint.position; float num = 1.2f; int num2 = 5; for (int i = 0; i < count; i++) { int num3 = i / num2; int num4 = i % num2; float num5 = position.x + (float)num4 * num; float num6 = position.z + (float)num3 * num; float y = position.y; GameObject val2 = new GameObject($"IdlePoint_{i}_{propertyName}"); val2.transform.position = new Vector3(num5, y, num6); array[i] = val2.transform; } return array; } private void ShowOwnedPropertiesMenu() { List<DialogueResponse> list = new List<DialogueResponse>(); Enumerator<Property> enumerator = Property.Properties.GetEnumerator(); while (enumerator.MoveNext()) { Property prop = enumerator.Current; if (prop.IsOwned && prop.PropertyName != null) { int capacity = EmployeeConfigManager.GetCapacity(prop.PropertyName); if (prop.EmployeeCapacity < capacity) { prop.EmployeeCapacity = capacity; } prop.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(GetIdleTransformsForProperty(prop.PropertyName, prop.EmployeeCapacity)); list.Add(new DialogueResponse($"{prop.PropertyName} (Cap: {prop.EmployeeCapacity})", $"{prop.PropertyName} (Cap: {prop.EmployeeCapacity})", delegate { ShowPropertyActions(prop); })); } } if (list.Count == 0) { _dialogue.SendNPCMessage("You don't own any properties yet."); return; } list.Add(new DialogueResponse("BACK", "Back", Run)); _dialogue.ShowResponses(list.ToArray(), 0.5f); } private void ShowPropertyEmployeesWithBeds(Property prop, int page = 0) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) Property prop2 = prop; List<Employee> employees = prop2.Employees; if (employees == null || employees.Count == 0) { _dialogue.SendNPCMessage("No employees found in " + prop2.PropertyName + "."); return; } List<DialogueResponse> list = new List<DialogueResponse>(); int count = employees.Count; int num = Mathf.CeilToInt((float)count / 6f); int num2 = page * 6; int num3 = Mathf.Min(num2 + 6, count); for (int i = num2; i < num3; i++) { Employee emp = employees[i]; if (!((Object)(object)emp == (Object)null)) { BedItem bed = emp.GetBed(); string value = (((Object)(object)bed != (Object)null) ? $"→ Bed at {((Component)bed).transform.position}" : "→ No bed assigned"); list.Add(new DialogueResponse($"{((NPC)emp).FirstName} {((NPC)emp).LastName} ({((Object)emp).name})", $"{((NPC)emp).FirstName} {((NPC)emp).LastName} {value}", delegate { OpenEmployeeBed(emp); })); } } if (page > 0) { list.Add(new DialogueResponse("← Previous", "Previous Page", delegate { ShowPropertyEmployeesWithBeds(prop2, page - 1); })); } if (page < num - 1) { list.Add(new DialogueResponse("→ Next", "Next Page", delegate { ShowPropertyEmployeesWithBeds(prop2, page + 1); })); } list.Add(new DialogueResponse("↩ Back", "Back", delegate { ShowPropertyActions(prop2); })); _dialogue.SendNPCMessage($"Showing employees in {prop2.PropertyName} (Page {page + 1} of {num})"); _dialogue.ShowResponses(list.ToArray(), 0.5f); } private void OpenEmployeeBed(Employee employee) { BedItem bed = employee.GetBed(); if ((Object)(object)bed == (Object)null) { _dialogue.SendNPCMessage(((NPC)employee).FirstName + " has no assigned bed."); return; } StorageEntity storageEntity = ((PlaceableStorageEntity)bed).StorageEntity; if ((Object)(object)storageEntity == (Object)null) { _dialogue.SendNPCMessage("Bed found, but not a valid storage."); return; } GameplayMenu val = Object.FindObjectOfType<GameplayMenu>(); if ((Object)(object)val != (Object)null) { val.SetIsOpen(false); } _dialogue.SendPlayerMessage("Opened bed storage for " + ((NPC)employee).FirstName); Singleton<StorageMenu>.Instance.Open(storageEntity); } private void ShowPayOptions() { List<DialogueResponse> list = new List<DialogueResponse> { new DialogueResponse("Pay all employees", "Pay all", delegate { EmployeeManager employeeManager = Object.FindObjectOfType<EmployeeManager>(); float totalUnpaidWages = WageUtils.GetTotalUnpaidWages(employeeManager); if (totalUnpaidWages <= 0f) { _dialogue.SendNPCMessage("All employees are already paid for today."); } else { _dialogue.SendNPCMessage($"Pay total wages for ${totalUnpaidWages}?"); _dialogue.ShowResponses(new DialogueResponse[2] { new DialogueResponse("Yes", "Confirm", delegate { if (WageUtils.TryPayAllUnpaidEmployees(employeeManager, out float totalCost, out string error)) { _dialogue.SendPlayerMessage($"Paid ${totalCost} in wages."); _dialogue.SendNPCMessage("All employees are now paid."); } else { _dialogue.SendNPCMessage("Payment failed: " + error); } ShowPayOptions(); }), new DialogueResponse("Back", "Back", ShowPayOptions) }, 0.3f); } }), new DialogueResponse("Pay by property", "Per property", ShowPropertyPayList), new DialogueResponse("Back", "Back", Run) }; _dialogue.ShowResponses(list.ToArray(), 0.4f); } private void ShowPropertyPayList() { List<DialogueResponse> list = new List<DialogueResponse>(); Enumerator<Property> enumerator = Property.OwnedProperties.GetEnumerator(); while (enumerator.MoveNext()) { Property prop = enumerator.Current; if (prop.PropertyName == null || prop.Employees == null || prop.Employees.Count == 0) { continue; } float propWages = WageUtils.GetTotalUnpaidWagesForProperty(prop); string text = $"{prop.PropertyName} (${propWages})"; list.Add(new DialogueResponse(text, text, delegate { if (propWages <= 0f) { _dialogue.SendNPCMessage("All employees at " + prop.PropertyName + " are paid."); ShowPropertyPayList(); } else { _dialogue.SendNPCMessage($"Pay ${propWages} for {prop.PropertyName}?"); _dialogue.ShowResponses(new DialogueResponse[2] { new DialogueResponse("Yes", "Confirm", delegate { if (WageUtils.TryPayUnpaidEmployeesForProperty(prop, out float cost, out string error)) { _dialogue.SendPlayerMessage($"Paid ${cost} for {prop.PropertyName}."); _dialogue.SendNPCMessage("Done."); } else { _dialogue.SendNPCMessage("Failed: " + error); } ShowPropertyPayList(); }), new DialogueResponse("Back", "Back", ShowPropertyPayList) }, 0.3f); } })); } list.Add(new DialogueResponse("Back", "Back", ShowPayOptions)); _dialogue.ShowResponses(list.ToArray(), 0.4f); } private void ShowPropertyActions(Property prop) { Property prop2 = prop; List<DialogueResponse> list = new List<DialogueResponse>(); list.Add(new DialogueResponse("Increase capacity", "Increase capacity", delegate { Property obj = prop2; obj.EmployeeCapacity += 1; EmployeeConfigManager.SetCapacity(prop2.PropertyName, prop2.EmployeeCapacity); prop2.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(GetIdleTransformsForProperty(prop2.PropertyName, prop2.EmployeeCapacity)); _dialogue.SendPlayerMessage($"Increased capacity of {prop2.PropertyName} to {prop2.EmployeeCapacity}"); _dialogue.SendNPCMessage($"Capacity is now {prop2.EmployeeCapacity}"); EmployeeConfigManager.SaveConfig(); ShowPropertyActions(prop2); })); list.Add(new DialogueResponse("List beds", "List beds", delegate { ShowPropertyEmployeesWithBeds(prop2); })); AddHireOption("Hire Cleaner ($1,500)", 1500, "cleaner", prop2, list); AddHireOption("Hire Botanist ($1,500)", 1500, "botanist", prop2, list); AddHireOption("Hire Handler ($1,500)", 1500, "handler", prop2, list); AddHireOption("Hire Chemist ($2,000)", 2000, "chemist", prop2, list); list.Add(new DialogueResponse("Back", "Back", ShowOwnedPropertiesMenu)); _dialogue.ShowResponses(list.ToArray(), 0.5f); } private void AddHireOption(string label, int fee, string employeeType, Property prop, List<DialogueResponse> responses) { string employeeType2 = employeeType; Property prop2 = prop; responses.Add(new DialogueResponse(label, label, delegate { _dialogue.SendNPCMessage($"Hiring a {employeeType2} at {prop2.PropertyName} will cost you ${fee}. Do you want to proceed?"); _dialogue.ShowResponses(new DialogueResponse[2] { new DialogueResponse("Yes, hire", "Confirm hire", delegate { if (NetworkSingleton<MoneyManager>.Instance.cashBalance < (float)fee) { _dialogue.SendNPCMessage($"You don't have enough money. Required: ${fee}"); } else { NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance((float)(-fee), true, false); string text = prop2.PropertyName.Replace(" ", "").ToLowerInvariant(); Console.SubmitCommand("addemployee " + employeeType2 + " " + text); _dialogue.SendPlayerMessage($"Hired new {employeeType2} at {prop2.PropertyName} for ${fee}"); _dialogue.SendNPCMessage("The employee is on their way."); ShowPropertyActions(prop2); } }), new DialogueResponse("No", "Cancel", delegate { _dialogue.SendPlayerMessage("Cancelled hiring."); ShowPropertyActions(prop2); }) }, 0.3f); })); } public void Cleanup() { if ((Object)(object)_npcObject != (Object)null) { Object.Destroy((Object)(object)_npcObject); } if ((Object)(object)_npc != (Object)null && NPCManager.NPCRegistry.Contains(_npc)) { NPCManager.NPCRegistry.Remove(_npc); } } } public class DialogueResponse { public string Id; public string Text; public Action Action; public DialogueResponse[] NextResponses; public bool DisableDefaultBehavior; public DialogueResponse(string id, string text, Action action, bool disableDefaultBehavior = true, DialogueResponse[] next = null) { Id = id; Text = text; Action = action; DisableDefaultBehavior = disableDefaultBehavior; NextResponses = next; } } public class Mod : MelonMod { [CompilerGenerated] private sealed class <Initialize>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Mod <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <Initialize>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; Mod mod = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = BotManager.WaitForSystems(); <>1__state = 1; return true; case 1: <>1__state = -1; ((MelonBase)mod).LoggerInstance.Msg("[Employee_Manager] BotManager..."); mod._botManager = BotManager.Create(mod); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForPropertyRestoreThenPatch>d__4 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private bool <hasTargetProps>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForPropertyRestoreThenPatch>d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; goto IL_003b; case 1: <>1__state = -1; goto IL_003b; case 2: { <>1__state = -1; break; } IL_003b: if (Property.Properties == null || Property.Properties.Count == 0) { <>2__current = null; <>1__state = 1; return true; } <hasTargetProps>5__2 = false; break; } Enumerator<Property> enumerator; while (!<hasTargetProps>5__2) { enumerator = Property.Properties.GetEnumerator(); while (enumerator.MoveNext()) { Property current = enumerator.Current; if ((current.IsOwned || EmployeeConfigManager.HasCapacity(current.PropertyName)) && current.PropertyName != null) { <hasTargetProps>5__2 = true; break; } } if (!<hasTargetProps>5__2) { <>2__current = null; <>1__state = 2; return true; } } enumerator = Property.Properties.GetEnumerator(); while (enumerator.MoveNext()) { Property current2 = enumerator.Current; if (string.IsNullOrWhiteSpace(current2.PropertyName)) { MelonLogger.Warning("[EmployeeManager] Skipping unnamed property."); continue; } if (!current2.IsOwned && !EmployeeConfigManager.HasCapacity(current2.PropertyName)) { MelonLogger.Msg("[EmployeeManager] Skipping " + current2.PropertyName + " — not owned and not saved."); continue; } int capacity = EmployeeConfigManager.GetCapacity(current2.PropertyName); current2.EmployeeCapacity = capacity; current2.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(BotManagerStaticUtils.GetIdleTransformsForProperty(current2.PropertyName, current2.EmployeeCapacity)); MelonLogger.Msg($"[✔] Patched {current2.PropertyName} → capacity: {current2.EmployeeCapacity}, idlePoints: {((Il2CppArrayBase<Transform>)(object)current2.EmployeeIdlePoints)?.Length}"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private BotManager _botManager; public override void OnInitializeMelon() { EmployeeConfigManager.LoadConfig(); MelonLogger.Msg("[Employee_Manager] Config loaded."); } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { ((MelonBase)this).LoggerInstance.Msg("Scene loaded: " + sceneName); if (sceneName == "Main") { MelonCoroutines.Start(Initialize()); MelonCoroutines.Start(WaitForPropertyRestoreThenPatch()); } } [IteratorStateMachine(typeof(<Initialize>d__3))] private IEnumerator Initialize() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <Initialize>d__3(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<WaitForPropertyRestoreThenPatch>d__4))] private IEnumerator WaitForPropertyRestoreThenPatch() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForPropertyRestoreThenPatch>d__4(0); } public override void OnSceneWasUnloaded(int buildIndex, string sceneName) { if (!(sceneName == "Main")) { return; } Enumerator<Property> enumerator = Property.Properties.GetEnumerator(); while (enumerator.MoveNext()) { Property current = enumerator.Current; if (current.IsOwned && current.PropertyName != null) { EmployeeConfigManager.SetCapacity(current.PropertyName, current.EmployeeCapacity); MelonLogger.Msg($"[\ud83d\udcbe] Saved {current.PropertyName} = {current.EmployeeCapacity}"); } } EmployeeConfigManager.SaveConfig(); _botManager?.Cleanup(); _botManager = null; } } public class TestDialogue { [CompilerGenerated] private sealed class <DelayedShowResponses>d__0 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public float delay; public TestDialogue <>4__this; public DialogueResponse[] next; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedShowResponses>d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown int num = <>1__state; TestDialogue testDialogue = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(delay); <>1__state = 1; return true; case 1: <>1__state = -1; testDialogue.ShowResponses(next, 0.1f); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly NPC _npc; private readonly MSGConversation _conversation; [IteratorStateMachine(typeof(<DelayedShowResponses>d__0))] private IEnumerator DelayedShowResponses(float delay, DialogueResponse[] next) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedShowResponses>d__0(0) { <>4__this = this, delay = delay, next = next }; } public TestDialogue(NPC npc) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown _npc = npc; _conversation = new MSGConversation(npc, npc.fullName); _npc.MSGConversation = _conversation; _conversation.messageHistory = new List<Message>(); _conversation.messageChainHistory = new List<MessageChain>(); _conversation.bubbles = new List<MessageBubble>(); _conversation.EntryVisible = true; if (_npc.ConversationCategories == null) { _npc.ConversationCategories = new List<EConversationCategory>(); _npc.ConversationCategories.Add((EConversationCategory)0); } _conversation.SetCategories(_npc.ConversationCategories); } public void SendNPCMessage(string text) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown Message val = new Message(text, (ESenderType)1, true, -1); _conversation.SendMessage(val, true, false); } public void SendPlayerMessage(string text) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Expected O, but got Unknown Message val = new Message(text, (ESenderType)0, true, -1); _conversation.SendMessage(val, true, false); } public void ShowResponses(DialogueResponse[] responses, float v) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown List<Response> val = new List<Response>(); foreach (DialogueResponse response in responses) { Action action = response.Action; Action action2 = delegate { action?.Invoke(); if (response.NextResponses != null && response.NextResponses.Length != 0) { MelonCoroutines.Start(DelayedShowResponses(0.5f, response.NextResponses)); } }; val.Add(new Response(response.Id, response.Text, Action.op_Implicit(action2), response.DisableDefaultBehavior)); } _conversation.ClearResponses(false); _conversation.ShowResponses(val, 0f, false); } } }