using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using Cysharp.Threading.Tasks; using Damntry.Utils.Collections.Queues; using Damntry.Utils.Collections.Queues.Interfaces; using Damntry.Utils.Events; using Damntry.Utils.ExtensionMethods; using Damntry.Utils.Logging; using Damntry.Utils.Reflection; using Damntry.Utils.Tasks; using Damntry.Utils.Tasks.AsyncDelay; using Damntry.Utils.Timers; using Damntry.Utils.Timers.StopwatchImpl; using Damntry.UtilsBepInEx.Components; using Damntry.UtilsBepInEx.Configuration; using Damntry.UtilsBepInEx.Configuration.ConfigurationManager; using Damntry.UtilsBepInEx.Configuration.ConfigurationManager.SettingAttributes; using Damntry.UtilsBepInEx.Debug; using Damntry.UtilsBepInEx.HarmonyPatching; using Damntry.UtilsBepInEx.HarmonyPatching.Attributes; using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching; using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Attributes; using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses; using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.BaseClasses.Inheritable; using Damntry.UtilsBepInEx.HarmonyPatching.AutoPatching.Interfaces; using Damntry.UtilsBepInEx.HarmonyPatching.Exceptions; using Damntry.UtilsBepInEx.IL; using Damntry.UtilsBepInEx.Logging; using Damntry.UtilsBepInEx.ModHelpers; using Damntry.UtilsMirror.Attributes; using Damntry.UtilsMirror.Components; using Damntry.UtilsMirror.Helpers; using Damntry.UtilsMirror.SyncVar; using Damntry.UtilsUnity.Components.InputManagement; using Damntry.UtilsUnity.Components.InputManagement.Model; using Damntry.UtilsUnity.ExtensionMethods; using Damntry.UtilsUnity.Rendering; using Damntry.UtilsUnity.Resources; using Damntry.UtilsUnity.Tasks.AsyncDelay; using Damntry.UtilsUnity.Timers; using Damntry.UtilsUnity.UI; using Damntry.UtilsUnity.UI.Extensions; using Damntry.UtilsUnity.Vectors; using HarmonyLib; using HighlightPlus; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using Microsoft.CodeAnalysis; using Mirror; using Mirror.RemoteCalls; using Rewired; using Rito.RadialMenu_v3; using StarterAssets; using Steamworks; using SuperQoLity.SuperMarket.ModUtils; using SuperQoLity.SuperMarket.ModUtils.ExternalMods; using SuperQoLity.SuperMarket.ModUtils.Messaging; using SuperQoLity.SuperMarket.ModUtils.UI; using SuperQoLity.SuperMarket.PatchClassHelpers.Components; using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities; using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.Search; using SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.ShelfSlotInfo; using SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.Model; using SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.RadialWheel; using SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.RadialWheel.Model; using SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting; using SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting.Caching; using SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting.Definitions; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Customers; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Component; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Helpers; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Models; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.AutoMode; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.AutoMode.DataDefinition; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.Helpers; using SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Movement; using SuperQoLity.SuperMarket.PatchClassHelpers.Networking.SyncVarBehaviours; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Definitions; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Definitions.Interfaces; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Helpers; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Helpers.Model; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Model; using SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Helpers; using SuperQoLity.SuperMarket.Patches.BroomShotgun; using SuperQoLity.SuperMarket.Patches.Building; using SuperQoLity.SuperMarket.Patches.EquipmentWheel; using SuperQoLity.SuperMarket.Patches.Highlighting; using SuperQoLity.SuperMarket.Patches.Misc; using SuperQoLity.SuperMarket.Patches.NPC; using SuperQoLity.SuperMarket.Patches.NPC.Customer; using SuperQoLity.SuperMarket.Patches.NPC.EmployeeModule; using SuperQoLity.SuperMarket.Patches.TransferItemsModule; using SuperQoLity.SuperMarket.Standalone; using SuperQoLity.SuperMarket.Standalone.Components; using SuperQoLity.SuperMarket.Standalone.MainMenuLogo; using SuperQoLity.SuperMarket.Standalone.MainMenuLogo.Fsm; using TMPro; using TeoGames.Mesh_Combiner.Scripts.Combine; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations.Rigging; using UnityEngine.Events; using UnityEngine.Experimental.Rendering; using UnityEngine.Networking; using UnityEngine.Profiling; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityHotReloadNS; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("None")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Bepinex plugin for Supermarket Together adding extra QoL features")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2.0+c4b32d218afa47503040f7dcdb612726fce98e4b")] [assembly: AssemblyProduct("es.damntry.SuperQoLity")] [assembly: AssemblyTitle("SuperQoLity")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal delegate TResult <>f__AnonymousDelegate0(T1 arg = default(T1)); namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SuperQoLity { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("es.damntry.SuperQoLity", "SuperQoLity", "1.0.2.0")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private static class <>O { public static PreprocessMessageFunc <0>__RemoveSpecialNotifNewLinesForLog; } private static int AssetIdModSignature { get; } = 3071; public static bool IsSolutionInDebugMode { get; private set; } = false; public void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__RemoveSpecialNotifNewLinesForLog; if (obj == null) { PreprocessMessageFunc val = GameNotifications.RemoveSpecialNotifNewLinesForLog; <>O.<0>__RemoveSpecialNotifNewLinesForLog = val; obj = (object)val; } TimeLogger.InitializeTimeLogger((PreprocessMessageFunc)obj, false, new object[1] { "SuperQoLity" }); SolutionDebugModeHandler(); ModConfig.Instance.InitializeConfig((BaseUnityPlugin)(object)this); ConfigDebugModeHandler(); AutoPatcher.RegisterAllAutoPatchContainers(); ModConfig.Instance.StartConfigBinding(); GameNotifications.Instance.InitializeGameNotifications(); TaskExtensionMethods.FireAndForget(((InputDetection)InputManagerSMT.Instance).InitializeAsync((Func)(() => (MonoBehaviour)(object)FirstPersonController.Instance), (Func)(() => !AuxUtils.IsChatOpen())), (LogCategories)8); NetworkSpawnManager.Initialize(AssetIdModSignature); TimeLogger.Logger.LogDebug("SuperQoLity (es.damntry.SuperQoLity) initialization finished.", (LogCategories)8); bool flag = AutoPatcher.StartAutoPatcher(); CopyBuildableOnCursor.AddHotkeys(); MainMenuLogos.StartProcess(); StartingMessage.InitStartingMessages(flag); TimeLogger.Logger.LogMessage("Mod SuperQoLity (es.damntry.SuperQoLity) loaded " + (flag ? "" : "(not quite) ") + "successfully.", (LogCategories)8); } private void SetupHotReloading() { InputManagerSMT.Instance.TryAddHotkey("HotReload", (KeyCode)286, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }, (InputState)0, HotkeyActiveContext.AlwaysActiveHighPrio, async delegate { TimeLogger.Logger.LogMessageShowInGame("Beginning SuperQoLity Hot Reloading", (LogCategories)int.MinValue); await Task.Delay(100); UnityHotReload.LoadNewAssemblyVersion(((object)this).GetType().Assembly, "C:\\Users\\Damntry\\Visual Studio Projects\\Visual Studio 2019 Projects\\repos\\!Supermarket Together\\SupermarketTogether_SuperQoLity\\SMT_QoLity\\bin\\Debug\\net481\\SuperQoLity.dll"); TimeLogger.Logger.LogMessageShowInGame("Hot Reloading finished", (LogCategories)int.MinValue); }); } private void SolutionDebugModeHandler() { } public static void ConfigDebugModeHandler() { bool flag = ModConfig.Instance.IsDebugEnabledConfig(); if (flag != TimeLogger.DebugEnabled) { TimeLogger.DebugEnabled = flag; TimeLogger.Logger.LogWarning("SuperQoLity Debug Dev mode " + (flag ? "enabled" : "disabled") + ".", (LogCategories)8); } } public static void HookChangeDebugSetting() { ModConfig.Instance.EnabledDevMode.SettingChanged += delegate { ConfigDebugModeHandler(); }; } private CheckResult StartMethodSignatureCheck() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown try { MethodSignatureChecker val = new MethodSignatureChecker(((object)this).GetType()); val.PopulateMethodSignaturesFromHarmonyPatches(); val.AddMethod(typeof(NPC_Manager), "EmployeeNPCControl", new Type[1] { typeof(int) }, (Type[])null); val.AddMethod(typeof(NPC_Manager), "GetFreeStorageContainer", new Type[1] { typeof(int) }, (Type[])null); val.AddMethod(typeof(NPC_Manager), "MainRestockUpdate"); val.AddMethod(typeof(NPC_Manager), "CheckIfShelfWithSameProduct"); val.AddMethod(typeof(NPC_Manager), "GetRandomGroundBox"); val.AddMethod(typeof(NPC_Manager), "GetRandomGroundBoxAllowedInStorage"); val.AddMethod(typeof(NPC_Manager), "DropBoxOnGround"); val.AddMethod(typeof(NPC_Manager), "UnequipBox"); val.AddMethod(typeof(NPC_Manager), "AttemptToGetRestPosition"); val.AddMethod(typeof(NPC_Manager), "CashierGetAvailableCheckout"); val.AddMethod(typeof(NPC_Manager), "UpdateEmployeeCheckouts"); val.AddMethod(typeof(NPC_Manager), "CheckIfCustomerInQueue"); val.AddMethod(typeof(NPC_Manager), "GetThiefTarget"); val.AddMethod(typeof(NPC_Manager), "IsFirstSecurityEmployee"); val.AddMethod(typeof(NPC_Manager), "GetClosestDropProduct"); val.AddMethod(typeof(NPC_Manager), "RetrieveCorrectPatrolPoint"); val.AddMethod(typeof(NPC_Manager), "UpdateEmployeeStats"); return val.StartSignatureCheck(); } catch (Exception ex) { TimeLogger.Logger.LogException(ex, (LogCategories)4194304); return CheckResult.UnknownError; } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "es.damntry.SuperQoLity"; public const string PLUGIN_NAME = "SuperQoLity"; public const string PLUGIN_VERSION = "1.0.2.0"; public const string BETTERSMT_SUPPORTED_VERSION = "2.5.0"; } } namespace SuperQoLity.SuperMarket { public enum GameOnlineMode { None, Host, Client } public enum GameWorldEvent { QuitOrMenu, LoadingWorld, CanvasAwake, FPControllerStarted, WorldLoaded } public enum CharacterSourceType { LocalPlayer, RemotePlayer, Employee } public static class WorldState { public static class BuildingEvents { public static Action OnShelfBuiltOrLoaded; public static Action OnProductShelfLoadedBuiltOrUpdated; public static Action OnStorageLoadedBuiltOrUpdated; } public static class ContainerEvents { public static Action OnBoxSpawned; public static Action OnBoxEquippedOrUpdatedLocalPlayer; public static Action OnBoxEquippedRemotePlayerOrEmployee; public static Action OnBoxDroppedByPlayer; public static Action OnBoxIntoStorage; public static Action OnProdShelfAssigned; public static Action OnProdShelfUnassigned; } public static class PlayerEvents { public static Action OnChangeEquipment; } public static class NPC_Events { public static Action OnEmployeeSpawned; } public static Action OnGamePauseChanged; public static GameWorldEvent CurrentGameWorldState { get; private set; } public static GameOnlineMode CurrentOnlineMode { get; set; } public static bool IsWorldLoaded => CurrentGameWorldState == GameWorldEvent.WorldLoaded; public static bool IsHost => CurrentOnlineMode == GameOnlineMode.Host; public static bool IsClient => CurrentOnlineMode == GameOnlineMode.Client; public static event Action OnGameWorldChange; public static event Action OnQuitOrMainMenu; public static event Action OnLoadingWorld; public static event Action OnCanvasAwake; public static event Action OnFPControllerStarted; public static event Action OnWorldLoaded; public static bool IsGameWorldAtOrAfter(GameWorldEvent worldState) { return CurrentGameWorldState >= worldState; } public static void SetGameWorldState(GameWorldEvent state) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (state > CurrentGameWorldState || state == GameWorldEvent.QuitOrMenu) { TimeLogger.Logger.LogDebugFunc((Func)(() => "World state change from " + $"{CurrentGameWorldState} to {state}"), (LogCategories)8); CurrentGameWorldState = state; } else { LogTier val = (LogTier)((CurrentOnlineMode == GameOnlineMode.Client) ? 32 : 2); TimeLogger.Logger.LogFunc(val, (Func)(() => "World state wanted to change from " + $"{CurrentGameWorldState} to {state}, but it is not allowed."), (LogCategories)8, false, (ValueTuple, bool>[])null); } EventMethods.TryTriggerEvents(WorldState.OnGameWorldChange, state); EventMethods.TryTriggerEvents(GetSubscribersForWorldState(state)); } public static void SubscribeToWorldStateEvent(GameWorldEvent state, Action actionOnEvent) { switch (state) { case GameWorldEvent.QuitOrMenu: OnQuitOrMainMenu += actionOnEvent; break; case GameWorldEvent.LoadingWorld: OnLoadingWorld += actionOnEvent; break; case GameWorldEvent.CanvasAwake: OnCanvasAwake += actionOnEvent; break; case GameWorldEvent.FPControllerStarted: OnFPControllerStarted += actionOnEvent; break; case GameWorldEvent.WorldLoaded: OnWorldLoaded += actionOnEvent; break; } } public static void UnsubscribeFromWorldStateEvent(GameWorldEvent state, Action actionOnEvent) { switch (state) { case GameWorldEvent.QuitOrMenu: OnQuitOrMainMenu -= actionOnEvent; break; case GameWorldEvent.LoadingWorld: OnLoadingWorld -= actionOnEvent; break; case GameWorldEvent.CanvasAwake: OnCanvasAwake -= actionOnEvent; break; case GameWorldEvent.FPControllerStarted: OnFPControllerStarted -= actionOnEvent; break; case GameWorldEvent.WorldLoaded: OnWorldLoaded -= actionOnEvent; break; } } public static Action GetSubscribersForWorldState(GameWorldEvent state) { return state switch { GameWorldEvent.QuitOrMenu => WorldState.OnQuitOrMainMenu, GameWorldEvent.LoadingWorld => WorldState.OnLoadingWorld, GameWorldEvent.CanvasAwake => WorldState.OnCanvasAwake, GameWorldEvent.FPControllerStarted => WorldState.OnFPControllerStarted, GameWorldEvent.WorldLoaded => WorldState.OnWorldLoaded, _ => null, }; } } } namespace SuperQoLity.SuperMarket.Standalone { public class CopyBuildableOnCursor { private enum BuildTargetAction { Clone, Move } private record IndexSearchResult(bool Found, int TabIndex, int MenuIndex); public static void AddHotkeys() { InputManagerSMT.Instance.AddHotkeyFromConfig(ModConfig.Instance.CloneBuildHotkey, (InputState)0, HotkeyActiveContext.WorldLoadedNotPaused, BeginCloneBuildTarget); InputManagerSMT.Instance.AddHotkeyFromConfig(ModConfig.Instance.MoveBuildHotkey, (InputState)0, HotkeyActiveContext.WorldLoadedNotPaused, BeginMoveBuildTarget); } public static void BeginCloneBuildTarget() { BeginBuildTargetAction(BuildTargetAction.Clone); } public static void BeginMoveBuildTarget() { BeginBuildTargetAction(BuildTargetAction.Move); } private static void BeginBuildTargetAction(BuildTargetAction copyMode) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) Builder_Main val = SMTInstances.BuilderMain(); try { if (val.cCameraController.isInCameraEvent || FirstPersonController.Instance.inVehicle || !val.pComponent.RequestGP() || !val.pComponent.RequestMP() || val.pNetworkComponent.equippedItem == 5) { return; } if (copyMode == BuildTargetAction.Move && val.recentlyMoved) { if (Object.op_Implicit((Object)(object)val.hEffect)) { ((Behaviour)val.hEffect).enabled = false; } if (Object.op_Implicit((Object)(object)val.hEffect2)) { val.hEffect2.highlighted = false; } } else { RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward, ref val2, (float)ModConfig.Instance.CloneMoveTargetDistance.Value, LayerMask.op_Implicit(val.lMask))) { return; } Transform buildObj = ((RaycastHit)(ref val2)).transform; IndexSearchResult indexSearchResult = FindBuildMenuIndexes(val, ref buildObj); if (indexSearchResult.Found) { val.currentTabIndex = indexSearchResult.TabIndex; switch (copyMode) { case BuildTargetAction.Clone: val.currentElementIndex = indexSearchResult.MenuIndex; break; case BuildTargetAction.Move: val.currentElementIndex = 0; break; } val.DeactivateBuilder(); val.SetDummy(val.currentTabIndex, val.currentElementIndex); val.cCameraController.ChangeLayerMask(true); val.canvasBuilderOBJ.SetActive(true); if (copyMode == BuildTargetAction.Move && !MoveBehaviour(buildObj)) { val.canvasBuilderOBJ.SetActive(false); } } } } finally { if (!val.canvasBuilderOBJ.activeSelf) { val.DeactivateBuilder(); } } } private static IndexSearchResult FindBuildMenuIndexes(Builder_Main builderMain, ref Transform buildObj) { if (((Component)buildObj).CompareTag(Tags.Interactable)) { while (Object.op_Implicit((Object)(object)buildObj.parent) && !((Component)buildObj).CompareTag(Tags.Movable) && !((Component)buildObj).CompareTag(Tags.Decoration)) { buildObj = buildObj.parent; } } if (((Component)buildObj).CompareTag(Tags.Movable)) { Data_Container component = ((Component)buildObj).GetComponent(); return FindItemIdInBuildMenu(builderMain, 0, component.containerID); } if (((Component)buildObj).CompareTag(Tags.Decoration)) { BuildableInfo component2 = ((Component)buildObj).GetComponent(); for (int i = 1; i < builderMain.tabContainerOBJ.transform.childCount; i++) { IndexSearchResult indexSearchResult = FindItemIdInBuildMenu(builderMain, i, component2.decorationID); if (indexSearchResult.Found) { return indexSearchResult; } } } return new IndexSearchResult(Found: false, -1, -1); } private static IndexSearchResult FindItemIdInBuildMenu(Builder_Main builderMain, int tabIndex, int itemId) { Transform val = ((Component)builderMain.tabContainerOBJ.transform.GetChild(tabIndex)).transform.Find("Container"); for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i); if (Object.op_Implicit((Object)(object)((Component)child).GetComponent()) && ((Component)child).GetComponent().FsmVariables.GetFsmInt("PropIndex").Value == itemId) { return new IndexSearchResult(Found: true, tabIndex, i); } } return new IndexSearchResult(Found: false, -1, -1); } private static bool MoveBehaviour(Transform rayHit) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) Builder_Main val = SMTInstances.BuilderMain(); if (((Component)rayHit).CompareTag(Tags.Movable)) { if (Object.op_Implicit((Object)(object)val.oldHitOBJ2) && (Object)(object)((Component)rayHit).gameObject != (Object)(object)val.oldHitOBJ2 && Object.op_Implicit((Object)(object)val.hEffect2)) { val.hEffect2.highlighted = false; } val.hEffect2 = ((Component)rayHit).GetComponent(); val.hEffect2.highlighted = true; val.oldHitOBJ2 = ((Component)rayHit).gameObject; val.currentMovedOBJ = ((Component)rayHit).gameObject; Data_Container component = val.currentMovedOBJ.GetComponent(); component.AddMoveEffect(); val.buildableTag = component.buildableTag; GameObject dummyPrefab = component.dummyPrefab; val.dummyOBJ = Object.Instantiate(dummyPrefab, Vector3.zero, val.currentMovedOBJ.transform.rotation); val.canPlace = false; val.pmakerFSM = val.dummyOBJ.GetComponent(); if (Object.op_Implicit((Object)(object)val.hEffect2)) { val.hEffect2.highlighted = false; } return true; } if (((Component)rayHit).CompareTag(Tags.Decoration)) { if (Object.op_Implicit((Object)(object)val.oldHitOBJ) && (Object)(object)((Component)rayHit).gameObject != (Object)(object)val.oldHitOBJ && Object.op_Implicit((Object)(object)val.hEffect)) { ((Behaviour)val.hEffect).enabled = false; } val.hEffect = ((Component)rayHit.Find("Mesh")).GetComponent(); ((Behaviour)val.hEffect).enabled = true; val.oldHitOBJ = ((Component)rayHit).gameObject; val.currentMovedOBJ = ((Component)rayHit).gameObject; BuildableInfo component2 = val.currentMovedOBJ.GetComponent(); GameObject dummyPrefabOBJ = component2.dummyPrefabOBJ; val.dummyOBJ = Object.Instantiate(dummyPrefabOBJ, Vector3.zero, val.currentMovedOBJ.transform.rotation); val.RetrieveBuilderInfo(component2); val.canPlace = false; val.pmakerFSM = val.dummyOBJ.GetComponent(); if (Object.op_Implicit((Object)(object)val.hEffect)) { ((Behaviour)val.hEffect).enabled = false; } return true; } return false; } } } namespace SuperQoLity.SuperMarket.Standalone.MainMenuLogo { public static class MainMenuLogos { private static readonly string RelativeLogosFolderPath = "Assets\\MainMenuLogos"; public static readonly int ProductsInBetween = 5; public static readonly (float min, float max) LogoRotationYRange = (-30f, 70f); public static readonly Vector3 LogoLocalPositionOffset = new Vector3(0f, 0.05f, 0f); private static readonly float LogoTargetSize = 32f; public static async void StartProcess() { int failCounter = 5; PlayMakerFSM fsm = default(PlayMakerFSM); while (failCounter > 0) { Scene activeScene = SceneManager.GetActiveScene(); if (((Scene)(ref activeScene)).name == "A_Intro") { GameObject val = GameObject.Find("SpawnProductBehaviour"); if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent(ref fsm)) { List objectsFromLogos = GetObjectsFromLogos(GetVanillaMainMenuProduct(fsm)); if (objectsFromLogos.Count != 0) { ReplaceFsmActions(fsm, objectsFromLogos); } else { TimeLogger.Logger.LogWarning("No logo images where found in the subfolder '" + RelativeLogosFolderPath + "'. Make sure that the files have png or jpg extension.", (LogCategories)268435456); } break; } failCounter++; } await Task.Delay(500); } } private static GameObject GetVanillaMainMenuProduct(PlayMakerFSM fsm) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown return (GameObject)fsm.Fsm.GetFsmArray("PRoductArray").Get(0); } private static List GetObjectsFromLogos(GameObject vanillaMainMenuProduct) { List list = new List(); foreach (string item in from file in Directory.EnumerateFiles(AssemblyUtils.GetCombinedPathFromAssemblyFolder(typeof(Plugin), RelativeLogosFolderPath), "*.*", SearchOption.TopDirectoryOnly) where file.ToLower().EndsWith(".png") || file.ToLower().EndsWith(".jpg") select file) { TimeLogger.Logger.LogInfo("Found logo file: " + item, (LogCategories)268435456); list.Add(CreateProductObject(vanillaMainMenuProduct, item)); } return list; } private static GameObject CreateProductObject(GameObject vanillaMainMenuProduct, string filePath) { //IL_0067: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Object.Instantiate(vanillaMainMenuProduct); Component val = ((IEnumerable)obj.GetComponents()).FirstOrDefault((Func)((Component c) => ((object)c).ToString().Contains("Combinable"))); if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } Object.DestroyImmediate((Object)(object)obj.GetComponent()); Object.DestroyImmediate((Object)(object)obj.GetComponent()); SpriteRenderer obj2 = obj.AddComponent(); obj2.sprite = AssetLoading.GetSpriteFromFile(filePath, new Vector2(0.5f, 0f), (GraphicsFormat)4, true); Rect rect = obj2.sprite.rect; float num = Math.Max(((Rect)(ref rect)).width, ((Rect)(ref rect)).height); float num2 = (float)Math.Round(LogoTargetSize / num, 4); ((Component)obj2).transform.localScale = new Vector3(num2, num2, num2); return obj; } private static void ReplaceFsmActions(PlayMakerFSM fsm, List mainMenuLogos) { FsmState val = ((IEnumerable)fsm.FsmStates).FirstOrDefault((Func)((FsmState f) => f.Name == "SpawnRandom")); if (val == null) { return; } for (int i = 0; i < val.Actions.Length; i++) { FsmStateAction val2 = val.Actions[i]; ArrayGetRandom val3 = (ArrayGetRandom)(object)((val2 is ArrayGetRandom) ? val2 : null); if (val3 != null) { val.Actions[i] = (FsmStateAction)(object)new ArrayGetRandomButNotReally(val3, mainMenuLogos); continue; } RandomFloat val4 = (RandomFloat)(object)((val2 is RandomFloat) ? val2 : null); if (val4 != null) { val.Actions[i] = (FsmStateAction)(object)new RandomFloatButNotReally(val4); continue; } SetPosition val5 = (SetPosition)(object)((val2 is SetPosition) ? val2 : null); if (val5 != null) { val.Actions[i] = (FsmStateAction)(object)new SetPositionOffset(val5); } } val.SaveActions(); } } } namespace SuperQoLity.SuperMarket.Standalone.MainMenuLogo.Fsm { [ActionCategory(/*Could not decode attribute arguments.*/)] public class ArrayGetRandomButNotReally : ArrayGetRandom { private static int currentLogoArrayIndex; private int prodsUntilLogoCounter; private List mainMenuLogos; public static bool IsLastItemModLogo { get; private set; } public ArrayGetRandomButNotReally(ArrayGetRandom instance, List mainMenuLogos) { this.mainMenuLogos = mainMenuLogos; base.array = instance.array; base.storeValue = instance.storeValue; base.index = instance.index; base.noRepeat = instance.noRepeat; base.everyFrame = instance.everyFrame; base.randomIndex = instance.randomIndex; base.lastIndex = instance.lastIndex; prodsUntilLogoCounter = MainMenuLogos.ProductsInBetween; } public override void Reset() { mainMenuLogos = null; currentLogoArrayIndex = 0; prodsUntilLogoCounter = 0; prodsUntilLogoCounter = MainMenuLogos.ProductsInBetween; ((ArrayGetRandom)this).Reset(); } public override void OnEnter() { DoGetAlmostRandomValue(); if (!base.everyFrame) { ((FsmStateAction)this).Finish(); } } public override void OnUpdate() { DoGetAlmostRandomValue(); } private void DoGetAlmostRandomValue() { if (prodsUntilLogoCounter < MainMenuLogos.ProductsInBetween) { prodsUntilLogoCounter++; ((ArrayGetRandom)this).DoGetRandomValue(); IsLastItemModLogo = false; return; } base.storeValue.SetValue((object)mainMenuLogos[currentLogoArrayIndex++]); IsLastItemModLogo = true; if (currentLogoArrayIndex >= mainMenuLogos.Count) { prodsUntilLogoCounter = 0; currentLogoArrayIndex = 0; } } } [ActionCategory(/*Could not decode attribute arguments.*/)] public class RandomFloatButNotReally : RandomFloat { public RandomFloatButNotReally(RandomFloat instance) { base.min = instance.min; base.max = instance.max; base.storeResult = instance.storeResult; } public override void OnEnter() { float value = ((!ArrayGetRandomButNotReally.IsLastItemModLogo) ? Random.Range(base.min.Value, base.max.Value) : Random.Range(MainMenuLogos.LogoRotationYRange.min, MainMenuLogos.LogoRotationYRange.max)); base.storeResult.Value = value; ((FsmStateAction)this).Finish(); } } [ActionCategory(/*Could not decode attribute arguments.*/)] public class SetPositionOffset : SetPosition { public SetPositionOffset(SetPosition instance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) base.gameObject = instance.gameObject; base.vector = instance.vector; base.x = instance.x; base.y = instance.y; base.z = instance.z; base.space = instance.space; base.everyFrame = instance.everyFrame; base.lateUpdate = instance.lateUpdate; } public override void OnEnter() { if (!base.everyFrame && !base.lateUpdate) { DoSetPositionOffset(); ((FsmStateAction)this).Finish(); } } public override void OnUpdate() { if (!base.lateUpdate) { DoSetPositionOffset(); } } public override void OnLateUpdate() { if (base.lateUpdate) { DoSetPositionOffset(); } if (!base.everyFrame) { ((FsmStateAction)this).Finish(); } } private void DoSetPositionOffset() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) ((SetPosition)this).DoSetPosition(); if (ArrayGetRandomButNotReally.IsLastItemModLogo) { Transform cachedTransform = ((ComponentAction)this).cachedTransform; cachedTransform.localPosition += MainMenuLogos.LogoLocalPositionOffset; } } } } namespace SuperQoLity.SuperMarket.Standalone.Components { public class FrequencyMult_Display : MonoBehaviour { private static FrequencyMult_Display instance; private GameObject freqMultDisplay; private TextMeshProUGUI textDisplay; private (float employee, float customer) loopMultiplierCycles; private bool allowDisplay; private void Awake() { freqMultDisplay = GameObjectManager.CreateSuperQoLGameObject("JobWorkload_Display", TargetObject.UI_MasterCanvas, new CreationSettings(false, TransformType.Transform, TransformLocals.Inherited)); SetupUI(); instance = this; } private void Start() { DisplayLogicFromSetting(); ModConfig.Instance.DisplayAutoModeFrequencyMult.SettingChanged += delegate { DisplayLogicFromSetting(); }; JobSchedulerManager.OnNewJobFrequencyMultiplier += UpdateFreqMultiplierDisplay; } public static void Initialize() { GameObjectManager.AddComponentTo(TargetObject.UI_MasterCanvas); } private void SetupUI() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) freqMultDisplay.layer = 5; RectTransform obj = freqMultDisplay.AddComponent(); RectTransformExtensions.SetAnchorAndPivot(obj, (AnchorPresets)2, (PivotPresets)2, 0, 0); obj.anchoredPosition = new Vector2(-10f, -60f); obj.sizeDelta = new Vector2(100f, 50f); textDisplay = freqMultDisplay.AddComponent(); ((Graphic)textDisplay).color = new Color(0.9725f, 0.3176f, 0.8948f, 1f); ((TMP_Text)textDisplay).fontSize = 21f; ((TMP_Text)textDisplay).fontStyle = (FontStyles)0; ((TMP_Text)textDisplay).horizontalAlignment = (HorizontalAlignmentOptions)4; ((TMP_Text)textDisplay).verticalAlignment = (VerticalAlignmentOptions)512; } public static void AllowDisplay() { instance.allowDisplay = true; instance.ShowDisplay(); } public static void Destroy() { if (!((Object)(object)instance == (Object)null)) { instance.allowDisplay = false; ModConfig.Instance.DisplayAutoModeFrequencyMult.SettingChanged -= delegate { instance.DisplayLogicFromSetting(); }; JobSchedulerManager.OnNewJobFrequencyMultiplier -= instance.UpdateFreqMultiplierDisplay; Object.Destroy((Object)(object)instance.freqMultDisplay); instance = null; } } private void DisplayLogicFromSetting() { if (ModConfig.Instance.DisplayAutoModeFrequencyMult.Value) { ShowDisplay(); } else { HideDisplay(); } } private void ShowDisplay() { if (allowDisplay && ModConfig.Instance.DisplayAutoModeFrequencyMult.Value) { UpdateDisplay(forceUpdate: true); freqMultDisplay.SetActive(true); } } private void HideDisplay() { freqMultDisplay.SetActive(false); } private void UpdateFreqMultiplierDisplay(float loopMultiplierCycleEmployee, float loopMultiplierCycleCustomer) { loopMultiplierCycles = (loopMultiplierCycleEmployee, loopMultiplierCycleCustomer); UpdateDisplay(forceUpdate: false); } private void UpdateDisplay(bool forceUpdate) { if (freqMultDisplay.activeSelf || forceUpdate) { ((TMP_Text)textDisplay).text = "E: " + GetFrequencyString(loopMultiplierCycles.employee) + " | C: " + GetFrequencyString(loopMultiplierCycles.customer); } } private string GetFrequencyString(float value) { if (value > 0f) { return Math.Round(value, 2) + " x"; } return "OFF"; } } public class InputBehaviour : MonoBehaviour { public delegate void InputAction(float currentTime, Player MainPlayerControls); private static InputBehaviour instance; private Player MainPlayerControls; private static bool isActive; private static GameWorldEvent behaviourWorldEvent = GameWorldEvent.FPControllerStarted; private static Dictionary subscriptedReferences; public static void RegisterClickAction(InputAction inputAction, GameWorldEvent worldEventToStartAt) where T : class { ActivateBehaviour(); subscriptedReferences.Add(typeof(T), (worldEventToStartAt, inputAction)); } public static void UnregisterClickAction() where T : class { if (subscriptedReferences != null && subscriptedReferences.Count != 0 && subscriptedReferences.ContainsKey(typeof(T))) { subscriptedReferences.Remove(typeof(T)); if (subscriptedReferences.Count == 0) { DeactivateBehaviour(); } } } private static void ActivateBehaviour() { if (isActive) { return; } subscriptedReferences = new Dictionary(); if (!Object.op_Implicit((Object)(object)instance) || !((MonoBehaviour)instance).didAwake) { WorldState.SubscribeToWorldStateEvent(behaviourWorldEvent, AddInputBehaviourComponent); WorldState.GetSubscribersForWorldState(behaviourWorldEvent); if (WorldState.IsGameWorldAtOrAfter(behaviourWorldEvent)) { AddInputBehaviourComponent(); } } isActive = true; if (Object.op_Implicit((Object)(object)instance)) { ((Behaviour)instance).enabled = true; } } private static void AddInputBehaviourComponent() { if ((Object)(object)GameObjectManager.AddComponentTo(TargetObject.LocalGamePlayer) == (Object)null) { TimeLogger.Logger.LogError("The click behaviour component could not be added and all its related logic wont work.", (LogCategories)33554432); } } private static void DeactivateBehaviour() { if (isActive) { subscriptedReferences = null; isActive = false; if (Object.op_Implicit((Object)(object)instance)) { ((Behaviour)instance).enabled = false; } } } public void Awake() { instance = this; KeyActions.Initialize(); PlayerNetwork val = SMTInstances.LocalPlayerNetwork(); MainPlayerControls = val.MainPlayer; } public void Update() { float time = Time.time; foreach (KeyValuePair subscriptedReference in subscriptedReferences) { if (WorldState.IsGameWorldAtOrAfter(subscriptedReference.Value.Item1)) { subscriptedReference.Value.Item2(time, MainPlayerControls); } } } } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct KeyActions { [StructLayout(LayoutKind.Sequential, Size = 1)] private readonly struct ActionNames { public static readonly string MainAction = "Main Action"; public static readonly string SecondaryAction = "Secondary Action"; } public static int MainActionId { get; private set; } public static int SecondaryActionId { get; private set; } public static void Initialize() { MainActionId = ReInput.mapping.GetActionId(ActionNames.MainAction); SecondaryActionId = ReInput.mapping.GetActionId(ActionNames.SecondaryAction); if (MainActionId < 0 && SecondaryActionId < 0) { throw new InvalidOperationException("None of the supported keys could be retrieved. SuperQoLity click behaviours wont work."); } if (MainActionId < 0) { TimeLogger.Logger.LogError("An action could not be found with name \"" + ActionNames.MainAction + "\"", (LogCategories)33554432); } if (SecondaryActionId < 0) { TimeLogger.Logger.LogError("An action could not be found with name \"" + ActionNames.MainAction + "\"", (LogCategories)33554432); } } } } namespace SuperQoLity.SuperMarket.Patches { public class GameWorldEventsPatch : FullyAutoPatchedInstance { private class PauseDetection { private static readonly Stopwatch swPause = Stopwatch.StartNew(); public static bool WasGamePaused; [HarmonyPatch(typeof(GameData), "Update")] [HarmonyPostfix] private static void GameCanvasUpdatePostFix(GameData __instance) { if (swPause.ElapsedMilliseconds > 20) { DetectGamePause(); swPause.Restart(); } } private static void DetectGamePause() { if (WorldState.IsWorldLoaded) { bool flag = Time.timeScale == 0f; if (flag != WasGamePaused) { EventMethods.TryTriggerEvents(WorldState.OnGamePauseChanged, flag, AuxUtils.IsMainMenuOpen()); } WasGamePaused = flag; } } } private class DetectGameLoadFinished { private enum DetectionState { Initial, Success, Failed } private static readonly Stopwatch sw = Stopwatch.StartNew(); private static GameObject transitionBCKobj; private static DetectionState state = DetectionState.Initial; [HarmonyPatch(typeof(NetworkManager), "OnStartServer")] [HarmonyPrefix] public static void OnStartHostPrefixPatch() { SetLoadingWorld(); } [HarmonyPatch(typeof(NetworkManager), "OnStartClient")] [HarmonyPrefix] public static void OnStartClientPrefixPatch() { if (WorldState.CurrentOnlineMode != GameOnlineMode.Host) { SetLoadingWorld(); } } private static void SetLoadingWorld() { WorldState.CurrentOnlineMode = (NetworkServer.activeHost ? GameOnlineMode.Host : GameOnlineMode.Client); WorldState.SetGameWorldState(GameWorldEvent.LoadingWorld); } [HarmonyPatch(typeof(GameCanvas), "Awake")] [HarmonyPostfix] private static void GameCanvasAwake(GameCanvas __instance) { WorldState.SetGameWorldState(GameWorldEvent.CanvasAwake); } [HarmonyPatch(typeof(GameCanvas), "Update")] [HarmonyPostfix] private static void GameCanvasUpdatePostFix(GameCanvas __instance) { if (sw.ElapsedMilliseconds < 100) { return; } try { if ((Object)(object)transitionBCKobj == (Object)null) { state = DetectionState.Initial; transitionBCKobj = GameObject.Find("MasterOBJ/MasterCanvas/TransitionBCK"); } if ((Object)(object)transitionBCKobj != (Object)null && !transitionBCKobj.activeSelf && state == DetectionState.Initial) { state = DetectionState.Success; WorldState.SetGameWorldState(GameWorldEvent.WorldLoaded); } } catch (Exception ex) { state = DetectionState.Failed; TimeLogger.Logger.LogExceptionWithMessage("Error while trying to detect game finished loading.", ex, (LogCategories)8); } finally { GameWorldEventsPatch instance = Container.Instance; if (state == DetectionState.Failed) { TimeLogger.Logger.LogError(((AutoPatchedInstanceBase)instance).ErrorMessageOnAutoPatchFail, (LogCategories)8); ((AutoPatchedInstanceBase)instance).UnpatchInstance(); sw.Stop(); } else { sw.Restart(); } } } } private class FirstPersonControllerStart { [HarmonyPatch(typeof(FirstPersonController), "Start")] [HarmonyPostfix] public static void OnFirstPersonControllerStart(FirstPersonController __instance) { WorldState.SetGameWorldState(GameWorldEvent.FPControllerStarted); } } private class DetectQuitToMainMenu { [HarmonyPatch(typeof(CustomNetworkManager), "OnClientDisconnect")] [HarmonyPostfix] public static void OnClientDisconnectPatch(CustomNetworkManager __instance) { WorldState.CurrentOnlineMode = GameOnlineMode.None; WorldState.SetGameWorldState(GameWorldEvent.QuitOrMenu); } } private class BuildEvents { [CompilerGenerated] private sealed class d__4 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; private Data_Container <__instance>5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <__instance>5__2 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <__instance>5__2 = lastDataContainerActivated; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnShelfBuiltOrLoaded, ((Component)<__instance>5__2).transform, ParentContainerType.ProductDisplay); 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 d__6 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; private Data_Container <__instance>5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <__instance>5__2 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <__instance>5__2 = lastDataContainerActivated; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnShelfBuiltOrLoaded, ((Component)<__instance>5__2).transform, ParentContainerType.Storage); 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 static Data_Container lastDataContainerActivated; [HarmonyPatch(typeof(Data_Container), "ActivateShelvesFromLoad")] [HarmonyPostfix] private static void NewBuildableLoadedHost(Data_Container __instance) { DataContainerType.TypeIndex containerType = __instance.GetContainerType(); if (containerType == DataContainerType.TypeIndex.ProductShelf || containerType == DataContainerType.TypeIndex.StorageShelf) { EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnShelfBuiltOrLoaded, ((Component)__instance).transform, containerType.ToParentContainerType()); } } [HarmonyPatch(typeof(NetworkSpawner), "UserCode_CmdSpawn__Int32__Vector3__Vector3")] [HarmonyPostfix] private static void NewBuildableBuiltHost(NetworkSpawner __instance, int prefabID, Vector3 pos, Vector3 rot) { int parentIndex; DataContainerType.TypeIndex containerType = DataContainerType.GetContainerType(prefabID, out parentIndex); if (containerType == DataContainerType.TypeIndex.ProductShelf || containerType == DataContainerType.TypeIndex.StorageShelf) { Transform child = __instance.levelPropsOBJ.transform.GetChild(parentIndex); GameObject gameObject = ((Component)child.GetChild(child.childCount - 1)).gameObject; EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnShelfBuiltOrLoaded, gameObject.transform, containerType.ToParentContainerType()); } } [HarmonyPatch(typeof(Data_Container), "DelayActivationShelves")] [HarmonyPostfix] private static void ProdShelfBuiltOrLoadedClientGetInstance(Data_Container __instance) { lastDataContainerActivated = __instance; } [IteratorStateMachine(typeof(d__4))] [HarmonyPatch(typeof(Data_Container), "DelayActivationShelves")] [HarmonyPriority(100)] [HarmonyPostfix] public static IEnumerator ProdShelfBuiltOrLoadedClient(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(0) { result = result }; } [HarmonyPatch(typeof(Data_Container), "DelayActivationStorage")] [HarmonyPostfix] private static void StorageShelfBuiltOrLoadedClientGetInstance(Data_Container __instance) { lastDataContainerActivated = __instance; } [IteratorStateMachine(typeof(d__6))] [HarmonyPatch(typeof(Data_Container), "DelayActivationStorage")] [HarmonyPriority(100)] [HarmonyPostfix] public static IEnumerator StorageShelfBuiltOrLoadedClient(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(0) { result = result }; } } private class ContainerEvents { private static Transform droppedInstantiatedObject; [HarmonyPatch(typeof(Data_Container), "BoxSpawner")] [HarmonyPostfix] private static void BoxSpawnerPatch(Data_Container __instance) { EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnStorageLoadedBuiltOrUpdated, __instance); } [HarmonyPatch(typeof(Data_Container), "ItemSpawner")] [HarmonyPostfix] private static void ItemSpawnerPatch(Data_Container __instance) { EventMethods.TryTriggerEvents(WorldState.BuildingEvents.OnProductShelfLoadedBuiltOrUpdated, __instance); } [HarmonyPatch(typeof(ManagerBlackboard), "UserCode_RpcParentBoxOnClient__GameObject")] [HarmonyPostfix] private static void BoxSpawned(ManagerBlackboard __instance, GameObject boxOBJ) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxSpawned, boxOBJ.transform); } [HarmonyPatch(typeof(PlayerNetwork), "UpdateBoxContents")] [HarmonyPostfix] private static void BoxPickUpOrUpdatedLocalPlayerPatch(PlayerNetwork __instance, int productIndex) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxEquippedOrUpdatedLocalPlayer, __instance.instantiatedOBJ.transform, productIndex); } [HarmonyPatch(typeof(PlayerNetwork), "OnChangeEquipment")] [HarmonyPrefix] private static void OnChangeEquipmentPrefix(PlayerNetwork __instance) { GameObject obj = UnityObjectExtensions.NullableObject(__instance.instantiatedOBJ); droppedInstantiatedObject = ((obj != null) ? obj.transform : null); } [HarmonyPatch(typeof(PlayerNetwork), "OnChangeEquipment")] [HarmonyPostfix] private static void OnChangeEquipmentPostfix(PlayerNetwork __instance, int oldEquippedItem, int newEquippedItem) { if (oldEquippedItem == 1) { CharacterSourceType characterSourceType = ToCharacterSource(((NetworkBehaviour)__instance).isLocalPlayer); EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxDroppedByPlayer, droppedInstantiatedObject, characterSourceType); } else if (newEquippedItem == 1 && !((NetworkBehaviour)__instance).isLocalPlayer && WorldState.CurrentOnlineMode == GameOnlineMode.Client) { int syncedProductID = ((Component)__instance).GetComponent().syncedProductID; EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxEquippedRemotePlayerOrEmployee, ((Component)__instance).transform, __instance.instantiatedOBJ.transform, syncedProductID, CharacterSourceType.RemotePlayer); } Action onChangeEquipment = WorldState.PlayerEvents.OnChangeEquipment; Transform obj = droppedInstantiatedObject; GameObject obj2 = UnityObjectExtensions.NullableObject(__instance.instantiatedOBJ); EventMethods.TryTriggerEvents(onChangeEquipment, __instance, obj, (obj2 != null) ? obj2.transform : null, oldEquippedItem, newEquippedItem, ((NetworkBehaviour)__instance).isLocalPlayer); } [HarmonyPatch(typeof(PlayerSyncCharacter), "DeserializeSyncVars")] [HarmonyTranspiler] public static IEnumerable CallOnChangeSyncedProductIDTranspiler(IEnumerable instructions, ILGenerator generator) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); FieldInfo fInfo = AccessTools.Field(typeof(PlayerSyncCharacter), "syncedProductID"); if (fInfo == null) { TimeLogger.Logger.LogError("The field PlayerSyncCharacter.syncedProductID could not be found. Highlighting of remote player held boxes wont work.", (LogCategories)67108864); return val.InstructionEnumeration(); } val.End(); val.MatchEndBackwards((CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((Func)((CodeInstruction c) => CodeInstructionExtensions.LoadsField(c, fInfo, true)), (string)null), new CodeMatch((Func)((CodeInstruction c) => c.opcode == OpCodes.Ldnull), (string)null) }); if (val.IsInvalid) { TimeLogger.Logger.LogError("The IL line loading the field PlayerSyncCharacter.syncedProductID could not be found. Highlighting of remote player held boxes wont work.", (LogCategories)67108864); return val.InstructionEnumeration(); } MethodInfo methodInfo = AccessTools.Method(typeof(ContainerEvents), "OnChangeSyncedProductID", (Type[])null, (Type[])null); ConstructorInfo constructorInfo = AccessTools.Constructor(typeof(Action), new Type[2] { typeof(object), typeof(IntPtr) }, false); val.RemoveInstruction().Insert((CodeInstruction[])(object)new CodeInstruction[3] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldftn, (object)methodInfo), new CodeInstruction(OpCodes.Newobj, (object)constructorInfo) }); return val.InstructionEnumeration(); } private static void OnChangeSyncedProductID(PlayerSyncCharacter playerSync) { if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { PlayerNetwork component = ((Component)playerSync).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.equippedItem == 1) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxEquippedRemotePlayerOrEmployee, ((Component)playerSync).transform, component.instantiatedOBJ.transform, playerSync.syncedProductID, CharacterSourceType.RemotePlayer); } } } [HarmonyPatch(typeof(NPC_Info), "UserCode_RpcEquipNPCItem__Int32__Int32")] [HarmonyPostfix] private static void UserCode_RpcEquipNPCItem__Int32__Int32(NPC_Info __instance, int equippedIndex, int productID) { if (equippedIndex == 1) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxEquippedRemotePlayerOrEmployee, ((Component)__instance).transform, __instance.instantiatedOBJ.transform, productID, CharacterSourceType.Employee); } } [HarmonyPatch(typeof(Data_Container), "UserCode_RpcUpdateArrayValuesStorage__Int32__Int32__Int32")] [HarmonyPostfix] private static void UserCode_RpcUpdateArrayValuesStorage__Int32__Int32__Int32(Data_Container __instance, int index, int PID, int PNUMBER) { if (PNUMBER >= 0) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnBoxIntoStorage, __instance); } } [HarmonyPatch(typeof(Data_Container), "UserCode_RpcUpdateObjectOnClients__Int32__Int32__Int32__Int32")] [HarmonyPostfix] private static void UserCode_RpcUpdateObjectOnClients__Int32__Int32__Int32__Int32(Data_Container __instance, int index, int PID, int PNUMBER, int oldPID) { if (oldPID < 0 && PID >= 0) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnProdShelfAssigned, __instance); } else if (oldPID >= 0 && PID < 0) { EventMethods.TryTriggerEvents(WorldState.ContainerEvents.OnProdShelfUnassigned, __instance); } } } public class NPC_Events { [HarmonyPatch(typeof(NPC_Manager), "SpawnEmployeeByIndex")] [HarmonyPriority(100)] [HarmonyPostfix] private static void SpawnEmployeeByIndexPostfix(NPC_Manager __instance, int index) { NPC_Info component = __instance.employeesArray[index].GetComponent(); EventMethods.TryTriggerEvents(WorldState.NPC_Events.OnEmployeeSpawned, component, index); } } public override bool IsAutoPatchEnabled => true; public override bool IsRollbackOnAutoPatchFail => false; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Detection of world events patch failed. Disabled"; public override void OnPatchFinishedVirtual(bool IsActive) { if (IsActive) { WorldState.OnWorldLoaded += delegate { PauseDetection.WasGamePaused = false; }; } } public static CharacterSourceType ToCharacterSource(bool isLocalPlayer) { if (!isLocalPlayer) { return CharacterSourceType.RemotePlayer; } return CharacterSourceType.LocalPlayer; } } public class ShelfItemCulling { public static void Initialize() { } public static void ShelfBuilt(NetworkSpawner instance, int prefabID) { instance.buildables[prefabID].GetComponent(); } public static void CreateProductShelfBounds(Data_Container instance) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in ((Component)instance).transform.Find("ProductContainer")) { _ = item; } } } public class StoreOpenStatusPatch : FullyAutoPatchedInstance { private static CancellableSingleTask storeClosedTask = new CancellableSingleTask(true); private static SemaphoreSlim semaphoreLock = new SemaphoreSlim(1, 1); public override bool IsAutoPatchEnabled { get { if (!ModConfig.Instance.EnableEmployeeChanges.Value) { return ModConfig.Instance.EnableTransferProducts.Value; } return true; } } public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Store opening state detection patch failed. Disabled"; public static event Action OnSupermarketOpenStateChanged; public override void OnPatchFinishedVirtual(bool IsActive) { if (IsActive) { NetworkSpawnManager.RegisterNetwork(StoreStatusNetwork.NetworkAssetId, true); WorldState.OnQuitOrMainMenu += async delegate { await storeClosedTask.StopTaskAndWaitAsync(500); }; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPriority(600)] [HarmonyPrefix] private static bool NetworkisSupermarketOpenPrefixPatch(ref bool __state) { __state = GameData.Instance.isSupermarketOpen; return true; } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static async void NetworkisSupermarketOpenPostfixPatch(bool __state) { if (GameData.Instance.isSupermarketOpen == __state) { return; } await storeClosedTask.StopTaskAndWaitAsync(); await semaphoreLock.WaitAsync(); try { bool value = true; if (!GameData.Instance.isSupermarketOpen) { await storeClosedTask.StartAwaitableTaskAsync((Func)CheckCustomersPendingActions, "Wait for end of customers actions", true); if (storeClosedTask.IsCancellationRequested) { TimeLogger.Logger.LogDebugFunc((Func)(() => "Skipped to next day or quitting to main menu before customers left the store."), (LogCategories)16); } else { TimeLogger.Logger.LogDebugFunc((Func)(() => "All customers are leaving or already left the supermarket."), (LogCategories)16); } value = false; } StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync.Value = value; EventMethods.TryTriggerEvents(StoreOpenStatusPatch.OnSupermarketOpenStateChanged, SyncVar.op_Implicit(StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync)); } finally { semaphoreLock.Release(); } } private static async Task CheckCustomersPendingActions() { UnityTimeStopwatch safetyTimeout = UnityTimeStopwatch.StartNew(); try { while (HasCustomersWithPendingActions(storeClosedTask.CancellationToken) && safetyTimeout.ElapsedSeconds < 180) { await UniTask.Delay(500, false, (PlayerLoopTiming)8, storeClosedTask.CancellationToken, false); } } catch (OperationCanceledException) { } } private static bool HasCustomersWithPendingActions(CancellationToken cancelToken = default(CancellationToken)) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (cancelToken.IsCancellationRequested) { return false; } foreach (Transform item in NPC_Manager.Instance.customersnpcParentOBJ.transform) { if (((Component)item).gameObject.GetComponent().state < 99) { return true; } } return false; } } } namespace SuperQoLity.SuperMarket.Patches.TransferItemsModule { public enum EnumItemTransferMode { [Description("Disabled")] Disabled, [Description("Only while store is closed")] OnlyWhileStoreClosed, [Description("Always on")] AlwaysOn } [HarmonyPatch(typeof(Data_Container))] public class IncreasedItemTransferPatch : FullyAutoPatchedInstance { private enum RowActionType { Add, Remove } public enum CharacterType { Player, Employee } public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableTransferProducts.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Transfer patch failed. Item Transfer Module inactive"; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (IsPatchActive) { NetworkSpawnManager.RegisterNetwork(ItemTransferNetwork.NetworkAssetId, true); } } public static int GetNumTransferItems(int giverItemCount, int receiverItemCount, int receiverMaxCapacity, CharacterType charType) { return GetNumTransferItems(giverItemCount, receiverItemCount, receiverMaxCapacity, charType, 1); } public static int GetNumTransferItems(int giverItemCount, int receiverItemCount, int receiverMaxCapacity, CharacterType charType, int numMovedProducts) { if (IsItemTransferEnabledFor(charType, numMovedProducts)) { int val = receiverMaxCapacity - receiverItemCount; numMovedProducts = Math.Min(Math.Min((charType == CharacterType.Player) ? ((SyncVar)(object)ItemTransferNetwork.ItemTransferQuantitySync).Value : int.MaxValue, giverItemCount), val); } return numMovedProducts; } public static bool IsItemTransferEnabledFor(CharacterType charType, int numMovedProducts) { if ((charType == CharacterType.Player && ((SyncVar)(object)ItemTransferNetwork.ItemTransferModeSync).Value == EnumItemTransferMode.Disabled) || (charType == CharacterType.Employee && !ModConfig.Instance.ClosedStoreEmployeeItemTransferMaxed.Value)) { return false; } if (!SyncVar.op_Implicit(StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync)) { return true; } switch (charType) { case CharacterType.Player: if (ModConfig.Instance.EnableTransferProducts.Value && ((SyncVar)(object)ItemTransferNetwork.ItemTransferQuantitySync).Value != numMovedProducts) { return ((SyncVar)(object)ItemTransferNetwork.ItemTransferModeSync).Value != EnumItemTransferMode.OnlyWhileStoreClosed; } return false; case CharacterType.Employee: return false; default: throw new InvalidOperationException($"{charType} is not a supported value in this method."); } } [HarmonyPatch("AddItemToRow")] [HarmonyTranspiler] private static IEnumerable AddItemToRowTranspiler(IEnumerable instructions, ILGenerator generator) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); FieldInfo fieldInfo = AccessTools.Field(typeof(PlayerNetwork), "extraParameter2"); Label? exitBranchLabel = null; int indexStart = val.End().MatchEndBackwards((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo, (string)null) }).MatchEndBackwards((CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction c) => CodeInstructionExtensions.Branches(c, ref exitBranchLabel)), (string)null) }) .Pos + 1; if (!exitBranchLabel.HasValue) { throw new TranspilerDefaultMsgException("Couldnt find the exit branch label for the AddItemToRow method."); } int pos = val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => inst.labels.Contains(exitBranchLabel.Value)), (string)null) }).Pos; return ReplaceConstantsWithCallResult(val.InstructionEnumeration().ToList(), generator, indexStart, pos, RowActionType.Add); } [HarmonyPatch("RemoveItemFromRow")] [HarmonyTranspiler] private static IEnumerable RemoveItemFromRowTranspiler(IEnumerable instructions, ILGenerator generator) { return TranspilerChangeProductTransferCount(instructions, generator, RowActionType.Remove); } private static IEnumerable TranspilerChangeProductTransferCount(IEnumerable instructions, ILGenerator generator, RowActionType rowActionType) { //IL_0049: 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_00f1: Unknown result type (might be due to invalid IL or missing references) List list = instructions.ToList(); int num = -1; int num2 = -1; FieldInfo extraParameter2 = AccessTools.Field(typeof(PlayerNetwork), "extraParameter2"); int num3 = list.FindLastIndex((CodeInstruction instruction) => CodeInstructionExtensions.LoadsField(instruction, extraParameter2, false)); if (num3 < 0) { throw new TranspilerDefaultMsgException("Couldnt find the instruction loading the value of the field extraParameter2"); } int num4 = list.FindLastIndex(num3, num3, (CodeInstruction instruction) => instruction.opcode == OpCodes.Br || instruction.opcode == OpCodes.Br_S); if (num4 < 0) { throw new TranspilerDefaultMsgException($"Couldnt find the Br/Br_S instruction when looking up to IL line {num3}"); } Label endElseLabel = (Label)list[num4].operand; int num5 = list.Count - 1; int num6 = list.FindLastIndex(num5, num5 - num3, (CodeInstruction instruction) => instruction.labels.FirstOrDefault() == endElseLabel); if (num6 < 0) { throw new TranspilerDefaultMsgException($"Couldnt find IL Label {endElseLabel} when searching from IL line {num3}"); } num = num4 + 1; num2 = num6 - 1; return ReplaceConstantsWithCallResult(list, generator, num, num2, rowActionType); } private static IEnumerable ReplaceConstantsWithCallResult(List instrList, ILGenerator generator, int indexStart, int indexEnd, RowActionType rowActionType) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) List list = CreateILCall_GetNumTransferItems(instrList, indexStart, indexEnd, rowActionType); LocalBuilder localBuilder = generator.DeclareLocal(typeof(int)); CodeInstruction val = CodeInstructionNew.LoadLocal(localBuilder.LocalIndex, false); CodeInstructionExtensions.MoveLabelsTo(instrList[indexStart], list[0]); if (rowActionType == RowActionType.Add) { if (instrList[indexStart + 3].operand == null || !instrList[indexStart + 3].operand.ToString().Contains("AchievementPoint")) { throw new TranspilerDefaultMsgException($"The call to a method containing the text \"AchievementPoint\" wasnt found at the expected line {indexStart + 3}"); } if (instrList[indexStart + 2].opcode != OpCodes.Ldc_I4_1) { throw new TranspilerDefaultMsgException($"The opcode Ldc_I4_1 for achievements wasnt found at the expected line {indexStart + 2}."); } instrList[indexStart + 2] = val; int num = 4; instrList.InsertRange(indexEnd, instrList.GetRange(indexStart, num)); instrList.RemoveRange(indexStart, num); indexEnd -= num; } instrList.InsertRange(indexStart, list); instrList.Insert(indexStart + list.Count, CodeInstructionNew.StoreLocal(localBuilder.LocalIndex)); indexEnd += list.Count + 1; CodeMatcher val2 = new CodeMatcher((IEnumerable)instrList, (ILGenerator)null); int num2 = 0; val2.Advance(indexStart); while (val2.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst, 1L)), (string)null) }).IsValid && val2.Pos <= indexEnd) { val2.SetInstructionAndAdvance(val); num2++; } if (num2 < 2) { throw new TranspilerDefaultMsgException($"Only {num2} matches where found of the expected " + "2."); } return val2.InstructionEnumeration(); } private static List CreateILCall_GetNumTransferItems(List instrList, int indexStart, int indexEnd, RowActionType rowActionType) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown List list = new List(); CodeInstruction boxCountILInstruction = GetBoxCountILInstruction(); switch (rowActionType) { case RowActionType.Add: list.AddRange(GetILParametersAddingItems(instrList, boxCountILInstruction)); break; case RowActionType.Remove: list.AddRange(GetILParametersRemovingItems(instrList, boxCountILInstruction)); break; default: throw new TranspilerDefaultMsgException($"Initial RowActionType: {rowActionType}"); } list.Add(new CodeInstruction(OpCodes.Ldc_I4_S, (object)0)); list.Add(Transpilers.EmitDelegate>((Func)GetNumTransferItems)); return list; } private static List GetILParametersAddingItems(List instrList, CodeInstruction getBoxCountILInstr) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = instrList.FindIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldstr && instruction.operand.ToString() == "message1"); if (num == -1) { throw new TranspilerDefaultMsgException("Couldnt find the line loading the string \"message1\"."); } int num2 = instrList.FindLastIndex(num, (CodeInstruction instruction) => CodeInstructionExtensions.IsLdloc(instruction, (LocalBuilder)null)); if (num2 == -1) { throw new TranspilerDefaultMsgException("Couldnt find the line loading the local var \"num3\"."); } int index = num2 - 1; int num3 = ILExtensionMethods.LocalIndex(instrList[num2]); int num4 = ILExtensionMethods.LocalIndex(instrList[index]); list.Add(getBoxCountILInstr); list.Add(CodeInstructionNew.LoadLocal(num4, false)); list.Add(CodeInstructionNew.LoadLocal(num3, false)); return list; } private static List GetILParametersRemovingItems(List instrList, CodeInstruction getBoxCountILInstr) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) List list = new List(); int num = -1; int num2 = 0; int num3 = int.MinValue; FieldInfo fieldInfo = AccessTools.Field(typeof(Data_Container), "productInfoArray"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(ProductData), "maxItemsPerBox"); if (fieldInfo == null) { throw new TranspilerDefaultMsgException("The field Data_Container.productInfoArray could not be found."); } if (fieldInfo2 == null) { throw new TranspilerDefaultMsgException("The field Data_Product.maxItemsPerBox could not be found."); } int num4 = -1; int num5 = -1; for (int i = 0; i < instrList.Count; i++) { CodeInstruction val = instrList[i]; if (num2 < 2 && CodeInstructionExtensions.LoadsField(val, fieldInfo, false)) { num2++; if (num2 == 2) { num3 = i + 1; } } else if (num5 == -1 && i >= num3 && i < num3 + 10 && CodeInstructionExtensions.IsStloc(val, (LocalBuilder)null)) { num5 = ILExtensionMethods.LocalIndex(val); } else if (num < 0 && CodeInstructionExtensions.LoadsField(val, fieldInfo2, false)) { num = i + 1; } else if (i == num && CodeInstructionExtensions.IsStloc(val, (LocalBuilder)null)) { num4 = ILExtensionMethods.LocalIndex(val); } } if (num2 < 2) { throw new TranspilerDefaultMsgException($"Couldnt reach the appropiate amount of productInfoArray usages (productInfoArrayInstance = {num2})"); } if (num5 == -1) { throw new TranspilerDefaultMsgException($"Couldnt find the num3 local var reference (num3IndexBeginSearch = {num3})"); } if (num4 == -1) { throw new TranspilerDefaultMsgException($"Couldnt find the maxItemsPerBox local var reference (maxItemsPerBoxLocalVarIndex = {num})"); } list.Add(CodeInstructionNew.LoadLocal(num5, false)); list.Add(getBoxCountILInstr); list.Add(CodeInstructionNew.LoadLocal(num4, false)); return list; } private static CodeInstruction GetBoxCountILInstruction() { return Transpilers.EmitDelegate>((Func)(() => ((Component)FirstPersonController.Instance).GetComponent().extraParameter2)); } } } namespace SuperQoLity.SuperMarket.Patches.NPC { public class NpcJobSchedulerPatch : FullyAutoPatchedInstance { private static bool canEmployeesDoSomething; private static bool canCustomersDoSomething; public override bool IsAutoPatchEnabled { get { if (!ModConfig.Instance.EnableCustomerChanges.Value) { return ModConfig.Instance.EnableEmployeeChanges.Value; } return true; } } public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Npc slowdown fix multiplier failed. Disabled"; public override void OnPatchFinishedVirtual(bool IsActive) { if (!IsActive) { return; } try { SetCustomPerfModeVisibility(); ModConfig.Instance.NpcJobFrequencyMode.SettingChanged += delegate { SetCustomPerfModeVisibility(); ConfigManagerController.RefreshGUI(); }; JobSchedulerManager.InitializeJobSchedulerEvents(); if (ModConfig.Instance.EnableEmployeeChanges.Value) { RestockMatcher.Enable(); } } catch { JobSchedulerManager.DisableJobScheduler(); RestockMatcher.Disable(); ((AutoPatchedInstanceBase)Container.Instance).UnpatchInstance(); throw; } } [HarmonyPatch(typeof(NPC_Manager), "FixedUpdate")] [HarmonyPrefix] public static void FixedUpdateResetFlags(NPC_Manager __instance) { canEmployeesDoSomething = false; canCustomersDoSomething = false; } [HarmonyAfterInstance(new Type[] { typeof(EmployeeJobAIPatch) })] [HarmonyPatch(typeof(NPC_Manager), "FixedUpdate")] [HarmonyPostfix] public static void FixedUpdateProcessNPCs(NPC_Manager __instance) { if (canEmployeesDoSomething && !__instance.mainManufacturingShelfUpdateIsRunning && ((Component)GameData.Instance).GetComponent().addonsBought[1]) { ((MonoBehaviour)__instance).StartCoroutine(__instance.MainManufacturingRestockUpdate()); } if (canEmployeesDoSomething || canCustomersDoSomething) { JobSchedulerManager.ProcessNPCJobs(__instance, canEmployeesDoSomething, canCustomersDoSomething); } } [HarmonyPatch(typeof(NPC_Manager), "FixedUpdate")] [HarmonyTranspiler] public static IEnumerable FixedUpdateNpcTranspiler(IEnumerable instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, generator); if (ModConfig.Instance.EnableEmployeeChanges.Value) { val = TranspileEmployeeCall(val); } if (ModConfig.Instance.EnableCustomerChanges.Value) { val = TranspileCustomerCall(val); } return val.InstructionEnumeration(); } public static CodeMatcher TranspileEmployeeCall(CodeMatcher codeMatcher) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0099: Unknown result type (might be due to invalid IL or missing references) codeMatcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null) && inst.labels.Count > 0), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => inst.operand is Label), (string)null) }); if (codeMatcher.IsInvalid) { throw new TranspilerDefaultMsgException("IL line \"if (childCount > 0)\" could not be found."); } int num = codeMatcher.Pos + 1; Label endLabel = (Label)codeMatcher.Operand; codeMatcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => inst.labels.Contains(endLabel)), (string)null) }); codeMatcher.RemoveInstructionsInRange(num, codeMatcher.Pos - 1); codeMatcher.Start().Advance(num).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldc_I4_1, (object)null) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.StoreField(typeof(NpcJobSchedulerPatch), "canEmployeesDoSomething") }); return codeMatcher; } private static CodeMatcher TranspileCustomerCall(CodeMatcher codeMatcher) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown codeMatcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => inst.opcode == OpCodes.Brtrue_S || inst.opcode == OpCodes.Brtrue), (string)null) }); if (codeMatcher.IsInvalid) { throw new TranspilerDefaultMsgException("IL line \"if (childCount2 != 0)\" could not be found."); } int pos = codeMatcher.Pos; Label startCondLabel = (Label)codeMatcher.Operand; codeMatcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => inst.labels.Contains(startCondLabel)), (string)null) }); int pos2 = codeMatcher.Pos; codeMatcher.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => inst.opcode == OpCodes.Ret), (string)null) }); codeMatcher.RemoveInstructionsInRange(pos2 - 1, codeMatcher.Pos - 1); Label label = default(Label); codeMatcher.Start().Advance(pos + 1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldc_I4_1, (object)null) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.StoreField(typeof(NpcJobSchedulerPatch), "canCustomersDoSomething") }) .CreateLabel(ref label) .Start() .Advance(pos) .Set(OpCodes.Brfalse, (object)label); return codeMatcher; } private void SetCustomPerfModeVisibility() { bool flag = ModConfig.Instance.NpcJobFrequencyMode.Value == EnumJobFrequencyMultMode.Auto_Custom; ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomEmployeeWaitTarget, (ConfigAttributes)3, flag); ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomCustomerWaitTarget, (ConfigAttributes)3, flag); ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomMinimumFrequencyMult, (ConfigAttributes)3, flag); ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomMaximumFrequencyMult, (ConfigAttributes)3, flag); ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomMaximumFrequencyReduction, (ConfigAttributes)3, flag); ConfigManagerExtension.SetConfigAttribute(ModConfig.Instance.CustomMaximumFrequencyIncrease, (ConfigAttributes)3, flag); } } } namespace SuperQoLity.SuperMarket.Patches.NPC.EmployeeModule { public enum EmployeeJob { Unassigned = 0, Cashier = 1, Restocker = 2, Storage = 3, Security = 4, Technician = 5, OnlineOrder = 6, Manufacturer = 7, Any = 99 } public enum EnumSecurityPickUp { [Description("Disabled")] Disabled, [Description("Reduced")] Reduced, [Description("Normal")] Normal, [Description("Always Maxed")] AlwaysMaxed } public enum EnumSecurityEmployeeThiefChase { [Description("Disabled")] Disabled, [Description("All chase but last one")] AllChaseButLastOne, [Description("Only one per Thief")] OnlyOnePerThief } public class EmployeeJobAIPatch : FullyAutoPatchedInstance { [CompilerGenerated] private sealed class d__32 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__32(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (WorldState.CurrentGameWorldState == GameWorldEvent.QuitOrMenu) { stolenProdPickups.Clear(); return false; } } else { <>1__state = -1; } if (stolenProdPickups.Count > 0) { StolenProductSpawn val = default(StolenProductSpawn); for (float num2 = Math.Min(5f, stolenProdPickups.Count); num2 >= 1f; num2 -= 1f) { if (Extensions.TryDequeue(stolenProdPickups, ref val)) { NetworkServer.UnSpawn(((Component)val).gameObject); } } } <>2__current = null; <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const bool LogEmployeeActions = false; private static bool newProdPickUpWorking; private static Queue stolenProdPickups; private static List taskPriorities; private static int currentTaskIndex; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableEmployeeChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Employee patch failed. Employee Module inactive"; public static int NumTransferItemsBase { get; } = 1; public static int MaxSecurityPickUpLevel { get; } = 200; public static float SecurityPickUpRangeLevelMult { get; } = 1.25f; public static int SecurityPickUpLayer { get; } = 25; public static float LevelsForExtraPickUp { get; } = 10f; public override void OnPatchFinishedVirtual(bool isActive) { if (isActive) { WorldState.NPC_Events.OnEmployeeSpawned = (Action)Delegate.Combine(WorldState.NPC_Events.OnEmployeeSpawned, new Action(EmployeeSpawned)); } } [HarmonyPatch(typeof(NPC_Manager), "Awake")] [HarmonyPostfix] public static void AwakePatch(NPC_Manager __instance) { newProdPickUpWorking = false; stolenProdPickups = new Queue(); GameObject npcAgentPrefab = __instance.npcAgentPrefab; GameObject val = ((npcAgentPrefab == null) ? null : npcAgentPrefab.GetComponent()?.stolenProductPrefab); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogFatal("An object in the chain \"NPC_Manager.npcAgentPrefab.NPC_Info.stolenProductPrefab\" is null. It was probably renamed of changed places. The employee patches cant be used and will be disabled.", (LogCategories)134217728); ((AutoPatchedInstanceBase)Container.Instance).UnpatchInstance(); TimeLogger.Logger.SendMessageNotificationError("Something changed due to a game update and the employee module can no longer work. It was disabled so the rest of the mod can still work", false); } else { val.layer = SecurityPickUpLayer; ((MonoBehaviour)__instance).StartCoroutine(Container.Instance.PickupMarkedStolenProductsLoop()); newProdPickUpWorking = true; } } private static void EmployeeSpawned(NPC_Info npcInfo, int index) { GenericNPC.AddSuperQolNpcObjects(((Component)npcInfo).gameObject, NPCType.Employee); } public static bool EmployeeNPCControl(NPC_Manager __instance, GameObject employeeObj, NPC_Info employee) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_3fed: Unknown result type (might be due to invalid IL or missing references) //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_0689: Unknown result type (might be due to invalid IL or missing references) //IL_0e3d: Unknown result type (might be due to invalid IL or missing references) //IL_0e65: Unknown result type (might be due to invalid IL or missing references) //IL_0e6a: Unknown result type (might be due to invalid IL or missing references) //IL_0e6f: Unknown result type (might be due to invalid IL or missing references) //IL_0e7b: Unknown result type (might be due to invalid IL or missing references) //IL_12bc: Unknown result type (might be due to invalid IL or missing references) //IL_12c1: Unknown result type (might be due to invalid IL or missing references) //IL_1508: Unknown result type (might be due to invalid IL or missing references) //IL_1530: Unknown result type (might be due to invalid IL or missing references) //IL_1535: Unknown result type (might be due to invalid IL or missing references) //IL_153a: Unknown result type (might be due to invalid IL or missing references) //IL_1546: Unknown result type (might be due to invalid IL or missing references) //IL_1611: Unknown result type (might be due to invalid IL or missing references) //IL_1621: Unknown result type (might be due to invalid IL or missing references) //IL_2538: Unknown result type (might be due to invalid IL or missing references) //IL_2543: Unknown result type (might be due to invalid IL or missing references) //IL_1f53: Unknown result type (might be due to invalid IL or missing references) //IL_1f63: Unknown result type (might be due to invalid IL or missing references) //IL_2b10: Unknown result type (might be due to invalid IL or missing references) //IL_2b20: Unknown result type (might be due to invalid IL or missing references) //IL_3497: Unknown result type (might be due to invalid IL or missing references) //IL_34bf: Unknown result type (might be due to invalid IL or missing references) //IL_34c4: Unknown result type (might be due to invalid IL or missing references) //IL_34c9: Unknown result type (might be due to invalid IL or missing references) //IL_34d5: Unknown result type (might be due to invalid IL or missing references) //IL_3df5: Unknown result type (might be due to invalid IL or missing references) //IL_3e1d: Unknown result type (might be due to invalid IL or missing references) //IL_3e22: Unknown result type (might be due to invalid IL or missing references) //IL_3e27: Unknown result type (might be due to invalid IL or missing references) //IL_3e33: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_1165: Unknown result type (might be due to invalid IL or missing references) //IL_1184: Unknown result type (might be due to invalid IL or missing references) //IL_118e: Unknown result type (might be due to invalid IL or missing references) //IL_11a0: Unknown result type (might be due to invalid IL or missing references) //IL_11ba: Unknown result type (might be due to invalid IL or missing references) //IL_11c9: Unknown result type (might be due to invalid IL or missing references) //IL_24da: Unknown result type (might be due to invalid IL or missing references) //IL_2b3c: Unknown result type (might be due to invalid IL or missing references) //IL_2b64: Unknown result type (might be due to invalid IL or missing references) //IL_2b69: Unknown result type (might be due to invalid IL or missing references) //IL_2b6e: Unknown result type (might be due to invalid IL or missing references) //IL_2b70: Unknown result type (might be due to invalid IL or missing references) //IL_3168: Unknown result type (might be due to invalid IL or missing references) //IL_3187: Unknown result type (might be due to invalid IL or missing references) //IL_3191: Unknown result type (might be due to invalid IL or missing references) //IL_31a1: Unknown result type (might be due to invalid IL or missing references) //IL_31bb: Unknown result type (might be due to invalid IL or missing references) //IL_31c5: Unknown result type (might be due to invalid IL or missing references) //IL_333a: Unknown result type (might be due to invalid IL or missing references) //IL_333f: Unknown result type (might be due to invalid IL or missing references) //IL_3342: Unknown result type (might be due to invalid IL or missing references) //IL_3310: Unknown result type (might be due to invalid IL or missing references) //IL_3315: Unknown result type (might be due to invalid IL or missing references) //IL_3318: Unknown result type (might be due to invalid IL or missing references) //IL_3cdc: Unknown result type (might be due to invalid IL or missing references) //IL_3ce1: Unknown result type (might be due to invalid IL or missing references) //IL_3ce4: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_081b: Unknown result type (might be due to invalid IL or missing references) //IL_082b: Unknown result type (might be due to invalid IL or missing references) //IL_07df: Unknown result type (might be due to invalid IL or missing references) //IL_07e4: Unknown result type (might be due to invalid IL or missing references) //IL_07e7: Unknown result type (might be due to invalid IL or missing references) //IL_109c: Unknown result type (might be due to invalid IL or missing references) //IL_10b7: Unknown result type (might be due to invalid IL or missing references) //IL_10c1: Unknown result type (might be due to invalid IL or missing references) //IL_1889: Unknown result type (might be due to invalid IL or missing references) //IL_1890: Unknown result type (might be due to invalid IL or missing references) //IL_1b00: Unknown result type (might be due to invalid IL or missing references) //IL_1b44: Unknown result type (might be due to invalid IL or missing references) //IL_1b54: Unknown result type (might be due to invalid IL or missing references) //IL_2b99: Unknown result type (might be due to invalid IL or missing references) //IL_2ed0: Unknown result type (might be due to invalid IL or missing references) //IL_2ed5: Unknown result type (might be due to invalid IL or missing references) //IL_2ed8: Unknown result type (might be due to invalid IL or missing references) //IL_362f: Unknown result type (might be due to invalid IL or missing references) //IL_3634: Unknown result type (might be due to invalid IL or missing references) //IL_3637: Unknown result type (might be due to invalid IL or missing references) //IL_3bc8: Unknown result type (might be due to invalid IL or missing references) //IL_3bcd: Unknown result type (might be due to invalid IL or missing references) //IL_3bd0: 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_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0bf0: Unknown result type (might be due to invalid IL or missing references) //IL_0cd9: Unknown result type (might be due to invalid IL or missing references) //IL_0cde: Unknown result type (might be due to invalid IL or missing references) //IL_0ce1: Unknown result type (might be due to invalid IL or missing references) //IL_10fc: Unknown result type (might be due to invalid IL or missing references) //IL_13b7: Unknown result type (might be due to invalid IL or missing references) //IL_13bc: Unknown result type (might be due to invalid IL or missing references) //IL_13bf: Unknown result type (might be due to invalid IL or missing references) //IL_18a4: Unknown result type (might be due to invalid IL or missing references) //IL_1d15: Unknown result type (might be due to invalid IL or missing references) //IL_1d34: Unknown result type (might be due to invalid IL or missing references) //IL_1d3e: Unknown result type (might be due to invalid IL or missing references) //IL_1d50: Unknown result type (might be due to invalid IL or missing references) //IL_1d6a: Unknown result type (might be due to invalid IL or missing references) //IL_1d79: Unknown result type (might be due to invalid IL or missing references) //IL_2b91: Unknown result type (might be due to invalid IL or missing references) //IL_2b96: Unknown result type (might be due to invalid IL or missing references) //IL_3b20: Unknown result type (might be due to invalid IL or missing references) //IL_3b25: Unknown result type (might be due to invalid IL or missing references) //IL_3b28: Unknown result type (might be due to invalid IL or missing references) //IL_3c5a: Unknown result type (might be due to invalid IL or missing references) //IL_3c5f: Unknown result type (might be due to invalid IL or missing references) //IL_3c62: Unknown result type (might be due to invalid IL or missing references) //IL_3c30: Unknown result type (might be due to invalid IL or missing references) //IL_3c35: Unknown result type (might be due to invalid IL or missing references) //IL_3c38: Unknown result type (might be due to invalid IL or missing references) //IL_09aa: Unknown result type (might be due to invalid IL or missing references) //IL_222e: Unknown result type (might be due to invalid IL or missing references) //IL_2233: Unknown result type (might be due to invalid IL or missing references) //IL_2236: Unknown result type (might be due to invalid IL or missing references) //IL_2e41: Unknown result type (might be due to invalid IL or missing references) //IL_2e46: Unknown result type (might be due to invalid IL or missing references) //IL_2e49: Unknown result type (might be due to invalid IL or missing references) //IL_1f1b: Unknown result type (might be due to invalid IL or missing references) //IL_38d4: Unknown result type (might be due to invalid IL or missing references) //IL_38d9: Unknown result type (might be due to invalid IL or missing references) //IL_38dc: Unknown result type (might be due to invalid IL or missing references) //IL_23fa: Unknown result type (might be due to invalid IL or missing references) //IL_3014: Unknown result type (might be due to invalid IL or missing references) //IL_2957: Unknown result type (might be due to invalid IL or missing references) //IL_296d: Unknown result type (might be due to invalid IL or missing references) //IL_2977: Unknown result type (might be due to invalid IL or missing references) //IL_29aa: Unknown result type (might be due to invalid IL or missing references) //IL_2a42: Unknown result type (might be due to invalid IL or missing references) //IL_2a47: Unknown result type (might be due to invalid IL or missing references) //IL_2a4a: Unknown result type (might be due to invalid IL or missing references) int state = employee.state; if (employee.employeeDismissed) { if (Vector3.Distance(employeeObj.transform.position, __instance.employeeSpawnpoint.transform.position) < 2f) { NetworkServer.Destroy(employeeObj); return true; } return false; } if (__instance.employeesOnRiot) { if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); __instance.UnequipBox(employee); } if (state != 0) { employee.state = 0; } return true; } if (state == -1) { return false; } if (!EmployeeNPC.TryGetEmployeeFrom(employeeObj, out var employeeNPC)) { return true; } int taskPriority = employee.taskPriority; if (taskPriority == 4 && state == 2) { if (Object.op_Implicit((Object)(object)employee.currentChasedThiefOBJ)) { if (employee.currentChasedThiefOBJ.transform.position.x < -15f || employee.currentChasedThiefOBJ.transform.position.x > 38f || employee.currentChasedThiefOBJ.GetComponent().productsIDCarrying.Count == 0) { employee.state = 0; return true; } if (Vector3.Distance(employeeObj.transform.position, employee.currentChasedThiefOBJ.transform.position) < 2f) { employeeNPC.MoveEmployeeTo(employeeObj, employee.currentChasedThiefOBJ); employee.state = 3; } else { employee.CallPathing(); } } else { employee.state = 0; } } NavMeshAgent component = employeeObj.GetComponent(); if (IsEmployeeAtDestination(component, out var stoppingDistance)) { employeeNPC.StartLookProcess(RotationSpeedMode.EmployeeTarget); switch (taskPriority) { case 0: break; case 1: switch (state) { case 0: case 1: { if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } int num18 = __instance.CashierGetAvailableCheckout(); if (num18 != -1) { employee.employeeAssignedCheckoutIndex = num18; __instance.UpdateEmployeeCheckouts(); GameObject gameObject = ((Component)__instance.checkoutOBJ.transform.GetChild(num18)).gameObject; employeeNPC.MoveEmployeeTo(((Component)gameObject.transform.Find("EmployeePosition")).transform.position, gameObject); employee.state = 2; return true; } employee.state = 10; return true; } case 2: employee.RPCNotificationAboveHead("NPCemployee0", ""); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3); employee.state = -1; return true; case 3: if (__instance.CheckIfCustomerInQueue(employee.employeeAssignedCheckoutIndex)) { if (!((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().checkoutQueue[0]) { employee.state = 4; return true; } if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().productsLeft > 0) { employee.state = 5; return true; } employee.state = 4; return true; } if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().isCheckoutClosed) { employee.employeeAssignedCheckoutIndex = -1; employee.state = 0; return true; } employee.state = 4; return true; case 4: employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3); employee.state = -1; return true; case 5: { if (((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().productsLeft == 0) { employee.state = 7; return true; } float num17 = Mathf.Clamp(__instance.productCheckoutWait - (float)employee.cashierLevel * 0.01f, 0.05f, 1f); employee.StartWaitState(num17, 6); employee.state = -1; return true; } case 6: { List internalProductListForEmployees = ((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().internalProductListForEmployees; int num13 = employee.cashierLevel / 15; num13 = Mathf.Clamp(num13, 1, 10); int num14 = Mathf.Clamp(employee.cashierValue - num13 - 1, 2, 10); int num15 = 0; for (int n = 0; n < internalProductListForEmployees.Count; n++) { GameObject val7 = internalProductListForEmployees[n]; if (Object.op_Implicit((Object)(object)val7)) { NPC_Info obj4 = employee; obj4.cashierExperience += num14; val7.GetComponent().AddProductFromNPCEmployee(); num15++; if (num15 >= num13) { break; } } } employee.state = 5; return true; } case 7: { GameObject currentNPC = ((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().currentNPC; if (!Object.op_Implicit((Object)(object)currentNPC)) { employee.state = 3; } else if (currentNPC.GetComponent().alreadyGaveMoney) { ((Component)__instance.checkoutOBJ.transform.GetChild(employee.employeeAssignedCheckoutIndex)).GetComponent().AuxReceivePayment(0f, true); employee.state = 3; return true; } float num16 = Mathf.Clamp(__instance.productCheckoutWait - (float)employee.cashierLevel * 0.01f, 0.05f, 1f); employee.StartWaitState(num16, 7); employee.state = -1; return true; } case 10: if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 3f) { employeeNPC.MoveEmployeeToRestPosition(); return true; } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; default: employee.state = 0; return true; } case 2: switch (state) { case 0: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + " logic begin."), false); if (employee.equippedItem > 0) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Box in hand. Dropping."), false); __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } RestockJobInfo restockJob; bool availableRestockJob = RestockJobsManager.GetAvailableRestockJob(__instance, out restockJob); employee.SetRestockJobInfo(restockJob); if (availableRestockJob) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Products available, moving to storage."), false); Vector3 position15 = ((Component)__instance.storageOBJ.transform.GetChild(restockJob.Storage.ShelfIndex).Find("Standspot")).transform.position; employeeNPC.MoveEmployeeToStorage(position15, restockJob.Storage); employeeNPC.AddExtraProductShelfTarget(restockJob.ProdShelf); employee.state = 2; return true; } if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5f) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to rest spot."), false); employeeNPC.MoveEmployeeToRestPosition(); return true; } employeeNPC.ClearNPCReservations(); employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; } case 1: return true; case 2: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Storage reached."), false); RestockJobInfo restockJobInfo = employee.GetRestockJobInfo(); if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo4) && employeeNPC.RefreshAndCheckValidTargetedProductShelf(__instance, restockJobInfo)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Picking box."), false); Transform child2 = __instance.storageOBJ.transform.GetChild(storageSlotInfo4.ShelfIndex); Data_Container component10 = ((Component)child2).GetComponent(); if (Object.op_Implicit((Object)(object)child2.Find("CanvasSigns"))) { component10.EmployeeUpdateArrayValuesStorage(storageSlotInfo4.SlotIndex * 2, storageSlotInfo4.ExtraData.ProductId, -1); } else { component10.EmployeeUpdateArrayValuesStorage(storageSlotInfo4.SlotIndex * 2, -1, -1); } employee.NetworkboxProductID = storageSlotInfo4.ExtraData.ProductId; employee.NetworkboxNumberOfProducts = storageSlotInfo4.ExtraData.Quantity; employee.EquipNPCItem(1); GameObject gameObject2 = ((Component)__instance.shelvesOBJ.transform.GetChild(restockJobInfo.ProdShelf.ShelfIndex)).gameObject; employeeNPC.MoveEmployeeToShelf(((Component)gameObject2.transform.Find("Standspot")).transform.position, restockJobInfo.ProdShelf); employee.state = 3; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Either storage or shelf reservations didnt match."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; return true; } case 3: case 4: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Checking if shelf is valid."), false); RestockJobInfo restockJobInfo2 = employee.GetRestockJobInfo(); if (employeeNPC.RefreshAndCheckValidTargetedProductShelf(__instance, restockJobInfo2)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Shelf reached fully valid."), false); Data_Container component11 = ((Component)__instance.shelvesOBJ.transform.GetChild(restockJobInfo2.ProdShelf.ShelfIndex)).GetComponent(); int maxProductsPerRow = restockJobInfo2.MaxProductsPerRow; int quantity = restockJobInfo2.ProdShelf.ExtraData.Quantity; if (employee.NetworkboxNumberOfProducts > 0 && quantity < maxProductsPerRow) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Adding products to shelf row."), false); int num30 = Mathf.Clamp(maxProductsPerRow - quantity, NumTransferItemsBase, employee.restockerLevel); int num31 = Mathf.Clamp(employee.boxNumberOfProducts, NumTransferItemsBase, employee.restockerLevel); int numMovedProducts = Mathf.Min(num30, num31); numMovedProducts = IncreasedItemTransferPatch.GetNumTransferItems(employee.boxNumberOfProducts, quantity, maxProductsPerRow, IncreasedItemTransferPatch.CharacterType.Employee, numMovedProducts); component11.EmployeeAddsItemToRow(restockJobInfo2.ShelfProdInfoIndex, numMovedProducts); employee.NetworkboxNumberOfProducts = employee.boxNumberOfProducts - numMovedProducts; employee.StartWaitState(__instance.employeeItemPlaceWait, 4); employee.state = -1; NPC_Info obj11 = employee; obj11.restockerExperience += employee.restockerValue; return true; } } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Target shelf is already full or not valid. Searching for a different one."), false); int productId = restockJobInfo2.ProdShelf.ExtraData.ProductId; if (employee.NetworkboxNumberOfProducts > 0 && ContainerSearch.CheckIfProdShelfWithSameProduct(__instance, productId, employee, out (ProductShelfSlotInfo, int) result)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Found another different shelf to add products."), false); employee.UpdateRestockJobInfo(result.Item1, result.Item2); employeeNPC.MoveEmployeeToShelf(result.Item1.ExtraData.Position, result.Item1); employee.state = 3; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Box is empty or there is no other shelf with the same product."), false); employee.state = 5; return true; } case 5: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Box in hand but cant restock anymore. Deciding what to do."), false); if (employee.NetworkboxNumberOfProducts <= 0) { MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 30, 6, 9); return true; } if (GetStorageContainerWithBoxToMerge(__instance, employee, employeeNPC)) { return true; } StorageSlotInfo freeStorageContainer = ContainerSearch.GetFreeStorageContainer(__instance, employeeObj.transform, employee.NetworkboxProductID); if (freeStorageContainer.ShelfFound) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to storage to place box."), false); Vector3 position14 = ((Component)((Component)__instance.storageOBJ.transform.GetChild(freeStorageContainer.ShelfIndex)).gameObject.transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeToStorage(position14, freeStorageContainer); employee.state = 7; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Moving to left over boxes spot."), false); employeeNPC.MoveEmployeeTo(__instance.leftoverBoxesSpotOBJ, null); employee.state = 8; return true; } case 6: LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Removing box in hand"), false); UnequipBox(employee); return true; case 7: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Arrived at storage, but checking again if there is some other slot to merge with."), false); if (GetStorageContainerWithBoxToMerge(__instance, employee, employeeNPC)) { return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": No merge possible."), false); if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo3)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Placing box in storage."), false); ((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo3.ShelfIndex)).GetComponent().EmployeeUpdateArrayValuesStorage(storageSlotInfo3.SlotIndex * 2, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts); employee.state = 6; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Target storage is not valid anymore."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 5); employee.state = -1; return true; } case 8: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Dropping box at left over spot."), false); Vector3 val18 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 4f, Random.Range(-1f, 1f)); ((Component)GameData.Instance).GetComponent().SpawnBoxFromEmployee(val18, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts); employee.state = 6; return true; } case 9: { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Recycling box."), false); float funds2 = 1.5f * (float)((Component)GameData.Instance).GetComponent().boxRecycleFactor; AchievementsManager.Instance.CmdAddAchievementPoint(2, 1); StatisticsManager instance6 = StatisticsManager.Instance; instance6.totalBoxesRecycled++; SMTAntiCheat_Helper.Instance.CmdAlterFunds(funds2); employee.state = 6; return true; } case 20: LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Reached storage and merging contents."), false); EmployeeTryMergeBoxContents(__instance, employee, employeeNPC, 5); return true; case 30: if (Object.op_Implicit((Object)(object)employee.closestCardboardBaler)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Adding empty box to cardboard baler."), false); employee.closestCardboardBaler.GetComponent().AuxiliarAddBoxToBaler(employee.boxProductID); UnequipBox(employee); } else { LOG.TEMPDEBUG_FUNC((Func)(() => "Restocker #" + GetUniqueId(employee) + ": Cardboard baler not there anymore."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } return true; default: employee.state = 0; return true; } case 3: switch (state) { case 0: { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + " logic begin."), false); if (employee.equippedItem > 0) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Dropping current box."), false); __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } GroundBoxStorageTarget closestGroundBox = GroundBoxSearch.GetClosestGroundBox(__instance, employeeObj.transform); NavMeshHit val14 = default(NavMeshHit); if (closestGroundBox.FoundGroundBox && NavMesh.SamplePosition(new Vector3(closestGroundBox.GroundBoxObject.transform.position.x, 0f, closestGroundBox.GroundBoxObject.transform.position.z), ref val14, 1f, -1)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Going to pick up box."), false); employee.randomBox = closestGroundBox.GroundBoxObject; employeeNPC.MoveEmployeeToBox(((NavMeshHit)(ref val14)).position, closestGroundBox.GroundBoxObject); if (closestGroundBox.HasStorageTarget) { employeeNPC.AddExtraStorageTarget(closestGroundBox.StorageSlot); } employee.state = 1; return true; } employee.state = 10; return true; } case 1: if (Object.op_Implicit((Object)(object)employee.randomBox)) { Vector3 val16 = new Vector3(employee.randomBox.transform.position.x, 0f, employee.randomBox.transform.position.z); Vector3 val17 = default(Vector3); ((Vector3)(ref val17))..ctor(((Component)employee).transform.position.x, 0f, ((Component)employee).transform.position.z); if (Vector3.Distance(val16, val17) < 2f) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Picking up box."), false); BoxData component9 = employee.randomBox.GetComponent(); employee.NetworkboxProductID = component9.productID; employee.NetworkboxNumberOfProducts = component9.numberOfProducts; employee.EquipNPCItem(1); ((Component)GameData.Instance).GetComponent().EmployeeDestroyBox(employee.randomBox); if (component9.numberOfProducts > 0) { employee.state = 18; return true; } employee.state = 6; return true; } } LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Box doesnt exist or is not at pick up range anymore."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; return true; case 2: { StorageSlotInfo storageSlotInfo = null; Vector3 zero = Vector3.zero; bool validStorageFound = false; if (employeeNPC.HasTargetedStorage()) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Checking pre-reserved storage."), false); validStorageFound = employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: true, out storageSlotInfo); LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Pre-reserved storage is " + (validStorageFound ? "" : "no longer ") + "valid."), false); } if (!validStorageFound) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Searching for storage to place held box."), false); storageSlotInfo = ContainerSearch.GetFreeStorageContainer(__instance, employeeObj.transform, employee.NetworkboxProductID); validStorageFound = storageSlotInfo.ShelfFound; LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Free storage " + (validStorageFound ? "" : "couldnt be ") + "found."), false); } if (validStorageFound) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Moving to storage to place box."), false); zero = ((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo.ShelfIndex).Find("Standspot")).transform.position; employeeNPC.MoveEmployeeToStorage(zero, storageSlotInfo); employee.state = 3; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Moving to drop box at left over spot."), false); employeeNPC.MoveEmployeeTo(__instance.leftoverBoxesSpotOBJ, null); employee.state = 4; return true; } case 3: { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Arrived at storage."), false); if (employeeNPC.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo2)) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Placing box in storage."), false); ((Component)__instance.storageOBJ.transform.GetChild(storageSlotInfo2.ShelfIndex)).GetComponent().EmployeeUpdateArrayValuesStorage(storageSlotInfo2.SlotIndex * 2, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts); employee.state = 5; NPC_Info obj10 = employee; obj10.storageExperience += employee.storageValue; return true; } LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Storage no longer valid."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 2); employee.state = -1; return true; } case 4: { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": At left over spot. Spawning box at drop."), false); Vector3 val15 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 3f, Random.Range(-1f, 1f)); ((Component)GameData.Instance).GetComponent().SpawnBoxFromEmployee(val15, employee.NetworkboxProductID, employee.NetworkboxNumberOfProducts); employee.state = 5; return true; } case 5: LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Removing box in hand."), false); UnequipBox(employee); return true; case 6: MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 33, 5, 7); return true; case 7: { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Recycling."), false); float funds = 1.5f * (float)((Component)GameData.Instance).GetComponent().boxRecycleFactor; AchievementsManager.Instance.CmdAddAchievementPoint(2, 1); StatisticsManager instance5 = StatisticsManager.Instance; instance5.totalBoxesRecycled++; SMTAntiCheat_Helper.Instance.CmdAlterFunds(funds); employee.state = 5; return true; } case 10: if ((double)Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5) { LOG.TEMPDEBUG_FUNC((Func)(() => "Storage #" + GetUniqueId(employee) + ": Moving to rest spot."), false); employeeNPC.MoveEmployeeToRestPosition(); return true; } employeeNPC.ClearNPCReservations(); employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; case 18: if (ContainerSearch.MoreThanOneBoxToMergeCheck(__instance, employee.boxProductID)) { employee.state = 19; return true; } employee.state = 2; return true; case 19: if (employee.boxNumberOfProducts <= 0) { employee.state = 6; return true; } if (GetStorageContainerWithBoxToMerge(__instance, employee, employeeNPC)) { return true; } employeeNPC.ClearNPCReservations(); employee.state = 2; return true; case 20: EmployeeTryMergeBoxContents(__instance, employee, employeeNPC, 19); return true; case 33: if (Object.op_Implicit((Object)(object)employee.closestCardboardBaler)) { employee.closestCardboardBaler.GetComponent().AuxiliarAddBoxToBaler(employee.boxProductID); UnequipBox(employee); } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } return true; default: employee.state = 0; return true; } case 4: switch (state) { case 0: if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } if (GetThiefTarget(__instance)) { return true; } if (__instance.IsFirstSecurityEmployee(employeeObj) || (__instance.customersnpcParentOBJ.transform.childCount == 0 && GameData.Instance.timeOfDay > 22f)) { GameObject closestDropProduct = __instance.GetClosestDropProduct(employeeObj); if (Object.op_Implicit((Object)(object)closestDropProduct)) { employee.droppedProductOBJ = closestDropProduct; employee.state = 4; employeeNPC.MoveEmployeeTo(closestDropProduct, null); return true; } } employee.state = 1; return true; case 1: { int num29 = __instance.RetrieveCorrectPatrolPoint(employeeObj); Transform val13 = ((num29 >= __instance.patrolPositionOBJ.transform.childCount) ? __instance.patrolPositionOBJ.transform.GetChild(0) : __instance.patrolPositionOBJ.transform.GetChild(num29)); if (Vector3.Distance(((Component)employee).transform.position, val13.position) > 3f) { employeeNPC.MoveSecurityAndScout(val13.position); return true; } employee.StartWaitState(1f, 0); employee.state = -1; return true; } case 3: if (Object.op_Implicit((Object)(object)employee.currentChasedThiefOBJ) && employee.currentChasedThiefOBJ.GetComponent().productsIDCarrying.Count > 0) { employee.currentChasedThiefOBJ.GetComponent().AuxiliarAnimationPlay(0); employee.RpcEmployeeHitThief(); float num28 = Mathf.Clamp(1.45f - (float)employee.securityLevel * 0.01f, 0.5f, 2f); employee.StartWaitState(num28, 2); employee.state = -1; NPC_Info obj9 = employee; obj9.securityExperience += 5 * employee.securityValue; return true; } employee.StartWaitState(0.5f, 0); employee.state = -1; return true; case 4: if (Object.op_Implicit((Object)(object)employee.droppedProductOBJ)) { EnumSecurityPickUp value = ModConfig.Instance.ImprovedSecurityPickUpMode.Value; if (value != 0 && newProdPickUpWorking && DoSecurityAreaPickUp(__instance, value, employeeObj, employee, stoppingDistance)) { employee.StartWaitState(0.5f, 0); employee.state = -1; return true; } employee.droppedProductOBJ.GetComponent().RecoverStolenProductFromEmployee(); employee.StartWaitState(0.5f, 0); employee.state = -1; NPC_Info obj8 = employee; obj8.securityExperience++; return true; } employee.state = 0; return true; default: employee.state = 0; return true; case 2: return true; } case 5: switch (state) { case 0: { if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } GameObject furnitureToFix = __instance.GetFurnitureToFix(employeeObj); if (Object.op_Implicit((Object)(object)furnitureToFix)) { employee.currentFurnitureToFix = furnitureToFix; employeeNPC.MoveEmployeeTo(furnitureToFix.transform.Find("Standspot").position, furnitureToFix); employee.state = 1; } else { employee.state = 10; } return true; } case 10: if (!TryMoveToClosestBale(__instance, employee, employeeObj, employeeNPC)) { if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5f) { LOG.TEMPDEBUG_FUNC((Func)(() => "Technician #" + GetUniqueId(employee) + ": Moving to rest spot."), false); employeeNPC.MoveEmployeeToRestPosition(); } else { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; } } return true; case 1: if (Object.op_Implicit((Object)(object)employee.currentFurnitureToFix) && __instance.RetrieveFurnitureRepairState(employee.currentFurnitureToFix)) { float num27 = 8f - (float)employee.technicianLevel * 0.1f; num27 = Mathf.Clamp(num27, 2f, 8f); employee.StartWaitState(num27, 2); employee.state = -1; return true; } return false; case 2: if (Object.op_Implicit((Object)(object)employee.currentFurnitureToFix) && __instance.RetrieveFurnitureRepairState(employee.currentFurnitureToFix)) { if (Object.op_Implicit((Object)(object)employee.currentFurnitureToFix.GetComponent())) { employee.currentFurnitureToFix.GetComponent().CmdFixBreakingEvent(); } else if (Object.op_Implicit((Object)(object)employee.currentFurnitureToFix.GetComponent())) { employee.currentFurnitureToFix.GetComponent().CmdFixBreakingEvent(); } NPC_Info obj7 = employee; obj7.technicianExperience += employee.technicianValue * 10; } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; case 3: UnequipBox(employee); return true; case 30: if (Object.op_Implicit((Object)(object)employee.currentCardboardBale)) { Vector3 val11 = new Vector3(employee.currentCardboardBale.transform.position.x, 0f, employee.currentCardboardBale.transform.position.z); Vector3 val12 = default(Vector3); ((Vector3)(ref val12))..ctor(((Component)employee).transform.position.x, 0f, ((Component)employee).transform.position.z); if (Vector3.Distance(val11, val12) < 2f) { employee.EquipNPCItem(2); ((Component)GameData.Instance).GetComponent().EmployeeDestroyBox(employee.currentCardboardBale); employee.state = 31; return true; } } employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; return false; case 31: MoveToGarbageContainer(__instance, employeeObj, employee, employeeNPC, 3, 32); return true; case 32: { float num26 = 18f * (float)((Component)GameData.Instance).GetComponent().boxRecycleFactor; AchievementsManager.Instance.CmdAddAchievementPoint(16, 1); StatisticsManager instance4 = StatisticsManager.Instance; instance4.totalBalesRecycled++; GameData.Instance.CmdAlterFunds(num26); NPC_Info obj6 = employee; obj6.technicianExperience += employee.technicianValue; employee.state = 3; return true; } default: employee.state = 0; return true; } case 6: switch (state) { case 0: if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } if (((Component)GameData.Instance).GetComponent().addonsBought[0] && OrderPackaging.Instance.isOrderDepartmentActivated && Object.op_Implicit((Object)(object)__instance.RetrieveAnOrderPickupPoint(false))) { int num25 = __instance.RetrievePackagingFreeOrderIndex(); if (num25 >= 0) { employee.packagingAssignedOrderIndex = num25; employeeNPC.MoveEmployeeTo(__instance.AttemptToGetOrderingDepartmentPosition(), __instance.orderingDepartmentSpotOBJ); employee.state = 1; return true; } } employee.state = 10; return true; case 10: if (Vector3.Distance(((Component)employee).transform.position, __instance.restSpotOBJ.transform.position) > 6.5f) { employeeNPC.MoveEmployeeToRestPosition(); return true; } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; case 1: if (OrderPackaging.Instance.ordersData[employee.packagingAssignedOrderIndex] != "") { employee.packagingAssignedOrderData = OrderPackaging.Instance.ordersData[employee.packagingAssignedOrderIndex]; OrderPackaging.Instance.RemoveOrderFromEmployee(employee.packagingAssignedOrderIndex); string[] array6 = employee.packagingAssignedOrderData.Split(new char[1] { '|' }); if (array6[3] == "") { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; } string[] array7 = array6[3].Split(new char[1] { '_' }); for (int num21 = 0; num21 < array7.Length; num21++) { employee.packagingAssignedOrderProducts.Add(int.Parse(array7[num21])); } int num22 = employee.orderingLevel / 2; num22 = Mathf.Clamp(num22, 1, 25); for (int num23 = 0; num23 < num22; num23++) { int item2 = ProductListing.Instance.availableProducts[Random.Range(0, ProductListing.Instance.availableProducts.Count)]; employee.packagingAssignedOrderProducts.Add(item2); } if (employee.packagingPackedOrderProducts.Count > 0) { employee.packagingPackedOrderProducts.Clear(); } employee.EquipNPCItem(3); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 2); employee.state = -1; return true; } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return false; case 2: if (employee.packagingAssignedOrderProducts.Count > 0) { int boxIDProduct = employee.packagingAssignedOrderProducts[0]; GenericShelfSlotInfo firstOfAnyShelfWithProduct = ContainerSearch.GetFirstOfAnyShelfWithProduct(__instance, boxIDProduct); if (firstOfAnyShelfWithProduct.ShelfFound) { GameObject val10 = ((firstOfAnyShelfWithProduct.ShelfType == ShelfType.ProdShelfSlot) ? __instance.shelvesOBJ : __instance.storageOBJ); employee.orderProductLocationInfoArray = new int[3] { (int)firstOfAnyShelfWithProduct.ShelfType, firstOfAnyShelfWithProduct.ShelfIndex, firstOfAnyShelfWithProduct.SlotIndex * 2 }; Transform child = val10.transform.GetChild(firstOfAnyShelfWithProduct.SlotIndex); Vector3 position13 = ((Component)child).transform.Find("Standspot").position; employeeNPC.MoveEmployeeTo(position13, ((Component)child).gameObject); employee.state = 3; } else { employee.packagingAssignedOrderProducts.RemoveAt(0); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 2); employee.state = -1; } } else if (employee.packagingPackedOrderProducts.Count > 0) { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 4); employee.state = -1; } else { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; } return false; case 3: { Data_Container component8 = ((Component)((employee.orderProductLocationInfoArray[0] != 0) ? __instance.shelvesOBJ : __instance.storageOBJ).transform.GetChild(employee.orderProductLocationInfoArray[1])).GetComponent(); int[] productInfoArray3 = component8.productInfoArray; int num24 = productInfoArray3[employee.orderProductLocationInfoArray[2] + 1]; if (employee.packagingAssignedOrderProducts[0] == productInfoArray3[employee.orderProductLocationInfoArray[2]] && num24 > 0) { if (employee.orderProductLocationInfoArray[0] == 0) { if (num24 == 1) { if (Object.op_Implicit((Object)(object)((Component)component8).transform.Find("CanvasSigns"))) { component8.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], employee.packagingAssignedOrderProducts[0], -1); } else { component8.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], -1, -1); } ((Component)GameData.Instance).GetComponent().SpawnBoxFromEmployee(employeeObj.transform.position, employee.packagingAssignedOrderProducts[0], 0); } else { component8.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], employee.packagingAssignedOrderProducts[0], num24 - 1); } } else { component8.NPCGetsItemFromRow(employee.packagingAssignedOrderProducts[0]); } employee.packagingPackedOrderProducts.Add(employee.packagingAssignedOrderProducts[0]); employee.packagingAssignedOrderProducts.RemoveAt(0); } employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 2); employee.state = -1; return true; } case 4: { GameObject val9 = __instance.RetrieveAnOrderPickupPoint(true); if (Object.op_Implicit((Object)(object)val9)) { employeeNPC.MoveEmployeeTo(val9.transform.Find("Standspot").position, val9); employee.state = 5; } else { employee.RPCNotificationAboveHead("emplomsgnopckp", ""); employee.StartWaitState(8f, 4); employee.state = -1; } return true; } case 5: { GameObject val8 = __instance.RetrieveAnOrderPickupPoint(true); if (Vector3.Distance(val8.transform.position, employeeObj.transform.position) < 4f) { StringBuilder stringBuilder = new StringBuilder(); for (int num19 = 0; num19 < employee.packagingPackedOrderProducts.Count; num19++) { stringBuilder.Append(employee.packagingPackedOrderProducts[num19].ToString()); if (num19 != employee.packagingPackedOrderProducts.Count - 1) { stringBuilder.Append('_'); } } string[] array5 = employee.packagingAssignedOrderData.Split(new char[1] { '|' }); string item = array5[0] + "|" + array5[1] + "|" + array5[2] + "|" + stringBuilder.ToString(); __instance.NPCsOrdersList.Add(item); string text4 = array5[0] + "|" + stringBuilder.ToString(); string[] pickupsData = val8.GetComponent().pickupsData; for (int num20 = 0; num20 < pickupsData.Length; num20++) { if (pickupsData[num20] == "") { val8.GetComponent().AddOrderBox(num20, text4); break; } } AchievementsManager.Instance.CmdAddAchievementPoint(19, 1); StatisticsManager instance3 = StatisticsManager.Instance; instance3.onlineOrdersMade++; NPC_Info obj5 = employee; obj5.orderingExperience += employee.orderingValue * 25; UnequipBox(employee); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 4); employee.state = -1; } return true; } case 6: case 7: case 8: case 9: return true; default: return true; } case 7: switch (state) { case 0: { employeeNPC.ClearNPCReservations(); if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } int num6 = __instance.GetPriorityIndex(employeeObj, 7) % 3; bool flag2 = false; bool flag3 = false; employee.thiefProductsNumber = -1; if (((Component)GameData.Instance).GetComponent().addonsBought[1]) { int[] array4 = num6 switch { 1 => new int[3] { 1, 2, 0 }, 2 => new int[3] { 2, 0, 1 }, _ => new int[3] { 0, 1, 2 }, }; NavMeshHit val4 = default(NavMeshHit); for (int m = 0; m < array4.Length; m++) { switch (array4[m]) { case 1: if (__instance.GetFreeManufacturingStorageContainer(10000, "999") < 0) { GameObject randomGroundManufacturingBoxAllowedInStorage = __instance.GetRandomGroundManufacturingBoxAllowedInStorage(employeeObj); if (Object.op_Implicit((Object)(object)randomGroundManufacturingBoxAllowedInStorage)) { employee.thiefProductsNumber = 1; employee.randomBox = randomGroundManufacturingBoxAllowedInStorage; employeeNPC.MoveEmployeeTo(randomGroundManufacturingBoxAllowedInStorage, null); flag2 = true; employee.state = 21; } else { employee.state = 1; } } else { GameObject randomGroundManufacturingBox = __instance.GetRandomGroundManufacturingBox(employeeObj); if (Object.op_Implicit((Object)(object)randomGroundManufacturingBox) && NavMesh.SamplePosition(new Vector3(randomGroundManufacturingBox.transform.position.x, 0f, randomGroundManufacturingBox.transform.position.z), ref val4, 1f, -1)) { employee.thiefProductsNumber = 1; employee.randomBox = randomGroundManufacturingBox; employeeNPC.MoveEmployeeTo(((NavMeshHit)(ref val4)).position, null); flag2 = true; employee.state = 21; } } break; case 2: if (__instance.mainManufacturingUpdateIsBeingCalculated) { flag3 = true; break; } employee.productAvailableArray = __instance.ReturnWeightedManufacturerTask(employeeObj, employee); if (employee.productAvailableArray[0] != -1) { employee.thiefProductsNumber = 2; Vector3 position9 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(employee.productAvailableArray[2])).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position9, null); flag2 = true; employee.state = 42; } break; default: { int manufacturingProducerWithQueue = __instance.GetManufacturingProducerWithQueue(num6); if (manufacturingProducerWithQueue >= 0) { employee.thiefProductsNumber = 0; __instance.manufacturingProducersList[manufacturingProducerWithQueue].GetComponent().EmployeeAssignCoroutineCall(employee); employee.packagingAssignedOrderIndex = manufacturingProducerWithQueue; flag2 = true; employee.state = 2; } break; } } if (flag2 || flag3) { break; } } } if (flag3) { employee.StartWaitState(0.2f, 0); employee.state = -1; } else if (!flag2) { employee.state = 1; } return true; } case 1: if (Vector3.Distance(((Component)employee).transform.position, __instance.manufacturingRestSpotOBJ.transform.position) > 6.5f) { Vector3 val5 = __instance.manufacturingRestSpotOBJ.transform.position + new Vector3(Random.Range(-4f, 4f), 0f, Random.Range(-4f, 4f)); NavMeshHit val6 = default(NavMeshHit); if (NavMesh.SamplePosition(val5, ref val6, 1f, -1) && ((NavMeshHit)(ref val6)).distance > 0.02f) { val5 = ((NavMeshHit)(ref val6)).position; } employeeNPC.MoveEmployeeTo(val5, null); } else { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; } return true; case 2: if (Object.op_Implicit((Object)(object)__instance.manufacturingProducersList[employee.packagingAssignedOrderIndex])) { ManufacturingProduction component3 = __instance.manufacturingProducersList[employee.packagingAssignedOrderIndex].GetComponent(); if (component3.productQueue.Count > 0) { string text = ManufacturingBase.Instance.RetrieveBaseRecipe(component3.productQueue[0]); string text2 = component3.combinableQueue[0]; employee.manufacturedEmployeeProductsList.Clear(); string[] array2 = text.Split(new char[1] { '|' }); for (int j = 0; j < array2.Length; j++) { string[] array3 = array2[j].Split(new char[1] { '-' }); for (int k = 0; k < array3.Length; k++) { if (ContainerSearch.GetFirstOfAnyShelfWithProduct(__instance, int.Parse(array3[k])).ShelfFound) { employee.manufacturedEmployeeProductsList.Add(array3[k]); break; } } } if (text2 != "" && text2 != "999") { array2 = text2.Split(new char[1] { '-' }); for (int l = 0; l < array2.Length; l++) { employee.manufacturedEmployeeProductsList.Add(array2[l]); } } employee.EquipNPCItem(5); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3); employee.state = -1; return true; } } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; case 3: if (employee.manufacturedEmployeeProductsList.Count > 0) { string[] array = employee.manufacturedEmployeeProductsList[0].Split(new char[1] { '|' }); bool flag = false; GameObject val = null; int num = 0; for (int i = 0; i < array.Length; i++) { int[] storageShelfWithProduct = __instance.GetStorageShelfWithProduct(int.Parse(array[i])); if (storageShelfWithProduct[0] > -1) { employee.orderProductLocationInfoArray = storageShelfWithProduct; val = ((storageShelfWithProduct[0] != 0) ? __instance.shelvesOBJ : __instance.storageOBJ); flag = true; num = storageShelfWithProduct[1]; break; } } if (flag) { Vector3 position = ((Component)val.transform.GetChild(num)).transform.Find("Standspot").position; employeeNPC.MoveEmployeeTo(position, null); employee.state = 4; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3); employee.state = -1; } } else if (Object.op_Implicit((Object)(object)__instance.manufacturingProducersList[employee.packagingAssignedOrderIndex])) { Vector3 position2 = __instance.manufacturingProducersList[employee.packagingAssignedOrderIndex].transform.Find("Standspot").position; employeeNPC.MoveEmployeeTo(position2, null); employee.state = 5; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } return true; case 4: { Data_Container component6 = ((Component)((employee.orderProductLocationInfoArray[0] != 0) ? __instance.shelvesOBJ : __instance.storageOBJ).transform.GetChild(employee.orderProductLocationInfoArray[1])).GetComponent(); int[] productInfoArray2 = component6.productInfoArray; int num7 = productInfoArray2[employee.orderProductLocationInfoArray[2] + 1]; int num8 = int.Parse(employee.manufacturedEmployeeProductsList[0]); if (num8 == productInfoArray2[employee.orderProductLocationInfoArray[2]] && num7 > 0) { if (employee.orderProductLocationInfoArray[0] == 0) { if (num7 == 1) { if (Object.op_Implicit((Object)(object)((Component)component6).transform.Find("CanvasSigns"))) { component6.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], num8, -1); } else { component6.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], -1, -1); } ((Component)GameData.Instance).GetComponent().SpawnBoxFromEmployee(employeeObj.transform.position, num8, 0); } else { component6.EmployeeUpdateArrayValuesStorage(employee.orderProductLocationInfoArray[2], num8, num7 - 1); } } else { component6.NPCGetsItemFromRow(num8); } employee.manufacturedEmployeeProductsList.RemoveAt(0); } employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 3); employee.state = -1; return true; } case 5: if (Object.op_Implicit((Object)(object)__instance.manufacturingProducersList[employee.packagingAssignedOrderIndex])) { ManufacturingProduction component4 = __instance.manufacturingProducersList[employee.packagingAssignedOrderIndex].GetComponent(); if (component4.productQueue.Count > 0) { NPC_Info obj = employee; obj.manufacturingExperience += employee.manufacturingValue * 3; component4.ProduceFromEmployee(); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; return true; } } employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; case 21: if (Object.op_Implicit((Object)(object)employee.randomBox) && Vector3.Distance(new Vector3(employee.randomBox.transform.position.x, 0f, employee.randomBox.transform.position.z), new Vector3(((Component)employee).transform.position.x, 0f, ((Component)employee).transform.position.z)) < 2f) { ManufacturingBoxData component2 = employee.randomBox.GetComponent(); employee.NetworkboxProductID = component2.manufacturedProductIndex; employee.NetworkboxNumberOfProducts = component2.numberOfProducts; employee.mBoxCombinableData = component2.combinablesData; employee.EquipNPCItem(4); ((Component)GameData.Instance).GetComponent().EmployeeDestroyBox(employee.randomBox); if (component2.numberOfProducts > 0) { employee.state = 31; } else { employee.state = 26; } } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } return true; case 22: { int freeManufacturingStorageContainer4 = __instance.GetFreeManufacturingStorageContainer(employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageContainer4 >= 0) { employee.currentFreeStorageIndex = freeManufacturingStorageContainer4; employee.currentFreeStorageOBJ = ((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(freeManufacturingStorageContainer4)).gameObject; Vector3 position10 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(freeManufacturingStorageContainer4)).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position10, null); employee.state = 23; } else { Vector3 position11 = __instance.leftoverBoxesSpotOBJ.transform.position; employeeNPC.MoveEmployeeTo(position11, null); employee.state = 24; } return true; } case 23: { int freeManufacturingStorageContainer3 = __instance.GetFreeManufacturingStorageContainer(employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageContainer3 >= 0 && employee.currentFreeStorageIndex == freeManufacturingStorageContainer3 && Object.op_Implicit((Object)(object)employee.currentFreeStorageOBJ)) { int freeManufacturingStorageRow2 = __instance.GetFreeManufacturingStorageRow(freeManufacturingStorageContainer3, employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageRow2 >= 0) { ((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(freeManufacturingStorageContainer3)).GetComponent().EmployeeUpdateArrayValuesStorage(freeManufacturingStorageRow2 * 2, employee.boxProductID, employee.boxNumberOfProducts, employee.mBoxCombinableData); employee.state = 25; NPC_Info obj2 = employee; obj2.manufacturingExperience += employee.manufacturingValue; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 22); employee.state = -1; } } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 22); employee.state = -1; } return true; } case 24: { Vector3 val3 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 3f, Random.Range(-1f, 1f)); ((Component)GameData.Instance).GetComponent().SpawnManufacturingBoxFromEmployee(val3, employee.boxProductID, employee.boxNumberOfProducts, employee.mBoxCombinableData); employee.state = 25; return true; } case 25: UnequipBox(employee); return true; case 26: MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 34, 25, 27); return true; case 27: { float num3 = 1.5f * (float)((Component)GameData.Instance).GetComponent().boxRecycleFactor; AchievementsManager.Instance.CmdAddAchievementPoint(2, 1); StatisticsManager instance2 = StatisticsManager.Instance; instance2.totalBoxesRecycled++; GameData.Instance.CmdAlterFunds(num3); employee.state = 25; return true; } case 31: if (__instance.MoreThanOneManufacturingBoxToMergeCheck(employee.boxProductID, employee.mBoxCombinableData)) { employee.state = 32; } else { employee.state = 22; } return true; case 32: { if (employee.boxNumberOfProducts <= 0) { employee.state = 26; return true; } int storageContainerWithManufacturingBoxToMerge2 = __instance.GetStorageContainerWithManufacturingBoxToMerge(employee.boxProductID, employee.mBoxCombinableData); if (storageContainerWithManufacturingBoxToMerge2 >= 0) { employee.currentFreeStorageIndex = storageContainerWithManufacturingBoxToMerge2; Vector3 position4 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(storageContainerWithManufacturingBoxToMerge2)).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position4, null); employee.state = 33; } else { employee.state = 22; } return true; } case 33: { int storageRowWithManufacturingBoxToMerge2 = __instance.GetStorageRowWithManufacturingBoxToMerge(employee.currentFreeStorageIndex, employee.boxProductID, employee.mBoxCombinableData); if (storageRowWithManufacturingBoxToMerge2 >= 0) { __instance.EmployeeMergeManufacturingBoxContents(employee, employee.currentFreeStorageIndex, employee.boxProductID, storageRowWithManufacturingBoxToMerge2); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 32); employee.state = -1; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 32); employee.state = -1; } return true; } case 34: if (Object.op_Implicit((Object)(object)employee.closestCardboardBaler)) { employee.closestCardboardBaler.GetComponent().AuxiliarAddBoxToBaler(employee.boxProductID); UnequipBox(employee); } return true; case 42: { ManufacturingContainer component5 = ((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(employee.productAvailableArray[2])).GetComponent(); int[] productInfoArray = component5.productInfoArray; int num4 = productInfoArray[employee.productAvailableArray[3]]; string text3 = component5.combinableInfoArray[employee.productAvailableArray[3] / 2]; if (num4 == employee.productAvailableArray[5] && text3 == employee.packagingAssignedOrderData) { int num5 = productInfoArray[employee.productAvailableArray[3] + 1]; if (num5 <= 0) { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; return true; } if (Object.op_Implicit((Object)(object)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(employee.productAvailableArray[2])).transform.Find("CanvasSigns"))) { component5.EmployeeUpdateArrayValuesStorage(employee.productAvailableArray[3], num4, -1, text3); } else { component5.EmployeeUpdateArrayValuesStorage(employee.productAvailableArray[3], -1, -1, ""); } employee.NetworkboxProductID = num4; employee.NetworkboxNumberOfProducts = num5; employee.mBoxCombinableData = text3; employee.EquipNPCItem(4); Vector3 position8 = ((Component)((Component)__instance.manufacturingShelvesOBJ.transform.GetChild(employee.productAvailableArray[0])).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position8, null); employee.state = 43; } else { employee.StartWaitState(ModConfig.Instance.EmployeeIdleWait.Value, 0); employee.state = -1; } return true; } case 43: if (((Component)__instance.manufacturingShelvesOBJ.transform.GetChild(employee.productAvailableArray[0])).GetComponent().productInfoArray[employee.productAvailableArray[1]] == employee.productAvailableArray[4]) { employee.state = 44; } else { employee.state = 45; } return true; case 44: { ManufacturingContainer component7 = ((Component)__instance.manufacturingShelvesOBJ.transform.GetChild(employee.productAvailableArray[0])).GetComponent(); int num9 = component7.productInfoArray[employee.productAvailableArray[1] + 1]; int maxManufacturingProductsPerRow = __instance.GetMaxManufacturingProductsPerRow(employee.productAvailableArray[0], employee.productAvailableArray[4]); if (employee.boxNumberOfProducts > 0 && num9 < maxManufacturingProductsPerRow) { int num10 = Mathf.Clamp(maxManufacturingProductsPerRow - num9, 1, employee.restockerLevel); int num11 = Mathf.Clamp(employee.boxNumberOfProducts, 1, employee.restockerLevel); int num12 = num11; if (num10 < num11) { num12 = num10; } component7.EmployeeAddsItemToRow(employee.productAvailableArray[1], num12); employee.NetworkboxNumberOfProducts = employee.boxNumberOfProducts - num12; employee.StartWaitState(__instance.employeeItemPlaceWait, 44); employee.state = -1; NPC_Info obj3 = employee; obj3.manufacturingExperience += employee.manufacturingValue; } else if (employee.boxNumberOfProducts > 0 && __instance.CheckIfManufacturingShelfWithSameProduct(employee.productAvailableArray[4], employee, employee.productAvailableArray[0], employee.packagingAssignedOrderData)) { Vector3 position12 = ((Component)((Component)__instance.manufacturingShelvesOBJ.transform.GetChild(employee.productAvailableArray[0])).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position12, null); employee.state = 43; } else { employee.state = 45; } return true; } case 45: { if (employee.boxNumberOfProducts <= 0) { MoveToBalerOrGarbageContainer(__instance, employeeObj, employee, employeeNPC, 60, 46, 49); return true; } int storageContainerWithManufacturingBoxToMerge3 = __instance.GetStorageContainerWithManufacturingBoxToMerge(employee.boxProductID, employee.mBoxCombinableData); if (storageContainerWithManufacturingBoxToMerge3 >= 0) { employee.currentFreeStorageIndex = storageContainerWithManufacturingBoxToMerge3; Vector3 position5 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(storageContainerWithManufacturingBoxToMerge3)).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position5, null); employee.state = 50; return true; } int freeManufacturingStorageContainer2 = __instance.GetFreeManufacturingStorageContainer(employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageContainer2 >= 0) { Vector3 position6 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(freeManufacturingStorageContainer2)).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position6, null); employee.state = 47; } else { Vector3 position7 = __instance.leftoverBoxesSpotOBJ.transform.position; employeeNPC.MoveEmployeeTo(position7, null); employee.state = 48; } return true; } case 46: UnequipBox(employee); return true; case 47: { int storageContainerWithManufacturingBoxToMerge = __instance.GetStorageContainerWithManufacturingBoxToMerge(employee.boxProductID, employee.mBoxCombinableData); if (storageContainerWithManufacturingBoxToMerge >= 0) { employee.currentFreeStorageIndex = storageContainerWithManufacturingBoxToMerge; Vector3 position3 = ((Component)((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(storageContainerWithManufacturingBoxToMerge)).transform.Find("Standspot")).transform.position; employeeNPC.MoveEmployeeTo(position3, null); employee.state = 50; return true; } int freeManufacturingStorageContainer = __instance.GetFreeManufacturingStorageContainer(employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageContainer >= 0) { int freeManufacturingStorageRow = __instance.GetFreeManufacturingStorageRow(freeManufacturingStorageContainer, employee.boxProductID, employee.mBoxCombinableData); if (freeManufacturingStorageRow >= 0) { ((Component)__instance.manufacturingStorageShelvesOBJ.transform.GetChild(freeManufacturingStorageContainer)).GetComponent().EmployeeUpdateArrayValuesStorage(freeManufacturingStorageRow * 2, employee.boxProductID, employee.boxNumberOfProducts, employee.mBoxCombinableData); employee.state = 46; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 45); employee.state = -1; } } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 45); employee.state = -1; } return true; } case 48: { Vector3 val2 = __instance.leftoverBoxesSpotOBJ.transform.position + new Vector3(Random.Range(-1f, 1f), 4f, Random.Range(-1f, 1f)); ((Component)GameData.Instance).GetComponent().SpawnManufacturingBoxFromEmployee(val2, employee.boxProductID, employee.boxNumberOfProducts, employee.mBoxCombinableData); employee.state = 46; return true; } case 49: { float num2 = 1.5f * (float)((Component)GameData.Instance).GetComponent().boxRecycleFactor; AchievementsManager.Instance.CmdAddAchievementPoint(2, 1); StatisticsManager instance = StatisticsManager.Instance; instance.totalBoxesRecycled++; GameData.Instance.CmdAlterFunds(num2); employee.state = 46; return true; } case 50: { int storageRowWithManufacturingBoxToMerge = __instance.GetStorageRowWithManufacturingBoxToMerge(employee.currentFreeStorageIndex, employee.boxProductID, employee.mBoxCombinableData); if (storageRowWithManufacturingBoxToMerge >= 0) { __instance.EmployeeMergeManufacturingBoxContents(employee, employee.currentFreeStorageIndex, employee.boxProductID, storageRowWithManufacturingBoxToMerge); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 45); employee.state = -1; } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 45); employee.state = -1; } break; } case 60: if (Object.op_Implicit((Object)(object)employee.closestCardboardBaler)) { employee.closestCardboardBaler.GetComponent().AuxiliarAddBoxToBaler(employee.boxProductID); UnequipBox(employee); } else { employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); employee.state = -1; } return true; } return true; default: Debug.Log((object)"Impossible employee current task case. Check logs."); return true; } employeeNPC.ClearNPCReservations(); switch (state) { default: employee.state = 0; return true; case 0: if (employee.equippedItem > 0) { __instance.DropBoxOnGround(employee); UnequipBox(employee); return true; } employeeNPC.MoveEmployeeToRestPosition(); employee.state = 1; return true; case 1: break; } } else if (EmployeeWalkSpeedPatch.IsWarpingEnabled() && !component.pathPending) { component.Warp(employeeNPC.LastDestinationSet); EmployeeWarpSound.PlayEmployeeWarpSound(employee); employee.StartWaitState(0.5f, state); employee.state = -1; return true; } return false; } private static void TryNonPrimaryJob(NPC_Info employee) { if (taskPriorities[currentTaskIndex + 1] != 0) { currentTaskIndex++; employee.taskPriority = currentTaskIndex; } } private static bool DoSecurityAreaPickUp(NPC_Manager __instance, EnumSecurityPickUp pickUpmode, GameObject employeeObj, NPC_Info employee, float stoppingDistance) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) int num = pickUpmode switch { EnumSecurityPickUp.Reduced => (int)Math.Ceiling((double)NumberExtensionMethods.ClampReturn(employee.securityLevel, 0, MaxSecurityPickUpLevel) / 2.0), EnumSecurityPickUp.Normal => NumberExtensionMethods.ClampReturn(employee.securityLevel, 0, MaxSecurityPickUpLevel), EnumSecurityPickUp.AlwaysMaxed => MaxSecurityPickUpLevel, _ => throw new NotImplementedException($"Unknown security pick up mode: {pickUpmode}"), }; int num2 = (int)Math.Ceiling((float)num / LevelsForExtraPickUp); float num3 = (float)num / (float)MaxSecurityPickUpLevel * SecurityPickUpRangeLevelMult; float num4 = 0.1f + stoppingDistance + (float)Math.Round(num3, 2); Collider[] array = (Collider[])(object)new Collider[num2]; if (Physics.OverlapSphereNonAlloc(employeeObj.transform.position, num4, array, 1 << SecurityPickUpLayer) > 0) { float num5 = 0f; Collider[] array2 = array; foreach (Collider val in array2) { if ((Object)(object)val == (Object)null) { break; } GameObject gameObject = ((Component)val).gameObject; StolenProductSpawn component = gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component) && gameObject.activeSelf) { num5 += component.productCarryingPrice; gameObject.SetActive(false); ((Component)component).transform.parent = null; gameObject.layer = 1; stolenProdPickups.Enqueue(component); employee.securityExperience++; num2--; } else { TimeLogger.Logger.LogDebug("Security area pick up found a " + $"collider in layer {SecurityPickUpLayer} that is not a " + "StolenProductSpawn: " + ((Object)((Component)val).gameObject).name, (LogCategories)134217728); } if (num2 <= 0) { break; } } if (num5 != 0f) { GameData.Instance.AlterFundsFromEmployee(num5); } return true; } return false; } [IteratorStateMachine(typeof(d__32))] private IEnumerator PickupMarkedStolenProductsLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__32(0); } private static bool TryMoveToClosestBale(NPC_Manager __instance, NPC_Info employee, GameObject employeeObj, EmployeeNPC employeeSQoL) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) GameObject closestBale = __instance.GetClosestBale(employeeObj); NavMeshHit val = default(NavMeshHit); if (Object.op_Implicit((Object)(object)closestBale) && NavMesh.SamplePosition(new Vector3(closestBale.transform.position.x, 0f, closestBale.transform.position.z), ref val, 1f, -1)) { employee.currentCardboardBale = closestBale; employeeSQoL.MoveEmployeeTo(((NavMeshHit)(ref val)).position, closestBale); employee.state = 30; return true; } return false; } private static bool GetStorageContainerWithBoxToMerge(NPC_Manager __instance, NPC_Info employee, EmployeeNPC employeeSQoL) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) StorageSlotInfo storageContainerWithBoxToMerge = ContainerSearch.GetStorageContainerWithBoxToMerge(__instance, employee.NetworkboxProductID); if (storageContainerWithBoxToMerge.ShelfFound) { LOG.TEMPDEBUG_FUNC((Func)(() => GetEmployeeTaskName(employee.taskPriority) + " #" + GetUniqueId(employee) + ": Moving to storage to merge box."), false); Vector3 position = ((Component)((Component)__instance.storageOBJ.transform.GetChild(storageContainerWithBoxToMerge.ShelfIndex)).transform.Find("Standspot")).transform.position; employeeSQoL.MoveEmployeeToStorage(position, storageContainerWithBoxToMerge); employee.state = 20; return true; } return false; } public static void MoveToBalerOrGarbageContainer(NPC_Manager __instance, GameObject employeeObj, NPC_Info employee, EmployeeNPC employeeSQoL, int cardboardTargetState, int trashTargetState, int recycleTargetState) { MoveToGarbageContainer(__instance, employeeObj, employee, employeeSQoL, cardboardTargetState, trashTargetState, recycleTargetState, useCardboardBaler: true); } public static void MoveToGarbageContainer(NPC_Manager __instance, GameObject employeeObj, NPC_Info employee, EmployeeNPC employeeSQoL, int trashTargetState, int recycleTargetState) { MoveToGarbageContainer(__instance, employeeObj, employee, employeeSQoL, -1, trashTargetState, recycleTargetState, useCardboardBaler: false); } private static void MoveToGarbageContainer(NPC_Manager __instance, GameObject employeeObj, NPC_Info employee, EmployeeNPC employeeSQoL, int cardboardTargetState, int trashTargetState, int recycleTargetState, bool useCardboardBaler) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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) string employeeTaskName = GetEmployeeTaskName(employee.taskPriority); LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Box empty, trying to recycle."), false); GameObject val = null; if (useCardboardBaler) { val = __instance.GetClosestCardboardBaler(employeeObj); } if (Object.op_Implicit((Object)(object)val)) { LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Moving to cardboard baler."), false); employee.closestCardboardBaler = val; employeeSQoL.MoveEmployeeTo(val.transform.Find("Standspot"), val); employee.state = cardboardTargetState; return; } if (__instance.closestRecyclePerk) { LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Moving to trash container with recycling perk."), false); employeeSQoL.MoveEmployeeTo(__instance.trashSpotOBJ, __instance.trashSpotOBJ); employee.state = recycleTargetState; return; } if (!__instance.employeeRecycleBoxes || __instance.interruptBoxRecycling) { LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Moving to trash container instead."), false); employeeSQoL.MoveEmployeeTo(__instance.trashSpotOBJ, __instance.trashSpotOBJ); employee.state = trashTargetState; return; } LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Moving to closest non trash recycle spot."), false); float num = Vector3.Distance(employeeObj.transform.position, __instance.recycleSpot1OBJ.transform.position); float num2 = Vector3.Distance(employeeObj.transform.position, __instance.recycleSpot2OBJ.transform.position); GameObject val2 = ((num < num2) ? __instance.recycleSpot1OBJ : __instance.recycleSpot2OBJ); employeeSQoL.MoveEmployeeTo(val2, val2); employee.state = recycleTargetState; } public static bool GetThiefTarget(NPC_Manager __instance) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (__instance.customersnpcParentOBJ.transform.childCount == 0) { return false; } int[] allowedStates = new int[2] { 0, 1 }; GameObject val = null; __instance.thievesList.Clear(); foreach (Transform item in __instance.customersnpcParentOBJ.transform) { Transform val2 = item; NPC_Info component = ((Component)val2).GetComponent(); if (component.isAThief && component.thiefFleeing && component.productsIDCarrying.Count > 0 && val2.position.z < -3f && val2.position.x > -15f && val2.position.x < 38f) { __instance.thievesList.Add(((Component)val2).gameObject); if (!component.thiefAssignedChaser) { component.thiefAssignedChaser = true; val = ((Component)val2).gameObject; break; } } } if ((Object)(object)val == (Object)null && __instance.thievesList.Count > 0) { switch (ModConfig.Instance.SecurityThiefChaseMode.Value) { case EnumSecurityEmployeeThiefChase.Disabled: val = GetRandomThief(__instance); break; case EnumSecurityEmployeeThiefChase.AllChaseButLastOne: if (GetEmployeesAssignedTo(EmployeeJob.Security, allowedStates).Any()) { val = GetRandomThief(__instance); } break; default: throw new NotImplementedException(EnumExtension.GetDescription((Enum)ModConfig.Instance.SecurityThiefChaseMode.Value)); case EnumSecurityEmployeeThiefChase.OnlyOnePerThief: break; } } if (Object.op_Implicit((Object)(object)val)) { NPC_Info closestEmployeeToTarget = GetClosestEmployeeToTarget(EmployeeJob.Security, allowedStates, val.transform); if (Object.op_Implicit((Object)(object)closestEmployeeToTarget)) { closestEmployeeToTarget.currentChasedThiefOBJ = val; closestEmployeeToTarget.state = 2; return true; } } return false; } private static NPC_Info GetClosestEmployeeToTarget(EmployeeJob employeeJob, int[] allowedStates, Transform target) { if (!Object.op_Implicit((Object)(object)NPC_Manager.Instance)) { TimeLogger.Logger.LogWarning("The NPC_Manager is null. Make sure to call this method after NPC_Manager Awake", (LogCategories)134217728); } NPC_Info closestEmployee = null; float closestDistanceSqr = float.MaxValue; GetEmployeesAssignedTo(EmployeeJob.Security, allowedStates).ForEach(delegate(Transform employeeT) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) NPC_Info component = ((Component)employeeT).GetComponent(); Vector3 val = employeeT.position - target.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < closestDistanceSqr) { closestDistanceSqr = sqrMagnitude; closestEmployee = component; } }); return closestEmployee; } private static GameObject GetRandomThief(NPC_Manager __instance) { return __instance.thievesList[Random.Range(0, __instance.thievesList.Count)]; } private static bool IsLastIdleSecurity(NPC_Info employee) { return (from t in GetEmployeesAssignedTo(EmployeeJob.Security) where (Object)(object)t != (Object)(object)((Component)employee).transform select t).All(delegate(Transform t) { NPC_Info component = ((Component)t).GetComponent(); return component.state != 0 && component.state != 1; }); } private static void EmployeeTryMergeBoxContents(NPC_Manager __instance, NPC_Info employee, EmployeeNPC employeeSQoL, int returnState) { string employeeTaskName = GetEmployeeTaskName(employee.taskPriority); if (employeeSQoL.RefreshAndCheckValidTargetedStorage(__instance, clearReservation: false, out var storageSlotInfo)) { LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Merging storage box."), false); __instance.EmployeeMergeBoxContents(employee, storageSlotInfo.ShelfIndex, storageSlotInfo.ExtraData.ProductId, storageSlotInfo.SlotIndex); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, returnState); employee.state = -1; } else { LOG.TEMPDEBUG_FUNC((Func)(() => employeeTaskName + " #" + GetUniqueId(employee) + ": Couldnt merge storage box."), false); employee.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, returnState); employee.state = -1; } } public static List GetEmployeesAssignedTo(EmployeeJob employeeJob) { return GetEmployeesAssignedTo(employeeJob, null); } public static bool HasEmployeeAssignedTo(EmployeeJob employeeJob) { return GetEmployeesAssignedTo(employeeJob).Any(); } public static int GetEmployeeCount(EmployeeJob employeeJob) { return GetEmployeesAssignedTo(employeeJob).Count; } public static List GetEmployeesAssignedTo(EmployeeJob employeeJob, int[] allowedStates) { if (!Object.op_Implicit((Object)(object)NPC_Manager.Instance)) { TimeLogger.Logger.LogWarning("The NPC_Manager is null. Make sure to call this method after NPC_Manager Awake", (LogCategories)134217728); } return ((IEnumerable)NPC_Manager.Instance.employeeParentOBJ.transform).Cast().Where(delegate(Transform t) { if (employeeJob == EmployeeJob.Any) { return true; } NPC_Info component = ((Component)t).GetComponent(); return component.taskPriority == (int)employeeJob && (allowedStates == null || allowedStates.Length == 0 || allowedStates.Contains(component.state)); }).ToList(); } private static void UnequipBox(NPC_Info npcInfo) { npcInfo.EquipNPCItem(0); npcInfo.NetworkboxProductID = 0; npcInfo.NetworkboxNumberOfProducts = 0; npcInfo.StartWaitState(ModConfig.Instance.EmployeeNextActionWait.Value, 0); npcInfo.state = -1; } private static string GetEmployeeTaskName(int taskPriority) { return taskPriority switch { 2 => "Restocker", 3 => "Storage", 4 => "Security", 5 => "Technician", 6 => "Online Order", 7 => "Manufacturing", _ => "Unknown", }; } public static string GetUniqueId(NPC_Info NPC) { return $"{((NetworkBehaviour)NPC).netId} ({NPC.NPCName})"; } private static bool IsEmployeeAtDestination(NavMeshAgent employeePathing, out float stoppingDistance) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) stoppingDistance = employeePathing.stoppingDistance; Vector3 velocity; if (EmployeeWalkSpeedPatch.IsEmployeeSpeedIncreased) { if (EmployeeWalkSpeedPatch.IsWarpingEnabled() && ((int)employeePathing.pathStatus == 2 || (int)employeePathing.pathStatus == 1)) { return false; } stoppingDistance = Math.Max(employeePathing.stoppingDistance, 1f); if (!employeePathing.pathPending && employeePathing.remainingDistance <= 5f) { if (employeePathing.remainingDistance <= stoppingDistance) { if (employeePathing.hasPath) { velocity = employeePathing.velocity; if (!(((Vector3)(ref velocity)).sqrMagnitude < EmployeeWalkSpeedPatch.WalkSpeedMultiplier * 5f)) { goto IL_0094; } } employeePathing.velocity = Vector3.zero; return true; } goto IL_0094; } goto IL_00f2; } if (!employeePathing.pathPending && employeePathing.remainingDistance <= employeePathing.stoppingDistance) { if (employeePathing.hasPath) { velocity = employeePathing.velocity; return ((Vector3)(ref velocity)).sqrMagnitude == 0f; } return true; } return false; IL_0094: if (!EmployeeWalkSpeedPatch.IsWarpingEnabled()) { employeePathing.velocity = employeePathing.desiredVelocity / (3.5f / employeePathing.remainingDistance); } goto IL_00f2; IL_00f2: return false; } } public class EmployeeWalkSpeedPatch : FullyAutoPatchedInstance { private static bool warpNotifyDone; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableEmployeeChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Employee speed while closed failed. Disabled"; public static float WalkSpeedMultiplier { get; set; } = -1f; public static bool IsEmployeeSpeedIncreased { get; private set; } public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (!IsPatchActive) { return; } WorldState.OnGameWorldChange += delegate(GameWorldEvent ev) { if (ev == GameWorldEvent.LoadingWorld) { float walkSpeedMultiplier = 1f; if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { walkSpeedMultiplier = ModConfig.Instance.ClosedStoreEmployeeWalkSpeedMultiplier.Value; } ChangeEmployeesSpeed(walkSpeedMultiplier); } }; DelayedSingleTask delayTask = new DelayedSingleTask((Action)delegate { if (WorldState.CurrentOnlineMode != GameOnlineMode.Client) { ChangeEmployeesSpeed(ModConfig.Instance.ClosedStoreEmployeeWalkSpeedMultiplier.Value); } }); ModConfig.Instance.ClosedStoreEmployeeWalkSpeedMultiplier.SettingChanged += delegate { delayTask.Start(1000); }; ModConfig.Instance.EnabledDevMode.SettingChanged += delegate { ShowWarpSpeedNotification(); }; StoreOpenStatusPatch.OnSupermarketOpenStateChanged += SupermarketOpenStateChanged; } private void ChangeEmployeesSpeed(float walkSpeedMultiplier) { WalkSpeedMultiplier = walkSpeedMultiplier; ShowWarpSpeedNotification(); if ((Object)(object)NPC_Manager.Instance != (Object)null) { NPC_Manager.Instance.UpdateEmployeeStats(); } } [HarmonyPatch(typeof(NPC_Manager), "UpdateEmployeeStats")] [HarmonyPriority(100)] [HarmonyPostfix] private static void UpdateEmployeeStatsPostfix(NPC_Manager __instance) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (WorldState.CurrentOnlineMode == GameOnlineMode.Client) { return; } foreach (Transform item in __instance.employeeParentOBJ.transform) { NavMeshAgent component = ((Component)item).GetComponent(); if (SyncVar.op_Implicit(StoreStatusNetwork.IsStoreOpenOrCustomersInsideSync)) { IsEmployeeSpeedIncreased = false; } else { float walkSpeedMultiplier = WalkSpeedMultiplier; IsEmployeeSpeedIncreased = walkSpeedMultiplier > 1f; component.speed *= walkSpeedMultiplier; component.acceleration *= 1f + walkSpeedMultiplier * 0.7f; component.angularSpeed *= 1f + walkSpeedMultiplier * 25000000f; } component.autoBraking = !IsEmployeeSpeedIncreased; } } [HarmonyPatch(typeof(NPC_Manager), "SpawnEmployeeByIndex")] [HarmonyPriority(100)] [HarmonyPostfix] private static void SpawnEmployeeByIndexPostfix(NPC_Manager __instance) { NPC_Manager.Instance.UpdateEmployeeStats(); } private static void SupermarketOpenStateChanged(bool isOpen) { if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { NPC_Manager.Instance.UpdateEmployeeStats(); } } public static bool IsWarpingEnabled() { float maxValue = BepinexConfigExtensions.GetMaxValue(((ConfigEntryBase)ModConfig.Instance.ClosedStoreEmployeeWalkSpeedMultiplier).Description.AcceptableValues); if (IsEmployeeSpeedIncreased && ModConfig.Instance.EnabledDevMode.Value) { return WalkSpeedMultiplier == maxValue; } return false; } private void ShowWarpSpeedNotification() { if (!warpNotifyDone && IsWarpingEnabled() && GameNotifications.Instance.NotificationsActive) { warpNotifyDone = true; TimeLogger.Logger.LogMessageShowInGame("SPEEEEEEDS", (LogCategories)64); } } } public class PerformanceCachingPatch : FullyAutoPatchedInstance { public class PopulateCacheOnBuilderInitialization { [CompilerGenerated] private sealed class d__0 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } PopulateMaxProductsPerRowCache(); 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(); } } [IteratorStateMachine(typeof(d__0))] [HarmonyPatch(typeof(Builder_Main), "RetrieveInitialBehaviours")] [HarmonyPostfix] public static IEnumerator WaitEndOfIEnumerable(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(0) { result = result }; } } private static readonly Dictionary<(int containerClass, int containerId, int productId), int> maxProductsPerRowCache = new Dictionary<(int, int, int), int>(); private static bool cachePopulated = false; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableEmployeeChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - AI caching patch failed. Disabled"; private static void PopulateMaxProductsPerRowCache() { if (cachePopulated) { return; } GameObject[] buildables = SMTInstances.NetworkSpawner().buildables; Data_Container val2 = default(Data_Container); foreach (GameObject val in buildables) { if ((Object)(object)val == (Object)null || !val.TryGetComponent(ref val2) || val2.GetContainerType() != 0) { continue; } ProductData[] productsData = ProductListing.Instance.productsData; foreach (ProductData val3 in productsData) { if (val3 != null) { int productID = val3.productID; int maxProductsPerRow = GetMaxProductsPerRow(val2, productID); maxProductsPerRowCache.Add((val2.containerClass, val2.containerID, productID), maxProductsPerRow); } } } cachePopulated = true; } public static int GetMaxProductsPerRowCachedThreaded(Data_Container dataContainer, int shelfProductId, int shelfIndex) { return GetMaxProductsPerRowCached(null, dataContainer, shelfProductId, shelfIndex, isThreaded: true); } public static int GetMaxProductsPerRowCached(NPC_Manager __instance, Data_Container dataContainer, int shelfProductId, int shelfIndex) { return GetMaxProductsPerRowCached(null, dataContainer, shelfProductId, shelfIndex, isThreaded: false); } public static int GetMaxProductsPerRowCached(NPC_Manager __instance, Data_Container dataContainer, int shelfProductId, int shelfIndex, bool isThreaded) { bool flag = false; int value = 0; if (cachePopulated) { flag = maxProductsPerRowCache.TryGetValue((dataContainer.containerClass, dataContainer.containerID, shelfProductId), out value); } else { TimeLogger.Logger.LogWarning("MaxProductsPerRow has been requested from the cache, but it hasnt been populated yet.", (LogCategories)1024); } if (!flag) { TimeLogger.Logger.LogWarning($"A maxProductsPerRow cache entry doesnt exist for containerID: {dataContainer.containerID} " + $"and productId: {shelfProductId}. Attempting to obtain it manually.", (LogCategories)8); if (((AutoPatchedInstanceBase)Container.Instance).IsPatchActive) { value = GetMaxProductsPerRow(dataContainer, shelfProductId); } else if ((Object)(object)__instance != (Object)null) { value = __instance.GetMaxProductsPerRow(shelfIndex, shelfProductId); } else if (isThreaded) { TimeLogger.Logger.LogWarning("This method is threaded and the amount cannot be calculated from the source Unity objects. Returning 0.", (LogCategories)8); } else { TimeLogger.Logger.LogError("The NPC_Manager instance is null and the value could not be obtained manually.", (LogCategories)8); } maxProductsPerRowCache.Add((dataContainer.containerClass, dataContainer.containerID, shelfProductId), value); } return value; } public static int GetMaxProductsPerRow(Data_Container dataContainer, int shelfProductId) { return GetMaxProductsPerRow(NPC_Manager.Instance, -1, dataContainer, shelfProductId); } private static int GetMaxProductsPerRow(NPC_Manager __instance, int shelfIndex, Data_Container dataContainer, int ProductID) { //IL_001e: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (ProductID >= ProductListing.Instance.productsData.Length) { return -1; } ProductData obj = ProductListing.Instance.productsData[ProductID]; Vector3 colliderSize = obj.colliderSize; bool isStackable = obj.isStackable; int num = Mathf.Clamp(Mathf.FloorToInt(dataContainer.shelfLength / (colliderSize.x * 1.1f)), 1, 100); int num2 = Mathf.FloorToInt(dataContainer.shelfWidth / (colliderSize.z * 1.1f)); num2 = Mathf.Clamp(num2, 1, 100); int num3 = num * num2; if (isStackable) { int num4 = Mathf.FloorToInt(dataContainer.shelfHeight / (colliderSize.y * 1.1f)); num4 = Mathf.Clamp(num4, 1, 100); num3 *= num4; } return num3; } } } namespace SuperQoLity.SuperMarket.Patches.NPC.Customer { public class CustomerCashCardPayRatio : FullyAutoPatchedInstance { public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableCustomerChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Customer card pay ratio patch failed. Disabled."; [HarmonyPatch(typeof(Data_Container), "RpcShowPaymentMethod")] [HarmonyPrefix] public static void RpcShowPaymentMethodPatch(ref int index) { bool flag = Random.Range(0, 100) < ModConfig.Instance.CustomerCardPayRatio.Value; index = (flag ? 1 : 0); } } public class NPC_CustomerNavFixer : FullyAutoPatchedInstance { [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } BeginNpcNavDetection(NPC_Manager.Instance.customersnpcParentOBJ.transform.childCount - 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 static TrappedCustomerDetection trapDetection; private static readonly float MaxCustomerVelocityForJob = 0.33f; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableCustomerChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Customer navigation fix patch failed. Disabled."; public override void OnPatchFinishedVirtual(bool IsActive) { if (IsActive) { trapDetection = new TrappedCustomerDetection(); WorldState.OnWorldLoaded += trapDetection.EnableDetection; WorldState.OnQuitOrMainMenu += trapDetection.DisableDetection; } } [IteratorStateMachine(typeof(d__9))] [HarmonyPatch(typeof(NPC_Manager), "SpawnCustomerNPC")] [HarmonyPostfix] public static IEnumerator WaitEndOfIEnumerable(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0) { result = result }; } [HarmonyPatch(typeof(NPC_Manager), "CustomerNPCControl")] [HarmonyTranspiler] private static IEnumerable CustomerDestinationSetTranspile(IEnumerable instructions, ILGenerator generator) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); MethodInfo mInfo = AccessTools.PropertySetter(typeof(NavMeshAgent), "destination"); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, mInfo)), (string)null) }).Repeat((Action)delegate(CodeMatcher c) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown c.Advance(1).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_1, (object)null) }).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate>((Action)BeginNpcNavDetection) }); }, (Action)delegate(string e) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) throw new TranspilerDefaultMsgException("No calls to 'typeof(NavMeshAgent).destination' found.Error was: " + e); }); return val.Instructions(); } [HarmonyPatch(typeof(NPC_Manager), "CustomerNPCControl")] [HarmonyTranspiler] private static IEnumerable AllowedVelocityForDestinationTranspile(IEnumerable instructions, ILGenerator generator) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); MethodInfo magnitudeGetter = AccessTools.PropertyGetter(typeof(Vector3), "sqrMagnitude"); Label? returnLabel = null; val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, magnitudeGetter)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Branches(inst, ref returnLabel)), (string)null) }); if (val.IsValid && returnLabel.HasValue) { val.Set(OpCodes.Bge, (object)returnLabel.Value).Advance(-1).Set(OpCodes.Ldc_R4, (object)MaxCustomerVelocityForJob); } else { TimeLogger.Logger.LogError("The call to property getter sqrMagnitude could not be found.", (LogCategories)134217728); } return val.Instructions(); } [HarmonyPatch(typeof(NPC_Manager), "CustomerNPCControl")] [HarmonyPrefix] public static void CustomerDestinationReachedPatch(NPC_Manager __instance, int NPCIndex) { GameObject gameObject = ((Component)__instance.customersnpcParentOBJ.transform.GetChild(NPCIndex)).gameObject; NPC_Info component = gameObject.GetComponent(); NavMeshAgent component2 = gameObject.GetComponent(); if (trapDetection.IsNavDetectionActive(component) && (!TestNavAgent(component2) || IsCustomerAtDestination(component, component2))) { trapDetection.StopNpcNavDetection(component); } } private static void BeginNpcNavDetection(int npcIndex) { try { NPC_Info component = ((Component)NPC_Manager.Instance.customersnpcParentOBJ.transform.GetChild(npcIndex)).gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.isCustomer) { trapDetection.BeginNpcNavDetection(component); } } catch (Exception ex) { TimeLogger.Logger.LogException(ex, (LogCategories)134217728); } } private static bool IsCustomerAtDestination(NPC_Info npcInfo, NavMeshAgent navAgent) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (npcInfo.state >= 0 && !navAgent.pathPending && navAgent.remainingDistance <= navAgent.stoppingDistance) { Vector3 velocity = navAgent.velocity; return ((Vector3)(ref velocity)).magnitude == 0f; } return false; } public static bool TestNavAgent(NavMeshAgent navAgent) { if (!Object.op_Implicit((Object)(object)navAgent) || !((Behaviour)navAgent).isActiveAndEnabled || !navAgent.isOnNavMesh) { return false; } return true; } } public class ReplaceCustomerUnavailableProducts : FullyAutoPatchedInstance { private static HashSet allowedProductIdList; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableCustomerChanges.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Customers ignores unlocked and unassigned products patch failed. Disabled"; public override void OnPatchFinishedVirtual(bool IsActive) { if (!IsActive) { return; } StoreOpenStatusPatch.OnSupermarketOpenStateChanged += delegate(bool IsOpen) { if (IsOpen) { allowedProductIdList = new HashSet(); GenerateAllowedShoppingProductList(); } }; } [HarmonyPatch(typeof(NPC_Manager), "GenerateCompensatedList")] [HarmonyPostfix] private static void AdjustCustomerShoppingListPatch(List __result) { RemoveNotAllowedProducts(__result); } [HarmonyPatch(typeof(NPC_Manager), "AddExtraProductsFromReverseVending")] [HarmonyPatch(typeof(NPC_Manager), "AddExtraProductsFromSeason")] [HarmonyPostfix] private static void AdjustCustomerShoppingListPatch(NPC_Info npcInfo) { RemoveNotAllowedProducts(npcInfo.productsIDToBuy); } private static void GenerateAllowedShoppingProductList() { ContainerSearchLambdas.ForEachProductShelfSlotLambda(NPC_Manager.Instance, checkNPCProdShelfTarget: false, delegate(int prodShelfIndex, int slotIndex, int productId, int quantity, Transform prodShelfObjT) { if (productId >= 0) { allowedProductIdList.Add(productId); } return ContainerSearchLambdas.LoopAction.Nothing; }); if (allowedProductIdList.Count == 0) { TimeLogger.Logger.LogWarningShowInGame("No products assigned to shelves. Customers will have the default shopping list", (LogCategories)134217728); } } private static void RemoveNotAllowedProducts(List productsIDToBuy) { if (!ModConfig.Instance.EnableShopListOnlyAssignedProducts.Value || allowedProductIdList.Count == 0) { return; } for (int i = 0; i < productsIDToBuy.Count; i++) { if (!allowedProductIdList.Contains(productsIDToBuy[i])) { productsIDToBuy[i] = allowedProductIdList.ElementAt(Random.Range(0, allowedProductIdList.Count)); } } } } } namespace SuperQoLity.SuperMarket.Patches.Misc { public class CheckoutAutoClickScanner : FullyAutoPatchedInstance { [CompilerGenerated] private sealed class d__19 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; public ProductCheckoutSpawn __instance; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__19(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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } __instance.isFinished = false; 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 LayerMask interactableMask = LayerMask.op_Implicit(-1); private FixedCapacityUniqueQueue checkoutItemQueue; private static readonly int MaxItemsQueue = 2; private float nextCheckoutProductPickTime; private float nextCheckoutProductQueueTime; private float DequeueTimeLimit; private static readonly float CheckoutProductPickInterval = 0.175f; private static readonly float CheckoutProductQueueInterval = 0.025f; private static readonly float NoCashierPermissionDelay = 0.5f; private static readonly float AllowedDequeueTimeSinceLastRaycast = 0.2f; private static readonly float NoHitDelay = CheckoutProductQueueInterval; private bool wasButtonDown; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Hold click to scan checkout products patch failed. Disabled."; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (IsPatchActive) { checkoutItemQueue = new FixedCapacityUniqueQueue(MaxItemsQueue, true); ModConfig.Instance.EnableCheckoutAutoClicker.SettingChanged += delegate { ManageState(); }; ManageState(); } } [IteratorStateMachine(typeof(d__19))] [HarmonyPatch(typeof(ProductCheckoutSpawn), "CreateProductObject")] [HarmonyPostfix] public static IEnumerator CreateProductObject(IEnumerator result, ProductCheckoutSpawn __instance) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__19(0) { result = result, __instance = __instance }; } private void ManageState() { if (ModConfig.Instance.EnableCheckoutAutoClicker.Value) { WorldState.OnFPControllerStarted += InitState; InputBehaviour.RegisterClickAction(ProcessCheckoutProductPickup, GameWorldEvent.FPControllerStarted); } else { WorldState.OnFPControllerStarted -= InitState; InputBehaviour.UnregisterClickAction(); } if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted)) { InitState(); } } private void InitState() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) SetVanillaCheckoutScanState(!ModConfig.Instance.EnableCheckoutAutoClicker.Value); if (LayerMask.op_Implicit(interactableMask) < 0) { interactableMask = SMTInstances.LocalPlayerNetwork().interactableMask; } } private static void SetVanillaCheckoutScanState(bool enable) { ChangeVanillaClickEnabled(NPC_Manager.Instance.productCheckoutPrefab, enable); ChangeClickAllSpawnProductsInScene(enable); } private static void ChangeClickAllSpawnProductsInScene(bool enable) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!WorldState.IsGameWorldAtOrAfter(GameWorldEvent.LoadingWorld)) { return; } Scene activeScene = SceneManager.GetActiveScene(); ProductCheckoutSpawn val = default(ProductCheckoutSpawn); foreach (GameObject item in from g in ((Scene)(ref activeScene)).GetRootGameObjects() where g.TryGetComponent(ref val) select g) { ChangeVanillaClickEnabled(item, enable); } } private static void ChangeVanillaClickEnabled(GameObject spawnObject, bool enable) { ((Behaviour)((IEnumerable)((Component)spawnObject.GetComponent()).GetComponents()).FirstOrDefault((Func)((PlayMakerFSM fsm) => fsm.FsmName == "Behaviour"))).enabled = enable; } public void ProcessCheckoutProductPickup(float currentTime, Player mainPlayerControl) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) int mainActionId = KeyActions.MainActionId; if (wasButtonDown && mainPlayerControl.GetButtonUp(mainActionId)) { wasButtonDown = false; ((Queue)(object)checkoutItemQueue).Clear(); nextCheckoutProductQueueTime = 0f; nextCheckoutProductPickTime = 0f; } if (nextCheckoutProductQueueTime > currentTime || !mainPlayerControl.GetButton(mainActionId)) { return; } wasButtonDown = true; nextCheckoutProductQueueTime = currentTime + NoHitDelay; RaycastHit val = default(RaycastHit); ProductCheckoutSpawn productBelt = default(ProductCheckoutSpawn); if (!((Component)FirstPersonController.Instance).GetComponent().RequestCP()) { nextCheckoutProductQueueTime = currentTime + NoCashierPermissionDelay; } else if (Physics.Raycast(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward, ref val, 4f, LayerMask.op_Implicit(interactableMask)) && ((Component)((RaycastHit)(ref val)).transform).TryGetComponent(ref productBelt)) { DequeueTimeLimit = currentTime + AllowedDequeueTimeSinceLastRaycast; CheckoutProductAimed(currentTime, productBelt); } else if (nextCheckoutProductPickTime < currentTime && ((Queue)(object)checkoutItemQueue).Count > 0) { if (DequeueTimeLimit >= currentTime) { PerformCheckoutProductClick(((Queue)(object)checkoutItemQueue).Dequeue(), currentTime); } else { ((Queue)(object)checkoutItemQueue).Clear(); } } } private void CheckoutProductAimed(float currentTime, ProductCheckoutSpawn productBelt) { ProductCheckoutSpawn val = default(ProductCheckoutSpawn); if (nextCheckoutProductPickTime < currentTime) { PerformCheckoutProductClick(productBelt, currentTime); ((Queue)(object)checkoutItemQueue).Clear(); } else if (!productBelt.isFinished && checkoutItemQueue.TryEnqueue(productBelt, ref val)) { nextCheckoutProductQueueTime = currentTime + CheckoutProductQueueInterval; } } private void PerformCheckoutProductClick(ProductCheckoutSpawn productBelt, float currentTime) { productBelt.isFinished = true; if (((NetworkBehaviour)productBelt).netId == 0) { TimeLogger.Logger.LogWarning("Attempted to scan product with netId 0. Skipping.", (LogCategories)int.MinValue); return; } productBelt.CmdAddProductValueToCheckout(); nextCheckoutProductPickTime = currentTime + CheckoutProductPickInterval; } } public class ExpandProductOrderClickArea : FullyAutoPatchedInstance { public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Increased clickable area in product order patch failed. Disabled."; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (IsPatchActive) { ManageState(); ModConfig.Instance.EnableExpandedProdOrderClickArea.SettingChanged += delegate { ManageState(); }; } } private void ManageState() { if (ModConfig.Instance.EnableExpandedProdOrderClickArea.Value) { WorldState.OnFPControllerStarted += ExpandOrderClickableArea; if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted) && IsOrderUiPrefabLoaded(out var managerBlackboard)) { ExpandOrderClickableArea(managerBlackboard); } } else { WorldState.OnFPControllerStarted -= ExpandOrderClickableArea; if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.FPControllerStarted) && IsOrderUiPrefabLoaded(out var managerBlackboard2)) { RestoreOrderClickableArea(managerBlackboard2); } } } private void ExpandOrderClickableArea() { if (!IsOrderUiPrefabLoaded(out var managerBlackboard)) { TimeLogger.Logger.LogError("ManagerBlackboard.UIShopItemPrefab should be instanced by now but its not.", (LogCategories)2048); } else { ExpandOrderClickableArea(managerBlackboard); } } private void ExpandOrderClickableArea(ManagerBlackboard managerBlackboard) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) SetButtonClickableArea(managerBlackboard, new Vector4(-175f, -5f, -3f, -50f)); GameObject gameObject = ((Component)managerBlackboard.UIShopItemPrefab.transform.Find("ContainerTypeBCK")).gameObject; ((Graphic)gameObject.GetComponent()).raycastTarget = false; ((Graphic)((Component)gameObject.transform.Find("ContainerImage")).GetComponent()).raycastTarget = false; } private void RestoreOrderClickableArea(ManagerBlackboard managerBlackboard) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) SetButtonClickableArea(managerBlackboard, Vector4.zero); } private void SetButtonClickableArea(ManagerBlackboard managerBlackboard, Vector4 padding) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) ((Graphic)((Component)managerBlackboard.UIShopItemPrefab.transform.Find("AddButton")).GetComponent()).raycastPadding = padding; } private bool IsOrderUiPrefabLoaded(out ManagerBlackboard managerBlackboard) { managerBlackboard = null; if ((Object)(object)GameData.Instance != (Object)null && ((Component)GameData.Instance).TryGetComponent(ref managerBlackboard)) { return (Object)(object)managerBlackboard.UIShopItemPrefab != (Object)null; } return false; } } public class PricingGunFixPatch : FullyAutoPatchedInstance { public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableMiscPatches.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Pricing Gun price patch failed. Disabled."; [HarmonyPatch(typeof(NPC_Manager), "CustomerNPCControl")] [HarmonyTranspiler] public static IEnumerable CustomerNPCControlTranspiler(IEnumerable instructions, ILGenerator generator) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_00dd: 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) CodeMatcher codeMatcher = new CodeMatcher(instructions, (ILGenerator)null); MethodInfo removeAtMethod = typeof(List).GetMethod("RemoveAt"); if (MoveToRemoveAt(useEnd: false).IsInvalid) { throw new TranspilerDefaultMsgException("IL assigning customer max buy price before line \"component.productsIDToBuy.RemoveAt(0);\" could not be found."); } object num3_Operand = codeMatcher.Instruction.operand; codeMatcher.MatchBack(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => inst.opcode == OpCodes.Ret), (string)null) }).MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsStloc(inst, (LocalBuilder)null)), (string)null) }); if (codeMatcher.IsInvalid) { throw new TranspilerDefaultMsgException("IL finding \"num\" productId var could not be found."); } int num = ILExtensionMethods.LocalIndex(codeMatcher.Instruction); MoveToRemoveAt(useEnd: true).MatchForward(true, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null) && inst.operand == num3_Operand), (string)null) }); if (codeMatcher.IsInvalid) { throw new TranspilerDefaultMsgException("IL loading num3 value into the stack could not be found."); } codeMatcher.SetInstructionAndAdvance(CodeInstructionNew.LoadLocal(num, false)).Insert((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate>((Func)GetRandomizedMarketPrice) }); return codeMatcher.InstructionEnumeration(); CodeMatcher MoveToRemoveAt(bool useEnd) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown return codeMatcher.MatchForward(useEnd, (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsStloc(inst, (LocalBuilder)null)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.IsLdloc(inst, (LocalBuilder)null)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => inst.opcode == OpCodes.Ldfld), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst)), (string)null), new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.Calls(inst, removeAtMethod)), (string)null) }); } } private static float GetRandomizedMarketPrice(int productID) { ProductData val = ProductListing.Instance.productsData[productID]; float num = val.basePricePerUnit * ProductListing.Instance.tierInflation[val.productTier]; if (ModConfig.Instance.EnablePriceGunFix.Value) { num = RoundPrice(num); } return num * Random.Range(2f, 2.5f); } private static float RoundPrice(float value) { return Mathf.Round(value * 100f) / 100f; } } public class SharedSavePatch : FullyAutoPatchedInstance { public override bool IsAutoPatchEnabled => Plugin.IsSolutionInDebugMode; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - TestAndDebugPatch FAILED. Disabled"; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (IsPatchActive) { InputManagerSMT.Instance.TryAddHotkey("hotkeySaveTest", (KeyCode)267, (InputState)0, HotkeyActiveContext.WorldLoaded, 1000, SaveAsClientX); } } public static async void SaveAsClientX() { LOG.TEMPWARNING("Save started", true); if ((Object)(object)NetworkManager.singleton == (Object)null) { TimeLogger.Logger.LogWarning("You can only save in a loaded world.", (LogCategories)int.MinValue); } if (SMTInstances.NetworkSpawner().isSaving) { TimeLogger.Logger.LogWarning("Saving is already in progress.", (LogCategories)int.MinValue); return; } _ = NetworkManager.singleton.mode; _ = 2; string loadedSaveFileName = FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value; string value = "StoreFile12.es3"; LOG.TEMPWARNING("CurrentFilename: " + loadedSaveFileName + " - City save name (host only) " + GetCityName(loadedSaveFileName), true); FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value = value; await SavePersistentValues(); await SavePropsCoroutine(); FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value = loadedSaveFileName; } private static string GetCityName(string loadedSaveFileName) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0019: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(Application.persistentDataPath, loadedSaveFileName); ES3Settings val = new ES3Settings((EncryptionType)1, "g#asojrtg@omos)^yq"); return new ES3File(text, val, false).Load("StoreName", (string)null); } private static async Task SavePersistentValues() { LOG.TEMPDEBUG("1. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true); PlayMakerFSM fsm = GameData.Instance.SaveOBJ.GetComponent(); fsm.FsmVariables.GetFsmBool("IsSaving").Value = true; LOG.TEMPDEBUG("2. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true); fsm.SendEvent("Send_Data"); LOG.TEMPDEBUG("3. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true); while (fsm.FsmVariables.GetFsmBool("IsSaving").Value) { LOG.TEMPDEBUG("4. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true); await Task.Delay(10); LOG.TEMPDEBUG("5. " + FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value, true); } } public static async Task SavePropsCoroutine() { NetworkSpawner instance = SMTInstances.NetworkSpawner(); instance.isSaving = true; ((Component)((Component)GameCanvas.Instance).transform.Find("SavingContainer")).gameObject.SetActive(true); await Task.Delay(500); int num = 0; string value = FsmVariables.GlobalVariables.GetFsmString("CurrentFilename").Value; string text = Application.persistentDataPath + "/" + value; LOG.TEMPWARNING("We will save props in file \"" + value + "\"", true); ES3Settings val = new ES3Settings((EncryptionType)1, "g#asojrtg@omos)^yq"); ES3.CacheFile(text, val); ES3Settings val2 = new ES3Settings(text, new Enum[1] { (Enum)(object)(Location)4 }); CultureInfo cultureInfo = new CultureInfo(Thread.CurrentThread.CurrentCulture.Name); if (cultureInfo.NumberFormat.NumberDecimalSeparator != ",") { cultureInfo.NumberFormat.NumberDecimalSeparator = ","; Thread.CurrentThread.CurrentCulture = cultureInfo; } Quaternion rotation; for (int i = 0; i < 4; i++) { GameObject gameObject = ((Component)instance.levelPropsOBJ.transform.GetChild(i)).gameObject; if (gameObject.transform.childCount != 0) { LOG.TEMPWARNING($"Saving {gameObject.transform.childCount} levelPropsOBJ objects for index {i}.", true); for (int j = 0; j < gameObject.transform.childCount; j++) { GameObject gameObject2 = ((Component)gameObject.transform.GetChild(j)).gameObject; string[] obj = new string[11] { i.ToString(), "|", gameObject2.GetComponent().containerID.ToString(), "|", gameObject2.transform.position.x.ToString(), "|", gameObject2.transform.position.y.ToString(), "|", gameObject2.transform.position.z.ToString(), "|", null }; rotation = gameObject2.transform.rotation; obj[10] = ((Quaternion)(ref rotation)).eulerAngles.y.ToString(); string text2 = string.Concat(obj); ES3.Save("propdata" + num, text2, text, val2); string text3 = "propinfoproduct" + num; int[] productInfoArray = gameObject2.GetComponent().productInfoArray; ES3.Save(text3, productInfoArray, text, val2); num++; } } } for (int k = num; (float)k < float.PositiveInfinity; k++) { string text4 = "propdata" + num; if (!ES3.KeyExists(text4, text, val2)) { break; } ES3.DeleteKey(text4, text, val2); } num = 0; int num2 = 0; GameObject gameObject3 = ((Component)instance.levelPropsOBJ.transform.GetChild(7)).gameObject; for (int l = 0; (float)l < float.PositiveInfinity; l++) { string text5 = "decopropdata" + num2; if (!ES3.KeyExists(text5, text, val2)) { break; } ES3.DeleteKey(text5, text, val2); num2++; } LOG.TEMPWARNING($"Saving {gameObject3.transform.childCount} decorative objects.", true); for (int m = 0; m < gameObject3.transform.childCount; m++) { GameObject gameObject4 = ((Component)gameObject3.transform.GetChild(m)).gameObject; string[] obj2 = new string[10] { "7|", gameObject4.GetComponent().decorationID.ToString(), "|", gameObject4.transform.position.x.ToString(), "|", gameObject4.transform.position.y.ToString(), "|", gameObject4.transform.position.z.ToString(), "|", null }; rotation = gameObject4.transform.rotation; obj2[9] = ((Quaternion)(ref rotation)).eulerAngles.y.ToString(); string text6 = string.Concat(obj2); ES3.Save("decopropdata" + num, text6, text, val2); if (gameObject4.GetComponent().decorationID == 4) { string text7 = "decopropdataextra" + num; string text8 = gameObject4.GetComponent().intValue + "|" + gameObject4.GetComponent().stringValue; ES3.Save(text7, text8, text, val2); } if (Object.op_Implicit((Object)(object)gameObject4.GetComponent())) { string text9 = "decopaintabledata" + num; string text10 = gameObject4.GetComponent().mainValue + "|" + gameObject4.GetComponent().secondaryValue; ES3.Save(text9, text10, text, val2); } num++; } ES3.StoreCachedFile(text, val); await Task.Delay(20); ((Component)((Component)GameCanvas.Instance).transform.Find("SavingContainer")).gameObject.SetActive(false); LOG.TEMPWARNING("Prop saving finished.", true); instance.isSaving = false; } } } namespace SuperQoLity.SuperMarket.Patches.Highlighting { public class HighlightStorageSlotsPatch : FullyAutoPatchedInstance { private class BoxEventsHighlighting { public static void BoxDroppedByPlayer(Transform t, CharacterSourceType charSource) { if (charSource == CharacterSourceType.LocalPlayer) { ContainerHighlightManager.ClearHighlightedContainers(clearProductIdFlag: true); } } public static void BoxEquippedOrUpdatedLocalPlayer(Transform transform, int productIndex) { ContainerHighlightManager.HighlightContainersByProduct(productIndex); } public static void BoxEquippedRemotePlayerOrEmployee(Transform charTransform, Transform boxTransform, int productIdBox, CharacterSourceType charSource) { ContainerHighlightManager.UpdateHeldBoxHighlighting(charTransform, boxTransform, productIdBox, charSource); } public static void BoxIntoStorage(Data_Container dataContainer) { ContainerHighlightManager.UpdateContainerHighlighting(((Component)dataContainer).transform, ParentContainerType.Storage); } public static void ProdShelfAssigned(Data_Container dataContainer) { ContainerHighlightManager.UpdateContainerHighlighting(((Component)dataContainer).transform, ParentContainerType.ProductDisplay); } public static void ProdShelfUnassigned(Data_Container dataContainer) { ContainerHighlightManager.UpdateContainerHighlighting(((Component)dataContainer).transform, ParentContainerType.ProductDisplay); } } private class HighlightInitialization { public static void OnShelfBuiltOrLoaded(Transform shelfTransform, ParentContainerType parentContainerType) { if (parentContainerType == ParentContainerType.Storage) { ContainerHighlightManager.AddHighlightMarkersToStorage(shelfTransform); } } public static void BoxSpawned(Transform newBox) { ContainerHighlightManager.UpdateBoxHighlight(newBox); } } private class BetterSMTRemoveHighlighting { [HarmonyPrepare] public static bool HarmonyPrepare() { if (((ExternalModHelper)BetterSMT_Helper.Instance).IsModLoadedAndEnabled) { return BetterSMT_Helper.Instance.IsVersionWithHighlighting(); } return false; } [HarmonyPatchStringTypes("BetterSMT.Patches.PlayerNetworkPatch", "ChangeEquipmentPatch")] [HarmonyBefore(new string[] { "BetterSMT" })] [HarmonyPrefix] public static bool ChangeEquipmentBetterSMTPatch(PlayerNetwork __instance, int newEquippedItem) { return false; } [HarmonyPatchStringTypes("BetterSMT.Patches.PlayerNetworkPatch", "UpdateBoxContentsPatch")] [HarmonyBefore(new string[] { "BetterSMT", "BetterSMT" })] [HarmonyPrefix] public static bool UpdateBoxContentsPatch(PlayerNetwork __instance, int productIndex) { return false; } } private class BetterSMTRemoveMarkerHighlighting { [HarmonyPrepare] private static bool HarmonyPrepare() { if (((ExternalModHelper)BetterSMT_Helper.Instance).IsModLoadedAndEnabled && BetterSMT_Helper.Instance.IsVersionWithHighlighting()) { return IsBetterSMTVersionWithMarkers(); } return false; } private static bool IsBetterSMTVersionWithMarkers() { return AssemblyUtils.GetMethodFromLoadedAssembly("BetterSMT.Patches.PlayerNetworkPatch", "BoxSpawnerPatch", true) != null; } [HarmonyPatchStringTypes("BetterSMT.Patches.PlayerNetworkPatch", "BoxSpawnerPatch")] [HarmonyPrefix] private static bool BoxSpawnerPatch(Data_Container __instance) { return false; } [HarmonyPatchStringTypes("BetterSMT.Patches.PlayerNetworkPatch", "NewBuildableConstructed")] [HarmonyPrefix] private static bool NewBuildableConstructed(NetworkSpawner __instance, int prefabID) { return false; } } private static DelayedSingleTask delayChangeColorTask; private static ContainerTypeFlags lastColorSettingsChanged; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnablePatchHighlight.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Highlight patching failed. Disabled"; public override void OnPatchFinishedVirtual(bool IsActive) { if (IsActive) { WorldState.BuildingEvents.OnShelfBuiltOrLoaded = (Action)Delegate.Combine(WorldState.BuildingEvents.OnShelfBuiltOrLoaded, new Action(HighlightInitialization.OnShelfBuiltOrLoaded)); WorldState.ContainerEvents.OnBoxSpawned = (Action)Delegate.Combine(WorldState.ContainerEvents.OnBoxSpawned, new Action(HighlightInitialization.BoxSpawned)); WorldState.ContainerEvents.OnBoxEquippedOrUpdatedLocalPlayer = (Action)Delegate.Combine(WorldState.ContainerEvents.OnBoxEquippedOrUpdatedLocalPlayer, new Action(BoxEventsHighlighting.BoxEquippedOrUpdatedLocalPlayer)); WorldState.ContainerEvents.OnBoxDroppedByPlayer = (Action)Delegate.Combine(WorldState.ContainerEvents.OnBoxDroppedByPlayer, new Action(BoxEventsHighlighting.BoxDroppedByPlayer)); WorldState.ContainerEvents.OnBoxEquippedRemotePlayerOrEmployee = (Action)Delegate.Combine(WorldState.ContainerEvents.OnBoxEquippedRemotePlayerOrEmployee, new Action(BoxEventsHighlighting.BoxEquippedRemotePlayerOrEmployee)); WorldState.ContainerEvents.OnBoxIntoStorage = (Action)Delegate.Combine(WorldState.ContainerEvents.OnBoxIntoStorage, new Action(BoxEventsHighlighting.BoxIntoStorage)); WorldState.ContainerEvents.OnProdShelfAssigned = (Action)Delegate.Combine(WorldState.ContainerEvents.OnProdShelfAssigned, new Action(BoxEventsHighlighting.ProdShelfAssigned)); WorldState.ContainerEvents.OnProdShelfUnassigned = (Action)Delegate.Combine(WorldState.ContainerEvents.OnProdShelfUnassigned, new Action(BoxEventsHighlighting.ProdShelfUnassigned)); ContainerHighlightManager.InitHighlightManager(); ModConfig instance = ModConfig.Instance; instance.HighlightVisualMode.SettingChanged += delegate { ContainerHighlightManager.UpdateHighlightMode(); }; instance.ShelfHighlightColorRGBA.SettingChanged += delegate { StartColorChangeDelay(ContainerTypeFlags.ProdShelf); }; instance.ShelfLabelHighlightColorRGBA.SettingChanged += delegate { StartColorChangeDelay(ContainerTypeFlags.ProdShelfSlot); }; instance.StorageHighlightColorRGBA.SettingChanged += delegate { StartColorChangeDelay(ContainerTypeFlags.Storage); }; instance.StorageSlotHighlightColorRGBA.SettingChanged += delegate { StartColorChangeDelay(ContainerTypeFlags.StorageSlot | ContainerTypeFlags.GroundBox); }; delayChangeColorTask = new DelayedSingleTask((Action)UpdateHighlightColors); InputManagerSMT.Instance.AddHotkeyFromConfig(instance.HotkeyToggleAimedHighlight, (InputState)0, HotkeyActiveContext.WorldLoaded, 100, ContainerHighlightManager.ToggleCrosshairInProductHighlight); InputManagerSMT.Instance.AddHotkeyFromConfig(instance.HotkeyCycleHighlightMode, (InputState)0, HotkeyActiveContext.WorldLoaded, 100, ContainerHighlightManager.ChangeToNextHighlightMode); HighlightEffect.customSorting = true; } } private static void StartColorChangeDelay(ContainerTypeFlags colorSettingsChanged) { if (WorldState.IsWorldLoaded) { if (lastColorSettingsChanged == ContainerTypeFlags.None) { lastColorSettingsChanged = colorSettingsChanged; } else { lastColorSettingsChanged |= colorSettingsChanged; } delayChangeColorTask?.Start(150); } } private static void UpdateHighlightColors() { ContainerHighlightManager.UpdateHighlightColorsFromSettings(lastColorSettingsChanged); lastColorSettingsChanged = ContainerTypeFlags.None; } } } namespace SuperQoLity.SuperMarket.Patches.EquipmentWheel { public class CameraBlockerPatch : FullyAutoPatchedInstance { private static float xPlayerRotation; private static float yCameraRotation; public override bool IsAutoPatchEnabled => RadialWheelNetwork.RadialEnabledSync.IsEnabledLocally; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Camera blocker failed. Disabled."; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (IsPatchActive) { NetworkSpawnManager.RegisterNetwork(RadialWheelNetwork.NetworkAssetId, true); RadialWheelManager.Initialize(); WorldState.PlayerEvents.OnChangeEquipment = (Action)Delegate.Combine(WorldState.PlayerEvents.OnChangeEquipment, new Action(RadialWheelManager.OnChangedEquipment)); } } [HarmonyPatch(typeof(CustomCameraController), "LateUpdate")] [HarmonyPrefix] private static void LateUpdatePatchPrefix(CustomCameraController __instance) { if (ShouldBlockCameraMovement(__instance)) { xPlayerRotation = __instance.x; yCameraRotation = __instance.y; } } [HarmonyPatch(typeof(CustomCameraController), "LateUpdate")] [HarmonyPostfix] private static void LateUpdatePatchPostfix(CustomCameraController __instance) { //IL_0022: 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) if (ShouldBlockCameraMovement(__instance)) { __instance.masterPlayerOBJ.transform.rotation = Quaternion.Euler(0f, xPlayerRotation, 0f); __instance.cinemachineOBJ.transform.localRotation = Quaternion.Euler(yCameraRotation, 0f, 0f); __instance.x = xPlayerRotation; __instance.y = yCameraRotation; } } private static bool ShouldBlockCameraMovement(CustomCameraController __instance) { if (RadialWheelManager.BlockCameraMovement && Object.op_Implicit((Object)(object)__instance.masterPlayerOBJ) && Object.op_Implicit((Object)(object)__instance.cinemachineOBJ) && !__instance.inVehicle && !__instance.isInCameraEvent) { return !__instance.IsInOptions; } return false; } } } namespace SuperQoLity.SuperMarket.Patches.Debug { public class TestAndDebugPatch : FullyAutoPatchedInstance { [Flags] private enum ActiveDebugPatches { None = 0, FasterTimePassing = 1, FasterMovingCustomers = 2, SpawnMoreEmployeesAndAutoAssign = 4, CustomerMassSpawning = 8, DifferentSizesNPC = 0x10, ExtraMaxEmployees = 0x20, CustomerNameplate = 0x40, All = -1 } [Flags] private enum ActiveDebugUtilities { None = 0, PerformanceTableLogging = 1, GetSceneComponents = 2, CheckoutProductFiller = 4, TheDuckening = 8, All = -1 } private class TimeScaleMethods : ITimeScaleMethods { private float vanillaCrouchSpeed = 4f; private float vanillaMoveSpeed = 5f; private float vanillaSprintSpeed = 10f; private float vanillaAirSpeed = 3f; private float vanillaSpeedChangeRate = 10f; private float vanillaGravity = -15f; public void ReadVanillaValues() { FirstPersonController val = SMTInstances.FirstPersonController(); vanillaCrouchSpeed = val.CrouchSpeed; vanillaMoveSpeed = val.MoveSpeed; vanillaSprintSpeed = val.SprintSpeed; vanillaAirSpeed = val.airSpeed; vanillaSpeedChangeRate = val.SpeedChangeRate; vanillaGravity = val.Gravity; } public void SetAdjustedSpeed(float timeScaleDiff) { FirstPersonController obj = SMTInstances.FirstPersonController(); obj.CrouchSpeed = vanillaCrouchSpeed * timeScaleDiff; obj.MoveSpeed = vanillaMoveSpeed * timeScaleDiff; obj.SprintSpeed = vanillaSprintSpeed * timeScaleDiff; obj.airSpeed = vanillaAirSpeed * timeScaleDiff; obj.SpeedChangeRate = vanillaSpeedChangeRate * timeScaleDiff; obj.Gravity = vanillaGravity * timeScaleDiff; } } public class ShowCustomerNameplateId { [CompilerGenerated] private sealed class d__1 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } Transform transform = NPC_Manager.Instance.customersnpcParentOBJ.transform; int num = transform.childCount - 1; GameObject gameObject = ((Component)transform.GetChild(num)).gameObject; Transform obj = gameObject.transform.Find("NameCanvas"); ((Component)obj).gameObject.SetActive(true); TextMeshProUGUI component = ((Component)obj.Find("NPCName")).GetComponent(); ((TMP_Text)component).text = ((Object)gameObject).GetInstanceID().ToString(); ((TMP_Text)component).isOverlay = true; 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(); } } [HarmonyPrepare] internal static bool IsCustomerNameplate() { return activeDebugPatches.HasFlag(ActiveDebugPatches.CustomerNameplate); } [IteratorStateMachine(typeof(d__1))] [HarmonyPatch(typeof(NPC_Manager), "SpawnCustomerNPC")] [HarmonyPostfix] public static IEnumerator ShowCustomerNameplateIdPatch(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { result = result }; } } public class FasterTimePassing { [HarmonyPrepare] internal static bool IsFasterTimePassingActive() { return activeDebugPatches.HasFlag(ActiveDebugPatches.FasterTimePassing); } [HarmonyPatch(typeof(GameData), "FixedUpdate")] [HarmonyPrefix] private static void FixedUpdate(GameData __instance) { if (__instance.isSupermarketOpen && WorldState.CurrentOnlineMode == GameOnlineMode.Host) { __instance.timeFactor = 0.025f; } } } public class FasterMovingCustomers { [CompilerGenerated] private sealed class d__1 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } if (WorldState.CurrentOnlineMode != GameOnlineMode.Host) { return false; } UpdateLastSpawnedCustomerSpeeds(); 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(); } } [HarmonyPrepare] internal static bool IsFasterCustomerActive() { return activeDebugPatches.HasFlag(ActiveDebugPatches.FasterMovingCustomers); } [IteratorStateMachine(typeof(d__1))] [HarmonyPatch(typeof(NPC_Manager), "SpawnCustomerNCP")] [HarmonyPostfix] public static IEnumerator WaitEndOfIEnumerable(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { result = result }; } public static void UpdateLastSpawnedCustomerSpeeds() { Transform transform = NPC_Manager.Instance.customersnpcParentOBJ.transform; NavMeshAgent component = ((Component)transform.GetChild(transform.childCount - 1)).gameObject.GetComponent(); component.speed = 100f; component.acceleration = float.MaxValue; component.angularSpeed = float.MaxValue; } } public class DifferentSizesNPC { [CompilerGenerated] private sealed class d__1 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } if (WorldState.CurrentOnlineMode != GameOnlineMode.Host) { return false; } UpdateLastSpawnedNPCSize(NPC_Manager.Instance.dummynpcParentOBJ, new Vector3(1.3f, 1.15f, 1.55f)); 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(); } } [HarmonyPrepare] internal static bool IsDifferentSizesNPCActive() { return activeDebugPatches.HasFlag(ActiveDebugPatches.DifferentSizesNPC); } [IteratorStateMachine(typeof(d__1))] [HarmonyPatch(typeof(NPC_Manager), "SpawnDummyNCP")] [HarmonyPostfix] public static IEnumerator WaitEndOfIEnumerable(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(0) { result = result }; } [HarmonyPatch(typeof(NPC_Manager), "GenerateCompensatedList")] [HarmonyPostfix] public static void GenerateCompensatedListCustomerPatch(int NPCID) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) UpdateLastSpawnedNPCSize(NPC_Manager.Instance.customersnpcParentOBJ, new Vector3(0.45f, 0.35f, 0.55f)); } [HarmonyPatch(typeof(NPC_Manager), "SetHiredEmployeesNumber")] [HarmonyPostfix] public static void SpawnEmployeeByIndexPostfix() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { UpdateLastSpawnedNPCSize(NPC_Manager.Instance.employeeParentOBJ, new Vector3(13f, 15f, 13f)); } } public static async void UpdateLastSpawnedNPCSize(GameObject obj, Vector3 size) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Transform transform = obj.transform; Transform npcNew = transform.GetChild(transform.childCount - 1); while (npcNew.childCount < 7) { await Task.Delay(100); } npcNew.GetChild(npcNew.childCount - 1).localScale = size; } } public class SpawnMoreEmployeesAndAutoAssign { [CompilerGenerated] private sealed class d__4 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator result; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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; break; case 1: <>1__state = -1; break; } if (result.MoveNext()) { <>2__current = result.Current; <>1__state = 1; return true; } Transform transform = NPC_Manager.Instance.employeeParentOBJ.transform; ((Component)transform.GetChild(transform.childCount - 1)).gameObject.GetComponent().taskPriority = (int)employeeAssigment; 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(); } } internal static bool IsAutoAssignAllEmployeesActive = activeDebugPatches.HasFlag(ActiveDebugPatches.SpawnMoreEmployeesAndAutoAssign); internal static EmployeeJob employeeAssigment = EmployeeJob.Restocker; internal static int TotalNumberEmployeesTarget = 30; public static void SpawnMoreEmployeesAndAutoAssignEvent(GameWorldEvent gameWorldEvent) { if (gameWorldEvent != GameWorldEvent.WorldLoaded || WorldState.CurrentOnlineMode != GameOnlineMode.Host) { return; } int num = NPC_Manager.Instance.hiredEmployeesData.Length; Array.Resize(ref NPC_Manager.Instance.hiredEmployeesData, TotalNumberEmployeesTarget); Array.Resize(ref NPC_Manager.Instance.employeesArray, TotalNumberEmployeesTarget); int num2 = 0; for (int i = num; i < TotalNumberEmployeesTarget; i++) { NPC_Manager.Instance.hiredEmployeesData[i] = NPC_Manager.Instance.hiredEmployeesData[num2]; if (++num2 >= num) { num2 = 0; } NPC_Manager.Instance.SpawnEmployeeByIndex(i); } int childCount = NPC_Manager.Instance.employeeParentOBJ.transform.childCount; NPC_Manager.Instance.priorityArray = Enumerable.Repeat((int)employeeAssigment, childCount).ToArray(); NPC_Manager.Instance.AssignEmployeesPriorities(); } [IteratorStateMachine(typeof(d__4))] public static IEnumerator WaitEndOfIEnumerable(IEnumerator result) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(0) { result = result }; } } public class CustomerMassSpawning { [HarmonyPrepare] internal static bool IsCustomerMassSpawningActive() { return activeDebugPatches.HasFlag(ActiveDebugPatches.CustomerMassSpawning); } [HarmonyPatch(typeof(GameData), "Update")] [HarmonyPostfix] private static void UpdatePatch(GameData __instance) { if (!WorldState.IsWorldLoaded || WorldState.CurrentOnlineMode != GameOnlineMode.Host) { return; } bool flag = false; int num = 0; if (AuxUtils.IsKeypressed((KeyCode)106)) { flag = true; num = 25; } if (AuxUtils.IsKeypressed((KeyCode)107)) { flag = true; num = 100; } if (AuxUtils.IsKeypressed((KeyCode)108)) { flag = true; num = 500; } if (!flag) { return; } for (int i = 0; i < num; i++) { IEnumerator enumerator = NPC_Manager.Instance.SpawnCustomerNPC(); while (enumerator.MoveNext()) { } } TimeLogger.Logger.LogWarning($"Total customers on map: {NPC_Manager.Instance.customersnpcParentOBJ.transform.childCount}", (LogCategories)1); } } public class IncreaseMaxEmployees { [HarmonyPrepare] internal static bool IsExtraEmployeesActive() { return activeDebugPatches.HasFlag(ActiveDebugPatches.ExtraMaxEmployees); } [HarmonyPatch(typeof(UpgradesManager), "OnStartClient")] [HarmonyPrefix] public static void AddExtraEmployeesOnLoad(UpgradesManager __instance) { NPC_Manager instance = NPC_Manager.Instance; instance.maxEmployees++; } } public static class ComponentLogger { private static Dictionary dict = new Dictionary(); public static async void GetActiveComponentsInScene(Scene newActiveScene) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!((Scene)(ref newActiveScene)).name.ToLower().Contains("main")) { return; } while (true) { AddNewMonoBehavioursFromActiveScene(); if (WorldState.IsWorldLoaded) { break; } await Task.Delay(2); } StringBuilder sb = new StringBuilder(); CollectionExtensions.Do>((IEnumerable>)dict.OrderBy((KeyValuePair x) => x.Value), (Action>)delegate(KeyValuePair p) { sb.Append(((object)p.Key).ToString()); sb.Append(" -- "); sb.AppendLine(p.Value.ToString("HH:mm:ss.fff")); }); LOG.TEMPWARNING(sb.ToString(), true); } public static void AddNewMonoBehavioursFromActiveScene() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) DateTime now = DateTime.Now; Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); for (int i = 0; i < rootGameObjects.Length; i++) { MonoBehaviour[] componentsInChildren = rootGameObjects[i].GetComponentsInChildren(true); foreach (MonoBehaviour key in componentsInChildren) { if (!dict.ContainsKey(key)) { dict.Add(key, now); } } } } } public static class CheckoutProductFiller { private static readonly float SpawnInterval = 0.15f; private static readonly int TotalProductLimit = 16; private static readonly List productsIDInCheckout = new List(); private static float timeFill; private static bool loopActive = false; public static async void StartProductSpawnLoop() { if ((Object)(object)NPC_Manager.Instance == (Object)null || Object.op_Implicit((Object)(object)NPC_Manager.Instance.checkoutOBJ)) { WorldState.OnQuitOrMainMenu += delegate { loopActive = false; }; } loopActive = true; while (loopActive && (Object)(object)NPC_Manager.Instance != (Object)null && (Object)(object)NPC_Manager.Instance.checkoutOBJ != (Object)null && NPC_Manager.Instance.checkoutOBJ.transform.childCount > 0) { PlaceProductOnBelt(); await UniTask.Delay(1, false, (PlayerLoopTiming)8, default(CancellationToken), false); } } public static void PlaceProductOnBelt() { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) Transform child = NPC_Manager.Instance.checkoutOBJ.transform.GetChild(0); if (timeFill > Time.time || ((Component)child).GetComponent().NetworkproductsLeft > TotalProductLimit) { return; } timeFill = Time.time + SpawnInterval; Data_Container component = ((Component)child).GetComponent(); int networkproductsLeft = component.NetworkproductsLeft; component.NetworkproductsLeft = networkproductsLeft + 1; int num = Random.Range(1, 50); GameObject val = Object.Instantiate(NPC_Manager.Instance.productCheckoutPrefab); ProductCheckoutSpawn component2 = val.GetComponent(); component2.NetworkproductID = num; component2.NetworkcheckoutOBJ = ((Component)child).gameObject; component2.NetworkproductCarryingPrice = 10f; component2.internalDataContainerListIndex = productsIDInCheckout.Count; productsIDInCheckout.Add(num); int num2 = 0; float num3 = 0f; float num4 = 0f; foreach (int item in productsIDInCheckout) { float num5 = ((!ProductListing.Instance.productsData[item].hasTrueCollider) ? ProductListing.Instance.productsData[item].productPrefab.GetComponent().size.x : ProductListing.Instance.productsData[item].trueColliderSize.x); if (productsIDInCheckout.Count == 1) { num3 = num5 / 2f; break; } num3 += num5 / 2f + num4 / 2f + 0.01f; if (num3 + num5 / 2f > 0.5f) { num2++; num3 = num5 / 2f; if (num2 > 6) { num2 = 0; } } num4 = num5; } val.transform.position = ((Component)((Component)child).transform.Find("CheckoutItemPosition")).transform.TransformPoint(new Vector3(num3, 0f, (float)num2 * 0.15f)); val.transform.rotation = child.rotation; ((Component)child).GetComponent().internalProductListForEmployees.Add(val); NetworkServer.Spawn(val, (NetworkConnection)null); } } public static class TheDuckening { private static readonly string[] duckPrefabSufixes = new string[15] { "Black", "Blue", "Cyan", "GreenDark", "GreenNeon", "LightPurple", "Orange", "Pink", "Pond", "Purple", "Red", "RedEye", "White", "Yellow", "YinYang" }; private static AssetBundleElement bundleElement; public static void LoadDuck() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0134: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = default(RaycastHit); if (!Physics.Raycast(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward, ref val, 100f, 1)) { return; } if (bundleElement == null) { bundleElement = new AssetBundleElement(typeof(Plugin), "Assets\\Debug\\rubberducks"); } string text = "Snowconesolid Assets/Super Rubber Duck Pack/Rubber Duck PREFABS/RubberDuck_"; string text2 = duckPrefabSufixes[Random.Range(0, duckPrefabSufixes.Length)]; GameObject val2 = default(GameObject); if (bundleElement.TryLoadNewPrefabInstance(text + text2, ref val2)) { ((Renderer)val2.GetComponent()).material.shader = ShaderUtils.SMT_Shader.Value; val2.transform.SetParent(((Component)SMTInstances.GameDataManager()).transform); val2.transform.position = ((RaycastHit)(ref val)).point; float num = Random.Range(0.15f, 1f); val2.transform.localScale = new Vector3(num, num, num); RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(val2.transform.position, Vector3.down, ref val3, 5f, 1)) { Transform transform = val2.transform; transform.position += new Vector3(0f, ((RaycastHit)(ref val3)).point.y + 0.1f, 0f); } val2.transform.Rotate(0f, 0f, (float)Random.Range(0, 360)); } } } public static class BoxStorageRemoval { public static void DeleteBoxesFromStorage() { ContainerSearchLambdas.ForEachStorageSlotLambda(NPC_Manager.Instance, checkNPCStorageTarget: true, skipEmptyBoxes: false, delegate(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT) { ((Component)storageObjT).GetComponent().EmployeeUpdateArrayValuesStorage(slotIndex * 2, -1, -1); return ContainerSearchLambdas.LoopAction.Nothing; }); } } private static ActiveDebugPatches activeDebugPatches; private static ActiveDebugUtilities activeDebugUtilities; public override bool IsAutoPatchEnabled => Plugin.IsSolutionInDebugMode; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - TestAndDebugPatch FAILED. Disabled"; public override void OnPatchFinishedVirtual(bool IsPatchActive) { if (!IsPatchActive) { return; } if (activeDebugUtilities == ActiveDebugUtilities.PerformanceTableLogging) { StartPerformanceTableLogging(); } if (SpawnMoreEmployeesAndAutoAssign.IsAutoAssignAllEmployeesActive) { WorldState.OnGameWorldChange += SpawnMoreEmployeesAndAutoAssign.SpawnMoreEmployeesAndAutoAssignEvent; } if (activeDebugUtilities == ActiveDebugUtilities.GetSceneComponents) { SceneManager.activeSceneChanged += delegate(Scene _, Scene newActiveScene) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) ComponentLogger.GetActiveComponentsInScene(newActiveScene); }; } if (activeDebugUtilities == ActiveDebugUtilities.CheckoutProductFiller) { WorldState.OnWorldLoaded += CheckoutProductFiller.StartProductSpawnLoop; } if (activeDebugUtilities == ActiveDebugUtilities.TheDuckening) { WorldState.OnWorldLoaded += delegate { InputManagerSMT.Instance.TryAddHotkey("PlaceDuck", (KeyCode)325, (InputState)2, HotkeyActiveContext.WorldLoaded, 90, delegate { TheDuckening.LoadDuck(); }); }; WorldState.OnQuitOrMainMenu += delegate { ((InputDetection)InputManagerSMT.Instance).RemoveHotkey("PlaceDuck"); }; } WorldState.OnWorldLoaded += delegate { if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { TimeScaleDebug.Initialize(UnityObjectExtensions.GameObject((Component)(object)SMTInstances.FirstPersonController()), (KeyCode[])null, 1f, 0.002f, 50f, 100, 0.3f, (float[])null, (PreprocessMessageFunc)null, (Func)(() => ModConfig.Instance.EnabledDevMode.Value), true); } }; } public static async Task MovePlayerTo(Vector3 position, Vector2 lookRotation) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) FirstPersonController fpc = SMTInstances.FirstPersonController(); CustomCameraController ccc = SMTInstances.GetCustomCameraController(); if (!Object.op_Implicit((Object)(object)fpc) || !Object.op_Implicit((Object)(object)ccc)) { TimeLogger.Logger.LogDebug("FirstPersonController or CustomCameraController have not awaken yet", (LogCategories)int.MinValue); } fpc.isTeleporting = true; await UniTask.DelayFrame(1, (PlayerLoopTiming)4, default(CancellationToken), false); ((Component)GameObject.Find("LocalGamePlayer").GetComponent()).transform.position = position; ccc.x = lookRotation.x; ccc.y = lookRotation.y; await UniTask.DelayFrame(1, (PlayerLoopTiming)4, default(CancellationToken), false); fpc.isTeleporting = false; } public static void DeleteAllFSM() { PlayMakerFSM[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { Object.DestroyImmediate((Object)(object)array[i]); } } private static void RotateShelfs() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) foreach (Transform item in NPC_Manager.Instance.shelvesOBJ.transform) { Transform val = item; val.position += new Vector3(0f, Random.Range(-0.5f, 0.5f), Random.Range(-0.08f, 0.08f)); val.localScale = new Vector3(Random.Range(0.5f, 1.4f), Random.Range(0.5f, 1.4f), Random.Range(0.5f, 1.4f)); val.rotation = Quaternion.Euler(val.rotation.x + Random.Range(0f, 8f), val.rotation.y + Random.Range(0f, 17f), val.rotation.z + Random.Range(0f, 4f)); } } public async void StartPerformanceTableLogging() { await PerformanceTableLoggingMethods.StartLogPerformanceTableNewThread(10000); } public void SpawnDroppedStolenProducts() { //IL_004a: 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_0077: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 100; i++) { GameObject obj = Object.Instantiate(((Component)NPC_Manager.Instance.employeeParentOBJ.transform.GetChild(0)).GetComponent().stolenProductPrefab, NPC_Manager.Instance.droppedProductsParentOBJ.transform); obj.transform.position = ((Component)FirstPersonController.Instance).transform.position + new Vector3(Random.Range(-0.3f, 0.3f), 0f, Random.Range(-0.3f, 0.3f)); obj.GetComponent().NetworkproductID = Random.Range(1, 300); obj.GetComponent().NetworkproductCarryingPrice = 1f; NetworkServer.Spawn(obj, (NetworkConnection)null); } } public static void FillAllStorageSlotsWithBoxes() { ContainerSearchLambdas.ForEachStorageSlotLambda(NPC_Manager.Instance, checkNPCStorageTarget: false, skipEmptyBoxes: false, delegate(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT) { ((Component)storageObjT).GetComponent().CmdUpdateArrayValuesStorage(slotIndex, 1, 20); return ContainerSearchLambdas.LoopAction.Nothing; }); } private void CatWaitState() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) RandomWait val = ActionHelpers.GetGameObjectFsm(GameObject.Find("TheCoolRoom/Cats/Cat_NoAlpha_C3/Cat_1"), "Behaviour").FsmStates.Where(delegate(FsmState state) { FsmStateAction[] actions = state.Actions; return (actions == null || actions.Any()) && ((object)state.Actions[0]).GetType() == typeof(RandomWait); }).Select((Func)((FsmState state) => (RandomWait)state.Actions[0])).FirstOrDefault(); if (val != null) { AccessTools.Field(typeof(RandomWait), "time").SetValue(val, float.MinValue); float num2 = (new FsmFloat().Value = 5f); FsmFloat value = FsmFloat.op_Implicit(num2); AccessTools.Field(typeof(RandomWait), "min").SetValue(val, value); AccessTools.Field(typeof(RandomWait), "max").SetValue(val, value); } } } } namespace SuperQoLity.SuperMarket.Patches.Building { public class GenericBuildPatches : FullyAutoPatchedInstance { public static readonly int VanillaPropLoadLimit = 5000; public static readonly int NewPropLoadLimit = 100000; public override bool IsAutoPatchEnabled => ModConfig.Instance.EnableBuildPatches.Value; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Generic building patches failed. Disabled."; [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyTranspiler] public static IEnumerable LoadSpawnIncreased(IEnumerable instructions, ILGenerator generator) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (!ModConfig.Instance.EnableIncreasedPropLoadLimits.Value) { return instructions; } CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction inst) => CodeInstructionExtensions.LoadsConstant(inst) && inst.operand is int num && num == VanillaPropLoadLimit), (string)null) }).Repeat((Action)delegate(CodeMatcher c) { c.SetOperandAndAdvance((object)NewPropLoadLimit); }, (Action)delegate(string e) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) throw new TranspilerDefaultMsgException("Vanilla buildable limiter not found. Its possible that the developer fixed this issue and this patch is not needed anymore. Error was: " + e); }); return val.Instructions(); } } } namespace SuperQoLity.SuperMarket.Patches.BroomShotgun { public class BroomShotgunPatch : FullyAutoPatchedInstance { public static readonly Vector3 BroomAimLocalPos = new Vector3(0.2f, 0.25f, -1f); public static readonly Quaternion BroomAimLocalRotation = Quaternion.Euler(Vector3.zero); private static WeaponManager shotgunManager; private static bool pNetworkPrefabModded; public override bool IsAutoPatchEnabled => BroomShotgunNetwork.ShotgunModuleEnabledSync.IsEnabledLocally; public override string ErrorMessageOnAutoPatchFail { get; protected set; } = "SuperQoLity - Broom Shotgun patching failed. Disabled"; public override void OnPatchFinishedVirtual(bool IsActive) { if (!IsActive) { return; } NetworkSpawnManager.RegisterNetwork(BroomShotgunNetwork.NetworkAssetId, false); InputManagerSMT.Instance.AddHotkeyFromConfig(ModConfig.Instance.BroomShotgunModeHotkey, (InputState)0, HotkeyActiveContext.WorldLoadedNotPaused, delegate { shotgunManager?.ToggleShotgunMode(); }); InputManagerSMT.Instance.TryAddHotkey("broomShotgunShoot", (KeyCode)323, (InputState)0, HotkeyActiveContext.CanShoot, 150, delegate { shotgunManager?.LocalPlayerFire(); }); WorldState.OnFPControllerStarted += delegate { shotgunManager = new WeaponManager(); shotgunManager.InitializeShotgunData(); }; WorldState.PlayerEvents.OnChangeEquipment = (Action)Delegate.Combine(WorldState.PlayerEvents.OnChangeEquipment, new Action(ChangedEquipment)); WorldState.OnQuitOrMainMenu += delegate { if (shotgunManager != null) { shotgunManager.LeaveShotgunAimMode(); shotgunManager.Destroy(); shotgunManager = null; } }; NetworkSpawnManager.OnBeforeObjectSpawn += OnBeforeSpawn; TaskExtensionMethods.FireAndForget(WeaponAudioSystem.LoadSoundFiles(), (LogCategories)536870912); } private void ChangedEquipment(PlayerNetwork __instance, Transform previousEquipped, Transform newEquipped, int previousIndex, int newIndex, bool isLocalPlayer) { if (shotgunManager != null && isLocalPlayer && newIndex != 3) { shotgunManager.LeaveShotgunAimMode(); } } private static void OnBeforeSpawn() { if (!pNetworkPrefabModded) { PlayerNetwork val = Resources.FindObjectsOfTypeAll().FirstOrDefault(); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogError("The base PlayerNetwork object couldnt be found. This will break the broom shotgun module.", (LogCategories)int.MinValue); return; } ((Component)val).gameObject.AddComponent(); WeaponAudioSystem.AddAudioSourceComponents(((Component)val).gameObject); pNetworkPrefabModded = true; } } [HarmonyPatch(typeof(PlayerSyncCharacter), "LateUpdate")] [HarmonyTranspiler] public static IEnumerable PlayerSyncCharacterTranspiler(IEnumerable instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, generator); val.MatchForward(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Switch, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ret, (object)null, (string)null) }); if (val.IsInvalid) { throw new TranspilerDefaultMsgException("Couldnt find the Switch + Ret IL."); } Label label = default(Label); val.Advance(-3).CreateLabel(ref label).InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstructionNew.LoadArgument(0, false) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstruction.LoadField(typeof(PlayerSyncCharacter), "pNetwork", false) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate<<>f__AnonymousDelegate0>((<>f__AnonymousDelegate0)WeaponManager.IsBroomEquipped) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Brfalse_S, (object)label) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { CodeInstructionNew.LoadArgument(0, false) }) .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { Transpilers.EmitDelegate>((Action)CustomAnimationLogic) }) .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ret, (object)null) }); return val.InstructionEnumeration(); } private static void CustomAnimationLogic(PlayerSyncCharacter __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) if (!((SyncVar)(object)BroomShotgunNetwork.ShotgunModuleEnabledSync).Value) { return; } PlayerNetwork pNetwork = __instance.pNetwork; if (shotgunManager != null && Object.op_Implicit((Object)(object)pNetwork) && pNetwork.equippedItem == 3) { bool flag = false; bool flag2; if (((NetworkBehaviour)pNetwork).isLocalPlayer) { ShotgunStatus localShotgunStatus = WeaponManager.LocalShotgunStatus; flag2 = localShotgunStatus == ShotgunStatus.EquipReady || localShotgunStatus == ShotgunStatus.IdleCooldown; flag = localShotgunStatus == ShotgunStatus.FireAnimation; } else { flag2 = WeaponManager.IsPlayerInShotgunmode(((Component)pNetwork).GetComponent()); } if (flag2) { pNetwork.instantiatedOBJ.transform.localPosition = BroomAimLocalPos; pNetwork.instantiatedOBJ.transform.localRotation = BroomAimLocalRotation; } else if (flag) { pNetwork.instantiatedOBJ.transform.localRotation = BroomAimLocalRotation; } if (!Object.op_Implicit((Object)(object)__instance.rightHandDestinationOBJ) && Object.op_Implicit((Object)(object)pNetwork.instantiatedOBJ) && Object.op_Implicit((Object)(object)pNetwork.instantiatedOBJ.transform.Find("RightHandIK"))) { __instance.rightHandDestinationOBJ = pNetwork.instantiatedOBJ.transform.Find("RightHandIK"); ((RigConstraint>)(object)__instance.rightHandConstraint).weight = 1f; } __instance.rightHandOBJ.position = __instance.rightHandDestinationOBJ.position; __instance.rightHandOBJ.rotation = __instance.rightHandDestinationOBJ.rotation; ((Component)__instance.rightHandOBJ).transform.localRotation = Quaternion.Euler(90f, 45f, 70f); } } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons { public enum ShotgunStatus { Unequipped, EquipAnimation, EquipReady, FireAnimation, IdleCooldown, None } public class WeaponManager { public const string WeaponsAssetsBundlePath = "Assets\\Weapon"; private static WeaponManager instance; private static readonly float VanillaGlobalInteractionRange = 2.5f; private static CustomCameraController customCamControl; private PlayerNetwork playerNetwork; private readonly WeaponLogic weaponLogic; private readonly WeaponAudioSystem audioSystem; private readonly WeaponAnimationSystem animationSystem; private float nextShotAvailableTime; private FsmFloat interactionDistanceFSM; public static ShotgunStatus LocalShotgunStatus { get { if (!WorldState.IsWorldLoaded) { return ShotgunStatus.None; } return SyncVar.op_Implicit(BroomShotgunNetwork.LocalInstance.ShotgunCurrentStatus); } private set { BroomShotgunNetwork.LocalInstance.ShotgunCurrentStatus.Value = value; } } public WeaponManager() { customCamControl = null; instance = this; weaponLogic = new WeaponLogic(); audioSystem = new WeaponAudioSystem(); animationSystem = new WeaponAnimationSystem(); TargetObjectResolver.ResetCache(); } public static bool IsPlayerInShotgunmode(BroomShotgunNetwork playerShotgunNetwork) { if (IsBroomEquipped(((Component)playerShotgunNetwork).GetComponent()) && SyncVar.op_Implicit(playerShotgunNetwork.ShotgunCurrentStatus) != ShotgunStatus.None) { return SyncVar.op_Implicit(playerShotgunNetwork.ShotgunCurrentStatus) != ShotgunStatus.Unequipped; } return false; } public static bool CanUseWeapon() { if (!SyncVarSetting.op_Implicit((SyncVarSetting)(object)BroomShotgunNetwork.ShotgunModuleEnabledSync) || !GetCameraController()) { return false; } if (!customCamControl.inEmoteEvent) { return !customCamControl.IsInOptions; } return false; } public static bool CanAimWeapon() { if (!customCamControl.isInCameraEvent) { return !customCamControl.inVehicle; } return false; } private static bool GetCameraController() { if (!Object.op_Implicit((Object)(object)customCamControl)) { Camera obj = UnityObjectExtensions.NullableObject(Camera.main); customCamControl = ((obj != null) ? ((Component)obj).GetComponent() : null); } return Object.op_Implicit((Object)(object)customCamControl); } public static bool IsBroomEquipped(PlayerNetwork pNetwork = null) { return (pNetwork ?? SMTInstances.LocalPlayerNetwork()).equippedItem == 3; } public void Destroy() { LocalShotgunStatus = ShotgunStatus.None; WorldState.OnGamePauseChanged = (Action)Delegate.Remove(WorldState.OnGamePauseChanged, new Action(OnGamePauseChanged)); weaponLogic.Destroy(); } public void InitializeShotgunData() { LocalShotgunStatus = ShotgunStatus.Unequipped; GameObject gameObject = ((Component)SMTInstances.FirstPersonController()).gameObject; audioSystem.Initialize(gameObject); animationSystem.Initialize(gameObject); interactionDistanceFSM = GetGlobalInteractionDistanceFloat(); WorldState.OnGamePauseChanged = (Action)Delegate.Combine(WorldState.OnGamePauseChanged, new Action(OnGamePauseChanged)); RemoveBaseCollidersRaycast(); } private void RemoveBaseCollidersRaycast() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) GameObject val = GameObject.Find("Level_Exterior/Colliders"); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogError("The base collider object couldnt be found. Shotgun pellets will stop at the invisible wall.", (LogCategories)int.MinValue); return; } foreach (Transform item in val.transform) { ((Component)item).gameObject.layer = 2; } } private FsmFloat GetGlobalInteractionDistanceFloat() { FirstPersonController obj = UnityObjectExtensions.NullableObject(SMTInstances.FirstPersonController()); object obj2; if (obj == null) { obj2 = null; } else { Transform obj3 = UnityObjectExtensions.NullableObject(((Component)obj).transform.Find("ExtraLocalBehaviours")); obj2 = ((obj3 != null) ? ((Component)obj3).GetComponents() : null); } PlayMakerFSM[] array = (PlayMakerFSM[])obj2; if (array != null && array.Length != 0) { PlayMakerFSM[] array2 = array; foreach (PlayMakerFSM val in array2) { if (val.FsmName == "Interact_behaviour") { return val.FsmVariables.FindFsmFloat("InteractDistance"); } } } return null; } private void OnGamePauseChanged(bool isPaused, bool isMainMenuOpen) { if (isPaused) { audioSystem.SetPlaybackState(SoundBite.All, AudioAction.Pause); } else { audioSystem.SetPlaybackState(SoundBite.All, AudioAction.UnPause); } } public void ToggleShotgunMode() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 if (playerNetwork == null) { playerNetwork = SMTInstances.LocalPlayerNetwork(); } if (!Object.op_Implicit((Object)(object)playerNetwork) || !CanUseWeapon()) { if (LocalShotgunStatus == ShotgunStatus.Unequipped || LocalShotgunStatus == ShotgunStatus.None) { if (IsBroomEquipped(playerNetwork) && WorldState.CurrentOnlineMode == GameOnlineMode.Client && (int)BroomShotgunNetwork.ShotgunModuleEnabledSync.Status == 1) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "Broom shotgun is disabled. Host does not have SuperQoLity or this feature enabled", true); } } else { LeaveShotgunAimMode(); } } else if (IsBroomEquipped(playerNetwork) && LocalShotgunStatus == ShotgunStatus.Unequipped) { if (HostPermissions.HasPermission(PlayerPermissionsEnum.Security)) { EnterShotgunAimMode(); } } else { LeaveShotgunAimMode(); } } private void EnterShotgunAimMode() { if (CanUseWeapon() && CanAimWeapon()) { audioSystem.SetPlaybackState(SoundBite.Equip, AudioAction.Play); LocalShotgunStatus = ShotgunStatus.EquipAnimation; animationSystem.StartShotgunAimAnimation(playerNetwork, delegate { LocalShotgunStatus = ShotgunStatus.EquipReady; }); if (interactionDistanceFSM != null) { interactionDistanceFSM.Value = 0f; } } } public void LeaveShotgunAimMode() { if (LocalShotgunStatus != 0) { LocalShotgunStatus = ShotgunStatus.Unequipped; if (interactionDistanceFSM != null) { interactionDistanceFSM.Value = VanillaGlobalInteractionRange; } animationSystem.CancelAnimations(); audioSystem.SetPlaybackState(SoundBite.All, AudioAction.Stop); } } public void LocalPlayerFire() { if (!CanUseWeapon() || !HostPermissions.HasPermission(PlayerPermissionsEnum.Security)) { return; } if (LocalShotgunStatus == ShotgunStatus.IdleCooldown && nextShotAvailableTime <= Time.time) { LocalShotgunStatus = ShotgunStatus.EquipReady; } if (LocalShotgunStatus == ShotgunStatus.EquipReady) { LocalShotgunStatus = ShotgunStatus.FireAnimation; nextShotAvailableTime = Time.time + WeaponLogic.ShotgunDefinition.RoundsPerSecond; weaponLogic.BeginLocalPlayerFire(out var broomObj); audioSystem.SetPlaybackState(SoundBite.Shoot, AudioAction.Play); animationSystem.StartShotgunRecoilAnimation(broomObj, delegate { LocalShotgunStatus = ShotgunStatus.IdleCooldown; audioSystem.SetPlaybackState(SoundBite.Pump, AudioAction.Play); animationSystem.SpawnShotgunShell(playerNetwork); }); } } public static void RemotePlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetDataArray) { //IL_0042: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_009e: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_008e: Unknown result type (might be due to invalid IL or missing references) if (!TargetObjectResolver.FindTargetObjectByNetid(playerSourceNetid, SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Helpers.TargetType.Player, out var targetObj)) { return; } PlayerNetwork component = ((Component)targetObj).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { TimeLogger.Logger.LogError($"The GameObject {component} does not " + "contain a PlayerNetwork component", (LogCategories)int.MinValue); return; } Vector3 endPoint2 = endPoint; if (fireNetDataArray.Length == 1) { if (TargetObjectResolver.GetTargetAdjustedPosition(fireNetDataArray[0], out var position)) { endPoint2 = position; } } else if (fireNetDataArray.Length > 1) { Vector3 val = Vector3.zero; for (int i = 0; i < fireNetDataArray.Length; i++) { if (TargetObjectResolver.GetTargetAdjustedPosition(fireNetDataArray[i], out var position2)) { val += position2; } } endPoint2 = val / (float)fireNetDataArray.Length; } instance.weaponLogic.BeginRemotePlayerFire(component, endPoint2); instance.audioSystem.PlayShootAudioFromPlayer(targetObj); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Helpers { internal static class TargetObjectResolver { private class CharacterSizeCache { private bool isGenericNpcCached; private bool isPlayerCached; private Vector3 genericNpcModelCenter; public Vector3 playerModelCenter; public bool GetGenericNpcCenter(Transform baseObj, out Vector3 center) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!isGenericNpcCached) { GetCharacterCenter(baseObj, out isGenericNpcCached, out genericNpcModelCenter); } center = genericNpcModelCenter; return isGenericNpcCached; } public bool GetPlayerCenter(Transform baseObj, out Vector3 center) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!isPlayerCached) { GetCharacterCenter(baseObj, out isPlayerCached, out playerModelCenter); } center = playerModelCenter; return isPlayerCached; } private void GetCharacterCenter(Transform remoteTargetT, out bool centerFound, out Vector3 center) { //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) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) center = Vector3.zero; Collider componentInChildren = ((Component)remoteTargetT).GetComponentInChildren(); Bounds bounds; if (Object.op_Implicit((Object)(object)componentInChildren)) { bounds = componentInChildren.bounds; center = ((Bounds)(ref bounds)).extents; centerFound = true; return; } Mesh val = null; SkinnedMeshRenderer componentInChildren2 = ((Component)remoteTargetT).GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren2)) { val = componentInChildren2.sharedMesh; } if (!Object.op_Implicit((Object)(object)val)) { MeshFilter componentInChildren3 = ((Component)remoteTargetT).GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren3)) { val = componentInChildren3.sharedMesh; } } if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogWarning("No Collider, SkinnedMeshRenderer or MeshFilter " + $"found for transform {remoteTargetT}", (LogCategories)268435456); centerFound = false; } else { bounds = val.bounds; center = ((Bounds)(ref bounds)).extents; centerFound = true; } } } private static GameObject parentTrashObj; private static CharacterSizeCache charSizeCache; public static void ResetCache() { charSizeCache = new CharacterSizeCache(); } public static bool GetTargetAdjustedPosition(FireNetworkData fireNetData, out Vector3 position) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (FindTargetObjectByNetid(fireNetData.TargetNetid, fireNetData.TargetType, out var targetObj)) { Vector3 center = Vector3.zero; if (fireNetData.TargetType switch { TargetType.Player => charSizeCache.GetPlayerCenter(targetObj, out center) ? 1 : 0, TargetType.NPC => charSizeCache.GetGenericNpcCenter(targetObj, out center) ? 1 : 0, _ => 0, } == 0) { position = targetObj.position; return true; } float num = 0.6f; Vector2 insideUnitCircle = Random.insideUnitCircle; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(center.x * num * insideUnitCircle.x, center.y * num * insideUnitCircle.y, 0f); Vector3 val2 = Vector3.up * center.y; Vector3 val3 = targetObj.TransformVector(val + val2); position = targetObj.position + val3; return true; } position = Vector3.zero; return false; } public static bool FindTargetObjectByNetid(uint targetNetid, TargetType targetType, out Transform targetObj) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) targetObj = null; switch (targetType) { case TargetType.Player: { PlayerNetwork val = ((IEnumerable)Object.FindObjectsByType((FindObjectsInactive)0, (FindObjectsSortMode)0)).FirstOrDefault((Func)((PlayerNetwork p) => ((NetworkBehaviour)p).netId == targetNetid)); if (Object.op_Implicit((Object)(object)val)) { targetObj = ((Component)val).transform; } break; } case TargetType.NPC: targetObj = FindNpcInParentByNetid(NPC_Manager.Instance.employeeParentOBJ, targetNetid); if (!Object.op_Implicit((Object)(object)targetObj)) { targetObj = FindNpcInParentByNetid(NPC_Manager.Instance.customersnpcParentOBJ, targetNetid); } if (Object.op_Implicit((Object)(object)targetObj)) { break; } if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { targetObj = FindNpcInParentByNetid(NPC_Manager.Instance.dummynpcParentOBJ, targetNetid); } else { if (WorldState.CurrentOnlineMode != GameOnlineMode.Client) { break; } Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); NetworkIdentity val3 = default(NetworkIdentity); foreach (GameObject val2 in rootGameObjects) { if (((Object)val2).name.StartsWith("A_NPC_Agent") && val2.TryGetComponent(ref val3) && val3.netId == targetNetid) { targetObj = val2.transform; break; } } } break; case TargetType.Trash: if (!Object.op_Implicit((Object)(object)parentTrashObj)) { parentTrashObj = GameObject.Find("Level_SupermarketProps/Trash/"); } targetObj = FindNpcInParentByNetid(parentTrashObj, targetNetid); break; default: throw new InvalidOperationException($"The target type {targetType} is not valid for this method."); } if (!Object.op_Implicit((Object)(object)targetObj) && targetType != TargetType.Trash) { TimeLogger.Logger.LogError($"No {targetType} object could be found " + $"with netid {targetNetid}", (LogCategories)int.MinValue); } return Object.op_Implicit((Object)(object)targetObj); } private static Transform FindNpcInParentByNetid(GameObject parentObj, uint targetNetid) { if (!Object.op_Implicit((Object)(object)parentObj)) { TimeLogger.Logger.LogError("The parentObj argument cant be null or destroyed.", (LogCategories)int.MinValue); return null; } NetworkIdentity val = default(NetworkIdentity); return ((IEnumerable)parentObj.transform).Cast().FirstOrDefault((Func)((Transform t) => ((Component)t).TryGetComponent(ref val) && val.netId == targetNetid)); } } public class WeaponAnimationSystem { private static readonly Vector3 ShellOffsetPosition = new Vector3(0.25f, -0.45f, 0.425f); private static readonly Vector3 ShellEjectionForce = Vector3.up * 2.9f; private static readonly float aimAnimationTime = 0.375f; private GameObject shellfObj; private LTDescr aimMoveAnimation; private LTDescr aimRotateAnimation; private LTDescr recoilMoveAnimation; public void Initialize(GameObject fpController) { fpController.AddComponent(); shellfObj = LoadShotgunShell(); LeanTween.init(); } private GameObject LoadShotgunShell() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (new AssetBundleElement(typeof(Plugin), "Assets\\Weapon\\shotgunshell").TryLoadObject("shotgunshell", ref shellfObj)) { shellfObj.GetComponent().material.shader = ShaderUtils.SMT_Shader.Value; shellfObj.GetComponent().excludeLayers = LayerMask.op_Implicit(SMTLayers.ConvertLayersToMask(SMT_Layers.Player)); } return shellfObj; } public void SpawnShotgunShell(PlayerNetwork playerNetwork) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_009e: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00bf: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)shellfObj)) { GameObject obj = Object.Instantiate(shellfObj); Rigidbody component = obj.GetComponent(); Vector3 val = VectorUtils.OffsetTransformPos(((Component)playerNetwork).transform, ShellOffsetPosition); component.position = val + ((Component)Camera.main).transform.position; Vector3 eulerAngles = shellfObj.transform.eulerAngles; eulerAngles.y = ((Component)Camera.main).transform.eulerAngles.y; component.rotation = Quaternion.Euler(eulerAngles); Vector3 val2 = ShellEjectionForce + ((Component)Camera.main).transform.right * 0.5f; component.velocity = val2 + Camera.main.velocity / 2f; component.interpolation = (RigidbodyInterpolation)1; Object.Destroy((Object)(object)obj, 3f); } } public void StartShotgunAimAnimation(PlayerNetwork playerNetwork, Action onComplete) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) GameObject instantiatedOBJ = playerNetwork.instantiatedOBJ; aimMoveAnimation = LeanTween.moveLocal(instantiatedOBJ, BroomShotgunPatch.BroomAimLocalPos, aimAnimationTime).setEase((LeanTweenType)4); aimRotateAnimation = LeanTween.rotateAroundLocal(instantiatedOBJ, Vector3.right, 90f, aimAnimationTime).setEase((LeanTweenType)4).setOnComplete(onComplete); } public void StartShotgunRecoilAnimation(GameObject broomObj, Action onComplete) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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) Vector3 val = Vector3.zero + Vector3.back * 1.3f + Vector3.right * 0.3f; recoilMoveAnimation = LeanTween.moveLocal(broomObj, val, 0.2f).setForceFromCurrentLocalPosition().setEase((LeanTweenType)18) .setOnComplete((Action)delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) LeanTween.moveLocal(broomObj, BroomShotgunPatch.BroomAimLocalPos, 0.65f).setForceFromCurrentLocalPosition().setEase((LeanTweenType)4) .setOnComplete(onComplete); }); } public void CancelAnimations() { if (aimMoveAnimation != null) { LeanTween.cancel(aimMoveAnimation.id); } if (aimRotateAnimation != null) { LeanTween.cancel(aimRotateAnimation.id); } if (recoilMoveAnimation != null) { LeanTween.cancel(recoilMoveAnimation.id); } } } public enum SoundBite { Equip, Shoot, Pump, All } public enum AudioAction { Play, Stop, Pause, UnPause } public class WeaponAudioSystem { private static AudioClip shotgunEquipAudioClip; private AudioSource shotgunEquipAudio; private static AudioClip shotgunShotAudioClip; private AudioSource shotgunShotAudio; private static AudioClip shotgunPumpAudioClip; private AudioSource shotgunPumpAudio; public void Initialize(GameObject fpController) { shotgunEquipAudio = GetShotgunAudioSourceByName("shotgunEquipAudio", fpController.transform); shotgunShotAudio = GetShotgunAudioSourceByName("shotgunShotAudio", fpController.transform); shotgunPumpAudio = GetShotgunAudioSourceByName("shotgunPumpAudio", fpController.transform); } public static AudioSource GetShotgunAudioSourceByName(string name, Transform obj) { return (from a in ((Component)obj).GetComponents() where ((Object)a.clip).name == name select a).FirstOrDefault(); } public void SetPlaybackState(SoundBite soundBite, AudioAction audioAction) { if (soundBite == SoundBite.Equip || soundBite == SoundBite.All) { DoAudioAction(UnityObjectExtensions.NullableObject(shotgunEquipAudio), audioAction); } if (soundBite == SoundBite.Shoot || soundBite == SoundBite.All) { DoAudioAction(UnityObjectExtensions.NullableObject(shotgunShotAudio), audioAction); } if (soundBite == SoundBite.Pump || soundBite == SoundBite.All) { DoAudioAction(UnityObjectExtensions.NullableObject(shotgunPumpAudio), audioAction); } } private void DoAudioAction(AudioSource audioSource, AudioAction audioAction) { if (Object.op_Implicit((Object)(object)audioSource)) { switch (audioAction) { case AudioAction.Play: audioSource.Play(); break; case AudioAction.Stop: audioSource.Stop(); break; case AudioAction.Pause: audioSource.Pause(); break; case AudioAction.UnPause: audioSource.UnPause(); break; } } } public static async Task LoadSoundFiles() { shotgunEquipAudioClip = await GetAudioClipFromFile(typeof(BroomShotgunPatch), "Assets\\Weapon\\EquipWeapon.mp3"); shotgunShotAudioClip = await GetAudioClipFromFile(typeof(BroomShotgunPatch), "Assets\\Weapon\\ShotgunShot.mp3"); shotgunPumpAudioClip = await GetAudioClipFromFile(typeof(BroomShotgunPatch), "Assets\\Weapon\\ShotgunPump.mp3"); } public static void AddAudioSourceComponents(GameObject targetObject) { CreateAudioSourceComponent(targetObject, "shotgunEquipAudio", shotgunEquipAudioClip, 1f); CreateAudioSourceComponent(targetObject, "shotgunShotAudio", shotgunShotAudioClip, 0.34f); CreateAudioSourceComponent(targetObject, "shotgunPumpAudio", shotgunPumpAudioClip, 0.31f); } private static AudioSource CreateAudioSourceComponent(GameObject targetObj, string objName, AudioClip clip, float volume) { AudioSource val = targetObj.AddComponent(); val.clip = clip; ((Object)val.clip).name = objName; val.playOnAwake = false; val.priority = 100; val.spatialBlend = 1f; val.rolloffMode = (AudioRolloffMode)1; val.volume = volume; val.maxDistance = 150f; val.minDistance = 0.5f; Transform val2 = targetObj.transform.Find("HitSound"); AudioSource val3 = default(AudioSource); if (Object.op_Implicit((Object)(object)val2) && ((Component)val2).TryGetComponent(ref val3) && Object.op_Implicit((Object)(object)val3)) { val.outputAudioMixerGroup = val3.outputAudioMixerGroup; } return val; } public void PlayShootAudioFromPlayer(Transform playerSourceT) { AudioSource shotgunAudioSourceByName = GetShotgunAudioSourceByName("shotgunShotAudio", playerSourceT); if (Object.op_Implicit((Object)(object)shotgunAudioSourceByName)) { shotgunAudioSourceByName.Play(); } } private static async Task GetAudioClipFromFile(Type projectType, string pathFromModRoot) { string audioFilePath = AssemblyUtils.GetCombinedPathFromAssemblyFolder(projectType, pathFromModRoot); UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(audioFilePath, (AudioType)13); try { Awaiter val = AsyncOperationAwaitableExtensions.GetAwaiter((AsyncOperation)(object)www.SendWebRequest()); if (!((Awaiter)(ref val)).IsCompleted) { await val; Awaiter val2 = default(Awaiter); val = val2; } ((Awaiter)(ref val)).GetResult(); if ((int)www.result != 2 && (int)www.result != 3) { AudioClip content = DownloadHandlerAudioClip.GetContent(www); if (string.IsNullOrEmpty(((Object)content).name)) { ((Object)content).name = Path.GetFileNameWithoutExtension(pathFromModRoot); } return content; } TimeLogger.Logger.LogError("File in path \"" + audioFilePath + "\" couldnt be loaded. The error message is: " + www.error, (LogCategories)8); } finally { ((IDisposable)www)?.Dispose(); } return null; } } public enum TargetType { None, OtherCollider, NPC, Player, Trash } public class WeaponLogic { private record struct PelletHitData(RaycastHit Hit, float Distance, Vector3 EndPoint, Ray PelletFullRay, TargetType Target) { [CompilerGenerated] private readonly bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) builder.Append("Hit = "); RaycastHit hit = Hit; builder.Append(((object)(RaycastHit)(ref hit)).ToString()); builder.Append(", Distance = "); builder.Append(Distance.ToString()); builder.Append(", EndPoint = "); Vector3 endPoint = EndPoint; builder.Append(((object)(Vector3)(ref endPoint)).ToString()); builder.Append(", PelletFullRay = "); Ray pelletFullRay = PelletFullRay; builder.Append(((object)(Ray)(ref pelletFullRay)).ToString()); builder.Append(", Target = "); builder.Append(Target.ToString()); return true; } } private PlayerNetwork pNetwork; private readonly SmokeManager tracerSmokeSystem; private GameObject masterPlayerOBJ; public static ShotgunDefinition ShotgunDefinition { get; } = ShotgunDefinition.DefaultShotgunDefinition; public WeaponLogic() { tracerSmokeSystem = new SmokeManager(); } public void Destroy() { tracerSmokeSystem.Destroy(); } public void BeginLocalPlayerFire(out GameObject broomObj) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (pNetwork == null) { pNetwork = SMTInstances.LocalPlayerNetwork(); } Vector3 broomTip; Vector3 broomTipPoint = GetBroomTipPoint(pNetwork, out broomObj, out broomTip); Vector3 crosshairEndPoint = GetCrosshairEndPoint(); List list = GeneratePelletsHitData(broomTipPoint, crosshairEndPoint); List list2 = new List(); NetworkIdentity val = default(NetworkIdentity); foreach (PelletHitData item in list) { TargetType target = item.Target; if (target != 0 && target != TargetType.OtherCollider && TriggerTargetBeingShot(target, item.Hit, out var targetBaseObj)) { if (!((Component)targetBaseObj).TryGetComponent(ref val)) { TimeLogger.Logger.LogError($"Object {targetBaseObj} does not contain a " + "NetworkIdentity component.", (LogCategories)int.MinValue); } else { list2.Add(new FireNetworkData(val.netId, target)); } } } SpawnTracerPellets(list, broomTipPoint, broomObj, broomTip); uint netId = ((NetworkBehaviour)SMTInstances.LocalPlayerNetwork()).netId; BroomShotgunNetwork.LocalInstance.CmdPlayerFire(crosshairEndPoint, netId, list2.ToArray()); } public void BeginRemotePlayerFire(PlayerNetwork sourcePlayer, Vector3 endPoint) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) GameObject broomObj; Vector3 broomTip; Vector3 broomTipPoint = GetBroomTipPoint(sourcePlayer, out broomObj, out broomTip); List pelletDataList = GeneratePelletsHitData(broomTipPoint, endPoint); SpawnTracerPellets(pelletDataList, broomTipPoint, broomObj, broomTip); } private bool TriggerTargetBeingShot(TargetType targetType, RaycastHit hitData, out Transform targetBaseObj) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) targetBaseObj = null; GameObject gameObject = ((Component)((RaycastHit)(ref hitData)).collider).gameObject; bool flag = targetType == TargetType.NPC || targetType == TargetType.Player; if (flag && gameObject.tag != "Interactable" && gameObject.tag != "Player") { return false; } targetBaseObj = GetTargetBaseObject(targetType, hitData); if (!Object.op_Implicit((Object)(object)targetBaseObj)) { TimeLogger.Logger.LogError($"The target base object of type {targetType} is null.", (LogCategories)int.MinValue); return false; } switch (targetType) { case TargetType.NPC: ((Component)targetBaseObj).GetComponent().CmdAnimationPlay(0); break; case TargetType.Player: { if (!Object.op_Implicit((Object)(object)masterPlayerOBJ)) { masterPlayerOBJ = FsmVariables.GlobalVariables.FindFsmGameObject("MasterPlayerOBJ").Value; } Vector3 val = gameObject.transform.position - masterPlayerOBJ.transform.position; ((Component)targetBaseObj).GetComponent().CmdPushPlayer(((Vector3)(ref val)).normalized); break; } case TargetType.Trash: gameObject.GetComponent().CmdClearTrash(); break; } if (flag) { string tag = gameObject.tag; gameObject.tag = "Untagged"; DelayedRestoreInteractableTag(gameObject, tag); } return true; } private Transform GetTargetBaseObject(TargetType targetType, RaycastHit hitData) { Transform transform = ((Component)((RaycastHit)(ref hitData)).collider).transform; switch (targetType) { case TargetType.NPC: return transform.parent; case TargetType.Player: if (((Component)transform).tag == "Player") { return transform; } return transform.parent.parent; case TargetType.Trash: return ((RaycastHit)(ref hitData)).transform; default: return null; } } private void SpawnTracerPellets(List pelletDataList, Vector3 muzzlePos, GameObject broomObj, Vector3 broomTip) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) SingleTracerData[] tracerDataGroup = pelletDataList.Select(delegate(PelletHitData p) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) Ray pelletFullRay = p.PelletFullRay; Vector3 startOffset = ShotgunDefinition.Tracers.StartOffset; Vector3 endPoint = p.EndPoint; float distance = p.Distance; ShotgunDefinition shotgunDefinition = ShotgunDefinition; RaycastHit hit = pelletDataList[0].Hit; return new SingleTracerData(pelletFullRay, startOffset, endPoint, distance, shotgunDefinition, ((RaycastHit)(ref hit)).normal, p.Target == TargetType.OtherCollider, pelletDataList.Count); }).ToArray(); ShotgunEffectsManager.SpawnTracerGroup(muzzlePos, tracerDataGroup, ShotgunDefinition, broomObj, broomTip, tracerSmokeSystem, animateTravel: true, addMuzzleFlash: false, addImpactHitMark: true, addImpactSparks: true, addLight: true); } private Vector3 GetBroomTipPoint(PlayerNetwork pNetwork, out GameObject broomObj, out Vector3 broomTip) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) broomObj = pNetwork.instantiatedOBJ; Bounds bounds = broomObj.GetComponent().sharedMesh.bounds; broomTip = ((Bounds)(ref bounds)).center + Vector3.forward * ((Bounds)(ref bounds)).extents.z; broomTip += Vector3.right * 0.009f; return broomObj.transform.TransformPoint(broomTip); } private async void DelayedRestoreInteractableTag(GameObject targetHit, string tag) { await UniTask.Delay(1550, false, (PlayerLoopTiming)8, default(CancellationToken), false); if (Object.op_Implicit((Object)(object)targetHit)) { targetHit.tag = tag; } } private List GeneratePelletsHitData(Vector3 muzzlePos, Vector3 endPoint) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_00cf: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Dictionary dictionary = new Dictionary(); RaycastHit val2 = default(RaycastHit); for (int i = 0; i < ShotgunDefinition.ProjectileCount; i++) { Ray val = CalculateRayForPellet(i == 0, muzzlePos, endPoint); TargetType value = TargetType.None; if (Physics.Raycast(val, ref val2, (float)ShotgunDefinition.ProjectileMaxRange, SMTLayers.RayCastGenericLayerMask)) { if (dictionary.TryGetValue(((RaycastHit)(ref val2)).colliderInstanceID, out value)) { value = ((value != TargetType.Player && value != TargetType.NPC && value != TargetType.Trash) ? SanitizeTargetCollider(value, val2) : TargetType.None); } else { value = GetTargetHitMatch(((Component)((RaycastHit)(ref val2)).collider).gameObject); value = SanitizeTargetCollider(value, val2); dictionary.Add(((RaycastHit)(ref val2)).colliderInstanceID, value); } list.Add(new PelletHitData(val2, ((RaycastHit)(ref val2)).distance, ((RaycastHit)(ref val2)).point, val, value)); } else { Vector3 point = ((Ray)(ref val)).GetPoint((float)ShotgunDefinition.ProjectileMaxRange); list.Add(new PelletHitData(default(RaycastHit), ShotgunDefinition.ProjectileMaxRange, point, val, value)); } } return list; } private TargetType SanitizeTargetCollider(TargetType targetType, RaycastHit hitData) { if (targetType == TargetType.None && Object.op_Implicit((Object)(object)((RaycastHit)(ref hitData)).collider)) { return TargetType.OtherCollider; } return targetType; } private Vector3 GetCrosshairEndPoint() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)Camera.main).transform; RaycastHit val = default(RaycastHit); if (Physics.Raycast(Camera.main.ViewportPointToRay(Vector2.op_Implicit(new Vector2(0.5f, 0.5f)), (MonoOrStereoscopicEye)2), ref val, (float)ShotgunDefinition.ProjectileMaxRange, SMTLayers.RayCastGenericLayerMask)) { return ((RaycastHit)(ref val)).point; } return transform.position + transform.forward * (float)ShotgunDefinition.ProjectileMaxRange; } private Ray CalculateRayForPellet(bool isFirstPellet, Vector3 muzzlePos, Vector3 endPoint) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Vector3 val = endPoint - muzzlePos; Vector3 val2 = ((Vector3)(ref val)).normalized; if (!isFirstPellet) { val2 = VectorUtils.GetRandomSpreadDirection(Camera.main, (SpreadAxis)2, val2, ShotgunDefinition.SpreadAngle); } return new Ray(muzzlePos, val2); } private TargetType GetTargetHitMatch(GameObject targetHit) { TargetType result = TargetType.None; Transform transform = targetHit.transform; TrashSpawn val = default(TrashSpawn); if (Object.op_Implicit((Object)(object)transform.parent) && Object.op_Implicit((Object)(object)((Component)transform.parent).GetComponent())) { result = TargetType.NPC; } else if (Object.op_Implicit((Object)(object)transform) && (Object.op_Implicit((Object)(object)((Component)transform).GetComponent()) || (Object.op_Implicit((Object)(object)transform.parent) && Object.op_Implicit((Object)(object)transform.parent.parent) && Object.op_Implicit((Object)(object)((Component)transform.parent.parent).GetComponent())))) { result = TargetType.Player; } else if (targetHit.TryGetComponent(ref val)) { result = TargetType.Trash; } return result; } } public record struct FireNetworkData(uint TargetNetid, TargetType TargetType); } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects { public class ShotgunEffectsBehaviour : MonoBehaviour { internal static ShotgunEffectsBehaviour Instance { get; private set; } internal static Dictionary GroupedTracers { get; set; } internal static List> GroupedImpacts { get; set; } static ShotgunEffectsBehaviour() { TracerGroupData.OnTracerAdded = (Action)Delegate.Combine(TracerGroupData.OnTracerAdded, (Action)delegate { ((Behaviour)Instance).enabled = true; }); ImpactGroupData.OnImpactAdded = (Action)Delegate.Combine(ImpactGroupData.OnImpactAdded, (Action)delegate { ((Behaviour)Instance).enabled = true; }); } private void Awake() { Instance = this; GroupedTracers = new Dictionary(); GroupedImpacts = new List>(); } private void Update() { //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) if (Time.timeScale == 0f) { return; } List list = null; List> list2 = null; float time = Time.time; Renderer val = default(Renderer); foreach (KeyValuePair groupedTracer in GroupedTracers) { Material key = groupedTracer.Key; TracerGroupData value = groupedTracer.Value; if (!value.HasStarted) { value.StartTracingTimers(time); } float num = time - value.StartLifetime; foreach (SingleTracerData tracer in value.Tracers) { LineRenderer lineRender = tracer.LineRender; if (Object.op_Implicit((Object)(object)lineRender)) { ProcessTracer(num, value, tracer); if (!((Renderer)lineRender).enabled) { Object.Destroy((Object)(object)((Component)lineRender).gameObject); } } } bool flag = ProcessMuzzleSmoke(value, value.MuzzleSmokeSettings, num); if (Object.op_Implicit((Object)(object)value.LightSrc)) { float num2 = num / value.TracerSettings.MuzzleFlashTime; if (num2 < 1f) { value.LightSrc.intensity = Mathf.Lerp(0f, 1.2f, num2); } else { ((Behaviour)value.LightSrc).enabled = false; Object.Destroy((Object)(object)((Component)value.LightSrc).gameObject); } } bool flag2 = true; if (Object.op_Implicit((Object)(object)value.BroomMuzzleObj) && value.BroomMuzzleObj.activeSelf && value.BroomMuzzleObj.TryGetComponent(ref val)) { float num3 = 1f - num / value.TracerSettings.MuzzleFlashTime; if (num3 > 0f) { Color color = val.material.GetColor("_TintColor"); color.a = num3; val.material.SetColor("_TintColor", color); flag2 = false; } else { value.BroomMuzzleObj.SetActive(false); } } if (value.HasTracersFinished() && !Object.op_Implicit((Object)(object)value.LightSrc) && flag && flag2) { if (list == null) { list = new List(); } list.Add(key); } } foreach (IImpactHandler groupedImpact in GroupedImpacts) { groupedImpact.UpdateFade(time); if (!groupedImpact.IsImpactFinished) { continue; } foreach (IImpactData item in groupedImpact.ImpactCollection) { GameObject[] impactObjs = item.ImpactObjs; foreach (GameObject val2 in impactObjs) { if (Object.op_Implicit((Object)(object)val2)) { Object.Destroy((Object)(object)val2); } } } if (list2 == null) { list2 = new List>(); } list2.Add(groupedImpact); } if (list != null) { foreach (Material item2 in list) { GroupedTracers.Remove(item2); } } if (list2 != null) { foreach (IImpactHandler item3 in list2) { GroupedImpacts.Remove(item3); } } if (GroupedTracers == null || (GroupedTracers.Count == 0 && GroupedImpacts.Count == 0)) { ((Behaviour)this).enabled = false; } } internal void ProcessTracer(float elapsedTime, TracerGroupData tracerGroup, SingleTracerData tracerData) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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) LineRenderer lineRender = tracerData.LineRender; if (tracerGroup.Animate && ((Renderer)lineRender).enabled) { if (!tracerData.HasCalculatedEndTime) { tracerData.CalculateTracerEndTime(tracerGroup.StartLifetime, tracerGroup.ProjectileSpeed); } ITracerSettings tracerSettings = tracerGroup.TracerSettings; float num = elapsedTime / tracerData.TotalFlightTime; float startWidth = default(float); Vector3 value = tracerData.FullRayPath.GetValue(num, ref startWidth); float num2 = LeanTween.easeInQuad(0f, 1f, num) * (1f / tracerSettings.LengthMultiplier); float endWidth = default(float); Vector3 value2 = tracerData.FullRayPath.GetValue(num2, ref endWidth); lineRender.SetPosition(0, value2); lineRender.SetPosition(1, value); lineRender.startWidth = startWidth; lineRender.endWidth = endWidth; if (tracerGroup.SmokeManagerSystem != null && tracerGroup.SmokeManagerSystem.Active && tracerData.SpawnsSmokeTrail) { float smokeSpawnChance = 1f - num; SmokeManager smokeManagerSystem = tracerGroup.SmokeManagerSystem; uint smokeTrailId = tracerData.SmokeTrailId; Ray projectileRay = tracerData.ProjectileRay; smokeManagerSystem.SpawnSmokeTrail(smokeTrailId, value2, ((Ray)(ref projectileRay)).direction, tracerSettings.SmokeSettings.BaseVelocity, tracerSettings.SmokeSettings, smokeSpawnChance); } if (num2 >= 1f) { ((Renderer)lineRender).enabled = false; } } } private bool ProcessMuzzleSmoke(TracerGroupData tracerGroup, InterpolatedMuzzleSmoke muzzleSmokeSettings, float elapsedTime) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_00a3: Unknown result type (might be due to invalid IL or missing references) if (tracerGroup.SmokeManagerSystem != null && tracerGroup.SmokeManagerSystem.Active && Object.op_Implicit((Object)(object)tracerGroup.BroomMuzzleObj) && elapsedTime < muzzleSmokeSettings.SmokeEffectTotalTime) { Vector3 position = tracerGroup.BroomMuzzleObj.transform.position; float num = elapsedTime / muzzleSmokeSettings.SmokeEffectTotalTime; float num2 = Mathf.Max(1f - num, 0.2f); int smokeCount = Mathf.RoundToInt((float)Random.Range(muzzleSmokeSettings.MinSmokeParticles, muzzleSmokeSettings.MaxSmokeParticles) * num2); Vector3 initialVelocity = Vector3.up * num2; float smokeSpread = num2 * muzzleSmokeSettings.Spread; tracerGroup.SmokeManagerSystem.SpawnSmokeGroup(tracerGroup.MuzzleSmokeId, position, smokeSpread, initialVelocity, smokeCount, muzzleSmokeSettings); return num >= 1f; } return true; } } public class ShotgunEffectsManager { public static void SpawnTracer(Vector3 start, SingleTracerData tracerData, IWeaponDefinition weaponDefinition, GameObject broomObj, Vector3 broomLocalTip, SmokeManager smokeManager, bool animateTravel, bool addMuzzleFlash, bool addImpactHitMark, bool addImpactSparks, bool addLight) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) SpawnTracerInternal(start, new SingleTracerData[1] { tracerData }, weaponDefinition, broomObj, broomLocalTip, smokeManager, animateTravel, addMuzzleFlash, addImpactHitMark, addImpactSparks, addLight); } public static void SpawnTracerGroup(Vector3 start, SingleTracerData[] tracerDataGroup, IWeaponDefinition weaponDefinition, GameObject broomObj, Vector3 broomLocalTip, SmokeManager smokeManager, bool animateTravel, bool addMuzzleFlash, bool addImpactHitMark, bool addImpactSparks, bool addLight) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) SpawnTracerInternal(start, tracerDataGroup, weaponDefinition, broomObj, broomLocalTip, smokeManager, animateTravel, addMuzzleFlash, addImpactHitMark, addImpactSparks, addLight); } private static void SpawnTracerInternal(Vector3 start, SingleTracerData[] tracerDataGroup, IWeaponDefinition weaponDefinition, GameObject broomObj, Vector3 broomLocalTip, SmokeManager smokeManager, bool animateTravel, bool addMuzzleFlash, bool addImpactHitMark, bool addImpactSparks, bool addLight) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) GameObject muzzleBroomObj = null; if (addMuzzleFlash || addLight || smokeManager != null) { CreateBroomMuzzleObj(weaponDefinition.Tracers.ColorStart, addMuzzleFlash, broomObj, broomLocalTip, out muzzleBroomObj); } Light light = null; if (addLight) { SpawnLightSourceFlash(weaponDefinition.Tracers.ColorStart, broomObj, broomLocalTip, out light); } Material tracerMat = new Material(ShaderUtils.URP_ParticleShaderUnlit.Value); List list = null; List list2 = null; if (addImpactHitMark) { list = new List(tracerDataGroup.Length); } if (addImpactSparks) { list2 = new List(tracerDataGroup.Length); } foreach (SingleTracerData singleTracerData in tracerDataGroup) { if (animateTravel) { SpawnTracerEffect(start, weaponDefinition, singleTracerData, tracerMat, muzzleBroomObj, light, smokeManager, animateTravel); } if (singleTracerData.CanCreateImpactMark) { list?.Add(new HitMarkSpatial(singleTracerData.EndPoint, singleTracerData.HitFaceRotation)); list2?.Add(new SparkInitialData(singleTracerData.EndPoint, singleTracerData.TotalDistance)); } } if (list != null && list.Count > 0) { VFX.SpawnImpactHitMarkGroup(list.ToArray(), weaponDefinition.Tracers.HitMarks); } if (list2 != null && list2.Count > 0) { VFX.SpawnImpactSparksGroup(list2.ToArray(), weaponDefinition.Tracers.Sparks); } } private static void SpawnTracerEffect(Vector3 start, IWeaponDefinition weaponDefinition, SingleTracerData tracerData, Material tracerMat, GameObject muzzleFlashObj, Light light, SmokeManager smokeManager, bool animateTravel) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) LineRenderer val2 = (tracerData.LineRender = new GameObject("Tracer").AddComponent()); ((Renderer)val2).sharedMaterial = tracerMat; val2.positionCount = 2; val2.numCapVertices = 1; val2.numCornerVertices = 1; val2.textureMode = (LineTextureMode)0; val2.useWorldSpace = true; val2.startColor = weaponDefinition.Tracers.ColorStart; val2.endColor = weaponDefinition.Tracers.ColorEnd; VFX.SpawnTracerEffect(tracerMat, weaponDefinition.ProjectileSpeed, weaponDefinition.Tracers, weaponDefinition.MuzzleSmoke, start, tracerData, light, smokeManager, muzzleFlashObj, animateTravel); } private static void CreateBroomMuzzleObj(Color color, bool addMuzzleFlash, GameObject broomObj, Vector3 broomLocalTip, out GameObject muzzleBroomObj) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) string text = "MuzzleBroom"; muzzleBroomObj = UnityObjectExtensions.GameObject((Component)(object)broomObj.transform.Find(text)); if (!Object.op_Implicit((Object)(object)muzzleBroomObj)) { if (addMuzzleFlash) { muzzleBroomObj = MeshUtils.CreateQuadPrimitive(text, 1f, 1f, true); Renderer component = muzzleBroomObj.GetComponent(); component.material = new Material(ShaderUtils.LegacyParticleShader.Value); component.material.SetColor("_TintColor", color); } else { muzzleBroomObj = new GameObject(text); } Transform transform = muzzleBroomObj.transform; Camera main = Camera.main; transform.localRotation = Quaternion.LookRotation((main != null) ? ((Component)main).transform.forward : Vector3.forward); muzzleBroomObj.transform.localScale = Vector3.one * 0.08f; muzzleBroomObj.transform.parent = broomObj.transform; muzzleBroomObj.transform.localPosition = broomLocalTip; } muzzleBroomObj.SetActive(true); } private static void SpawnLightSourceFlash(Color color, GameObject broomObj, Vector3 broomLocalTip, out Light light) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Light"); light = val.AddComponent(); light.type = (LightType)2; light.range = 17f; light.intensity = 0.65f; light.color = color; val.transform.parent = broomObj.transform; val.transform.localPosition = broomLocalTip; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Model { public interface IImpactData { GameObject[] ImpactObjs { get; } } public record struct HitMarkSpatial(Vector3 Position, Quaternion HitFaceRotation) { [CompilerGenerated] private readonly bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) builder.Append("Position = "); Vector3 position = Position; builder.Append(((object)(Vector3)(ref position)).ToString()); builder.Append(", HitFaceRotation = "); Quaternion hitFaceRotation = HitFaceRotation; builder.Append(((object)(Quaternion)(ref hitFaceRotation)).ToString()); return true; } } public readonly struct HitMarkData : IImpactData { public GameObject[] ImpactObjs { get; } public HitMarkData(GameObject impactObj) { ImpactObjs = (GameObject[])(object)new GameObject[1] { impactObj }; } } public record struct SparkInitialData(Vector3 Position, float Distance) { [CompilerGenerated] private readonly bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) builder.Append("Position = "); Vector3 position = Position; builder.Append(((object)(Vector3)(ref position)).ToString()); builder.Append(", Distance = "); builder.Append(Distance.ToString()); return true; } } public readonly struct SparkData : IImpactData { public Vector3 Position { get; } public GameObject[] ImpactObjs { get; } public SparkData(SparkInitialData sparkData, GameObject[] impactSparkObjs) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Position = sparkData.Position; ImpactObjs = impactSparkObjs; } } public interface IImpactHandler where T : IImpactData { List ImpactCollection { get; } bool IsImpactFinished { get; } void AddNewImpactEntry(T impactData); void UpdateFade(float currentTime); } public class ImpactHitMarkHandler : ImpactGroupData, IImpactHandler { public List ImpactCollection { get; } = new List(); public bool IsImpactFinished { get; private set; } public ImpactHitMarkHandler(float currentTime, Color color, IImpactSettings impactSettings, Material matReference) : base(currentTime, color, impactSettings, matReference) { }//IL_000d: Unknown result type (might be due to invalid IL or missing references) public void AddNewImpactEntry(IImpactData impactData) { if (!(impactData is HitMarkData)) { throw new InvalidOperationException("The parameter type must be HitMarkData"); } ImpactCollection.Add(impactData); ImpactGroupData.OnImpactAdded?.Invoke(); } public void UpdateFade(float currentTime) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) float num = ReverseProgress(currentTime); if (num <= 0f) { IsImpactFinished = true; } else { matReference.SetColor("_TintColor", color * num); } } } public class ImpactSparksHandler : ImpactGroupData, IImpactHandler { public List ImpactCollection { get; } = new List(); public bool IsImpactFinished { get; private set; } public ImpactSparksHandler(float currentTime, Color color, IImpactSettings impactSettings, Material matReference) : base(currentTime, color, impactSettings, matReference) { }//IL_000d: Unknown result type (might be due to invalid IL or missing references) public void AddNewImpactEntry(IImpactData impactData) { if (!(impactData is SparkData)) { throw new InvalidOperationException("The parameter type must be SparkData"); } ImpactCollection.Add(impactData); ImpactGroupData.OnImpactAdded?.Invoke(); } public void UpdateFade(float currentTime) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) float num = ReverseProgress(currentTime); if (num <= 0f) { IsImpactFinished = true; return; } float num2 = impactSettings.MinFadeProgress + num * impactSettings.MinFadeProgress; matReference.SetColor("_TintColor", color * num2); } } public abstract class ImpactGroupData { protected readonly float timeStart; protected float lifeTime; protected Color color; protected IImpactSettings impactSettings; protected Material matReference; public static Action OnImpactAdded { get; set; } protected ImpactGroupData(float currentTime, Color color, IImpactSettings impactSettings, Material matReference) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) timeStart = currentTime; lifeTime = impactSettings.FadeTime; this.color = color; this.impactSettings = impactSettings; this.matReference = matReference; base..ctor(); } protected float ReverseProgress(float currentTime) { return 1f - (currentTime - timeStart) / lifeTime; } } public class SingleTracerData { public uint SmokeTrailId { get; private set; } public Vector3CurvesDistanceWidth FullRayPath { get; } public Ray ProjectileRay { get; } public Vector3 EndPoint { get; } public float TotalDistance { get; } public LineRenderer LineRender { get; set; } public float EndTime { get; private set; } public float TotalFlightTime { get; private set; } public bool CanCreateImpactMark { get; private set; } public Quaternion HitFaceRotation { get; private set; } public bool HasCalculatedEndTime { get; private set; } public bool SpawnsSmokeTrail { get; } public SingleTracerData(Ray projectileRay, Vector3 startOffset, Vector3 endPoint, float totalDistance, IWeaponDefinition weaponDefinition, Vector3 hitFaceRotation, bool createsImpactMark, int totalTracers) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) SmokeTrailId = TracerGroupData.GlobalSmokeIdCounter++; ProjectileRay = projectileRay; EndPoint = endPoint; TotalDistance = totalDistance; CanCreateImpactMark = createsImpactMark; HitFaceRotation = (createsImpactMark ? Quaternion.LookRotation(hitFaceRotation) : Quaternion.identity); Vector3 direction = ((Ray)(ref projectileRay)).direction; Ray projectileRay2 = ProjectileRay; FullRayPath = GenerateVector3TracePath(startOffset, direction, ((Ray)(ref projectileRay2)).origin, EndPoint, TotalDistance, weaponDefinition); SpawnsSmokeTrail = Random.value < 1f / ((float)totalTracers / 3f); } private static Vector3CurvesDistanceWidth GenerateVector3TracePath(Vector3 startOffset, Vector3 direction, Vector3 startPoint, Vector3 endPoint, float totalProjectileDistance, IWeaponDefinition weaponDefinition) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) ITracerSettings tracers = weaponDefinition.Tracers; float num = ((tracers.MaxWidthDistance >= 0f) ? tracers.MaxWidthDistance : ((float)weaponDefinition.ProjectileMaxRange)); Vector3 val = startPoint; if (startOffset != Vector3.zero) { Quaternion val2 = Quaternion.LookRotation(direction); val = startPoint + val2 * startOffset; } return new Vector3CurvesDistanceWidth(val, endPoint, tracers.WidthStart, tracers.WidthEnd, totalProjectileDistance, num); } public void CalculateTracerEndTime(float startLifeTime, float projectileSpeed) { EndTime = startLifeTime + TotalDistance / projectileSpeed; TotalFlightTime = EndTime - startLifeTime; HasCalculatedEndTime = true; } } public class TracerGroupData { public static uint GlobalSmokeIdCounter { get; set; } = 1u; public uint MuzzleSmokeId { get; private set; } = GlobalSmokeIdCounter++; public ITracerSettings TracerSettings { get; private set; } public InterpolatedMuzzleSmoke MuzzleSmokeSettings { get; private set; } public bool HasStarted { get; private set; } public float StartLifetime { get; private set; } public float ProjectileSpeed { get; } public Light LightSrc { get; } public SmokeManager SmokeManagerSystem { get; } public GameObject BroomMuzzleObj { get; } public bool Animate { get; } public Vector3 StartPos { get; } public List Tracers { get; } public static Action OnTracerAdded { get; set; } public TracerGroupData(ITracerSettings tracerSettings, float projectileSpeed, InterpolatedMuzzleSmoke muzzleSmokeSettings, Vector3 startPos, Light lightSrc, SmokeManager smokeManager, GameObject muzzleFlashObj, bool animate) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) TracerSettings = tracerSettings; MuzzleSmokeSettings = muzzleSmokeSettings; ProjectileSpeed = projectileSpeed; LightSrc = lightSrc; SmokeManagerSystem = smokeManager; BroomMuzzleObj = muzzleFlashObj; Animate = animate; StartPos = startPos; Tracers = new List(); base..ctor(); } public void StartTracingTimers(float currentTime) { if (!HasStarted) { HasStarted = true; StartLifetime = currentTime; } } public void AddNewTracerEntry(SingleTracerData tracerData) { Tracers.Add(tracerData); OnTracerAdded?.Invoke(); } public bool HasTracersFinished() { return Tracers.All((SingleTracerData t) => !Object.op_Implicit((Object)(object)t.LineRender) || !((Renderer)t.LineRender).enabled); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Helpers { public class SmokeManager { private record struct HistoricPosData(Vector3 CenterPos, float Time) { [CompilerGenerated] private readonly bool PrintMembers(StringBuilder builder) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) builder.Append("CenterPos = "); Vector3 centerPos = CenterPos; builder.Append(((object)(Vector3)(ref centerPos)).ToString()); builder.Append(", Time = "); builder.Append(Time.ToString()); return true; } } private class InterpolationCache { private readonly Dictionary previousSmokeParticles; private readonly CancellationTokenSource cancelSource; public InterpolationCache() { previousSmokeParticles = new Dictionary(); cancelSource = new CancellationTokenSource(); TaskExtensionMethods.FireAndForgetCancels(CleanUpOldData(), (LogCategories)268435456, false); } public void Destroy() { cancelSource.Cancel(); } public bool CanInterpolate(uint UniqueInstanceId, Vector3 centerPosition, out Vector3 lastCenterPos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) lastCenterPos = default(Vector3); HistoricPosData value = new HistoricPosData(centerPosition, Time.time); if (previousSmokeParticles.TryGetValue(UniqueInstanceId, out var value2)) { previousSmokeParticles[UniqueInstanceId] = value; lastCenterPos = value2.CenterPos; return true; } previousSmokeParticles.Add(UniqueInstanceId, value); return false; } public async Task CleanUpOldData() { while (!cancelSource.IsCancellationRequested) { await UniTask.Delay(1000, false, (PlayerLoopTiming)8, cancelSource.Token, false); float num = Time.time - 1f; KeyValuePair[] array = previousSmokeParticles.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair keyValuePair = array[i]; if (keyValuePair.Value.Time < num) { previousSmokeParticles.Remove(keyValuePair.Key); } } } } } private const float warningCooldown = 4f; private readonly ParticleSystem partSystem; private readonly InterpolationCache interpolationCache; private int MaxParticlesCountWarning; private int SoftParticleCountWarning; private float canWarnSoftLimitTime = -1f; private float canWarnHardLimitTime = -1f; private GameObject smokeEmitterObj; public bool Active { get; private set; } public SmokeManager() { int value = ModConfig.Instance.MaxShotgunSmokeParticles.Value; if (value > 0) { partSystem = CreateSmokeSystem(value); Active = true; interpolationCache = new InterpolationCache(); UpdateMaxParticles(); ModConfig.Instance.MaxShotgunSmokeParticles.SettingChanged += delegate { UpdateMaxParticles(); }; StartLoggingMaxParticleCount(); } } private async void StartLoggingMaxParticleCount() { } public void Destroy() { Active = false; interpolationCache.Destroy(); } private void UpdateMaxParticles() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) int value = ModConfig.Instance.MaxShotgunSmokeParticles.Value; MainModule main = partSystem.main; ((MainModule)(ref main)).maxParticles = value; Active = value > 0; MaxParticlesCountWarning = value; SoftParticleCountWarning = Mathf.RoundToInt((float)value * 0.85f); } public void SpawnSmokeTrail(uint uniqueEffectId, Vector3 position, Vector3 direction, Vector3 initialVelocity, InterpolatedSmoke smokeSettings, float smokeSpawnChance) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (Active) { Vector3 randomSpreadOffset = VectorUtils.GetRandomSpreadOffset((SpreadAxis)2, direction, initialVelocity, smokeSettings.Spread); if (interpolationCache.CanInterpolate(uniqueEffectId, position, out var lastCenterPos)) { InterpolateSmoke(lastCenterPos, position, randomSpreadOffset, smokeSettings, smokeSpawnChance); } if (smokeSpawnChance == 1f || Random.value <= smokeSpawnChance) { SpawnSmoke(position, randomSpreadOffset, smokeSettings); } } } public void SpawnSmokeGroup(uint uniqueEffectId, Vector3 centerPosition, float smokeSpread, Vector3 initialVelocity, int smokeCount, InterpolatedMuzzleSmoke muzzleSmokeSettings) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (Active) { if (interpolationCache.CanInterpolate(uniqueEffectId, centerPosition, out var lastCenterPos)) { InterpolateSmokeSpreadGroup(lastCenterPos, centerPosition, initialVelocity, muzzleSmokeSettings, 1f, smokeCount, smokeSpread); } for (int i = 0; i < smokeCount; i++) { SpawnSmokeRandomSpread(centerPosition, smokeSpread, initialVelocity, muzzleSmokeSettings); } } } private void InterpolateSmoke(Vector3 lastCenterPos, Vector3 currentCenterPos, Vector3 initialVelocity, InterpolatedSmoke smokeSettings, float smokeSpawnChance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) InterpolateSmokeInternal(lastCenterPos, currentCenterPos, initialVelocity, smokeSettings, smokeSpawnChance); } private void InterpolateSmokeSpreadGroup(Vector3 lastCenterPos, Vector3 currentCenterPos, Vector3 initialVelocity, InterpolatedMuzzleSmoke smokeSettings, float smokeSpawnChance, int smokeCount, float smokeSpread) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) InterpolateSmokeInternal(lastCenterPos, currentCenterPos, initialVelocity, smokeSettings, smokeSpawnChance, smokeCount, smokeSpread); } private void InterpolateSmokeInternal(Vector3 lastCenterPos, Vector3 currentCenterPos, Vector3 initialVelocity, InterpolatedSmoke smokeSettings, float smokeSpawnChance, int smokeCount = 1, float smokeSpread = 0f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) float num = Vector3.Distance(currentCenterPos, lastCenterPos); if (smokeSettings.MaxInterpolationDistance > 0f && num > smokeSettings.MaxInterpolationDistance) { return; } int num2 = Mathf.RoundToInt(num * smokeSettings.InterpolationCountPerDistanceUnit); if (num2 == 0) { return; } float num3 = (float)num2 + 1f; float num4 = smokeCount; if (num4 > 1f) { num4 = Mathf.Max(1f, Mathf.Floor((float)smokeCount / 2f)); } for (int i = 1; i <= num2; i++) { if (smokeSpawnChance < 1f && Random.value > smokeSpawnChance) { continue; } float num5 = (float)i / num3; Vector3 val = Vector3.Lerp(lastCenterPos, currentCenterPos, num5); if (smokeSettings is InterpolatedMuzzleSmoke muzzleSmokeSettings) { for (int j = 0; (float)j < num4; j++) { SpawnSmokeRandomSpread(val, smokeSpread, initialVelocity, muzzleSmokeSettings); } } else { SpawnSmoke(val, initialVelocity, smokeSettings); } } } private void SpawnSmokeRandomSpread(Vector3 centerPosition, float smokeSpread, Vector3 initialVelocity, InterpolatedMuzzleSmoke muzzleSmokeSettings) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Vector3 randomWorldPosOffset = VectorUtils.GetRandomWorldPosOffset(Camera.main, (SpreadAxis)2, centerPosition, smokeSpread); initialVelocity *= Random.Range(muzzleSmokeSettings.MinfloatSpeed, muzzleSmokeSettings.MaxFloatSpeed); SpawnSmoke(randomWorldPosOffset, initialVelocity, muzzleSmokeSettings); } public void SpawnSmoke(Vector3 tracerPos, Vector3 initialVelocity, ISmokeSettings smokeSettings) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (!Active) { return; } EmitParams val = default(EmitParams); ((EmitParams)(ref val)).position = tracerPos; ((EmitParams)(ref val)).startLifetime = Random.Range(smokeSettings.MinLifetime, smokeSettings.MaxLifetime); ((EmitParams)(ref val)).startSize = Random.Range(smokeSettings.MinStartSize, smokeSettings.MaxStartSize); ((EmitParams)(ref val)).startColor = Color32.op_Implicit(new Color(1f, 1f, 1f, Random.Range(smokeSettings.MinAlpha, smokeSettings.MaxAlpha))); ((EmitParams)(ref val)).velocity = initialVelocity; EmitParams val2 = val; partSystem.Emit(val2, 1); if (MaxParticlesCountWarning >= 500) { if (partSystem.particleCount >= MaxParticlesCountWarning && canWarnHardLimitTime < Time.time) { canWarnHardLimitTime = Time.time + 4f; TimeLogger.Logger.LogWarning("Smoke particle system reached hard warning limit! " + $"({partSystem.particleCount}/{MaxParticlesCountWarning})", (LogCategories)268435456); } else if (partSystem.particleCount >= SoftParticleCountWarning && canWarnSoftLimitTime < Time.time) { canWarnSoftLimitTime = Time.time + 4f; TimeLogger.Logger.LogWarning("Smoke particle system reached soft warning limit! " + $"({partSystem.particleCount}/{MaxParticlesCountWarning})", (LogCategories)268435456); } } } private ParticleSystem CreateSmokeSystem(int maxParticles = 1000) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00ab: 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_00ba: 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_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) smokeEmitterObj = new GameObject("SmokeTracerEmitter"); GameObjectManager.GetGameObjectFrom(TargetObject.LocalGamePlayer, out var gameObject); if (Object.op_Implicit((Object)(object)gameObject)) { smokeEmitterObj.transform.parent = gameObject.transform; } ParticleSystem val = smokeEmitterObj.AddComponent(); MainModule main = val.main; ((MainModule)(ref main)).maxParticles = maxParticles; ((MainModule)(ref main)).loop = false; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(0f); EmissionModule emission = val.emission; ((EmissionModule)(ref emission)).enabled = false; ColorOverLifetimeModule colorOverLifetime = val.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val2 = new Gradient(); val2.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[3] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0.5f, 0.75f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val2); ShapeModule shape = val.shape; ((ShapeModule)(ref shape)).enabled = false; ParticleSystemRenderer component = ((Component)val).GetComponent(); component.renderMode = (ParticleSystemRenderMode)0; Material val3 = new Material(ShaderUtils.LegacyParticleShader.Value); Texture2D mainTexture = TextureUtils.GenerateCircle(32); val3.mainTexture = (Texture)(object)mainTexture; val3.color = Color.white; ((Renderer)component).material = val3; return val; } } public class VFX { private static GameObject hitmarkPrimitive; public static void SpawnTracerEffect(Material mat, float projectileSpeed, ITracerSettings tracerSettings, InterpolatedMuzzleSmoke muzzleSmokeSettings, Vector3 start, SingleTracerData tracerData, Light lightRef, SmokeManager smokeManager, GameObject muzzleFlashObj, bool animateTravel) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ShotgunEffectsBehaviour.Instance)) { TimeLogger.Logger.LogError("Tracers cant be spawned at this moment, the ShotgunEffectsBehaviour has not awaken yet.", (LogCategories)268435456); return; } if (!ShotgunEffectsBehaviour.GroupedTracers.TryGetValue(mat, out var value)) { value = new TracerGroupData(tracerSettings, projectileSpeed, muzzleSmokeSettings, start, lightRef, smokeManager, muzzleFlashObj, animateTravel); ShotgunEffectsBehaviour.GroupedTracers.Add(mat, value); } value.AddNewTracerEntry(tracerData); float time = Time.time; value.StartTracingTimers(time); float elapsedTime = time - value.StartLifetime; ShotgunEffectsBehaviour.Instance.ProcessTracer(elapsedTime, value, tracerData); } public static void SpawnImpactHitMark(HitMarkSpatial position, IImpactSettings impactSettings) { SpawnImpactHitMarkGroup(new HitMarkSpatial[1] { position }, impactSettings); } public static void SpawnImpactHitMarkGroup(HitMarkSpatial[] hitMarkSpatials, IImpactSettings impactSettings) { //IL_003e: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (hitMarkSpatials == null || hitMarkSpatials.Length == 0) { TimeLogger.Logger.LogError("Param impactPositions cant be null or empty.", (LogCategories)268435456); return; } if (!Object.op_Implicit((Object)(object)ShotgunEffectsBehaviour.Instance)) { TimeLogger.Logger.LogError("Impact hit marks cant be spawned at this moment, the ShotgunEffectsBehaviour has not awaken yet.", (LogCategories)268435456); return; } Color color = impactSettings.Color; Material val = CreateLegacyParticleMaterial(color); ImpactHitMarkHandler impactHitMarkHandler = new ImpactHitMarkHandler(Time.time, color, impactSettings, val); for (int i = 0; i < hitMarkSpatials.Length; i++) { GameObject val2 = CreateImpactHitMarkObject(hitMarkSpatials[i], impactSettings, val); if (Object.op_Implicit((Object)(object)val2)) { impactHitMarkHandler.AddNewImpactEntry(new HitMarkData(val2)); } } ShotgunEffectsBehaviour.GroupedImpacts.Add(impactHitMarkHandler); } private static GameObject CreateImpactHitMarkObject(HitMarkSpatial hit, IImpactSettings impactSettings, Material sharedMaterial = null) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00de: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)hitmarkPrimitive)) { hitmarkPrimitive = MeshUtils.CreateCubePrimitive("ImpactHitMark", 1f, 1f, 0.5f, true); if (!Object.op_Implicit((Object)(object)hitmarkPrimitive)) { TimeLogger.Logger.LogError("The hitmark primitive could not be created. Hitmarks wont show up.", (LogCategories)268435456); return null; } hitmarkPrimitive.SetActive(false); } GameObject obj = Object.Instantiate(hitmarkPrimitive); Vector3 val = hit.HitFaceRotation * (Vector3.forward * 0.006f); obj.transform.position = hit.Position + val; obj.transform.rotation = hit.HitFaceRotation; Transform transform = obj.transform; transform.localScale *= impactSettings.BaseSize; Renderer component = obj.GetComponent(); if (Object.op_Implicit((Object)(object)sharedMaterial)) { component.sharedMaterial = sharedMaterial; } else { component.sharedMaterial = CreateLegacyParticleMaterial(impactSettings.Color); } obj.SetActive(true); return obj; } public static void SpawnImpactSparksGroup(SparkInitialData[] sparkDataGroup, IImpactSettings impactSettings, int sparkCount = 4) { //IL_003e: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (sparkDataGroup == null || sparkDataGroup.Length == 0) { TimeLogger.Logger.LogError("Param sparkDataGroup cant be null or empty.", (LogCategories)268435456); return; } if (!Object.op_Implicit((Object)(object)ShotgunEffectsBehaviour.Instance)) { TimeLogger.Logger.LogError("Impact sparks cant be spawned at this moment, the ShotgunEffectsBehaviour has not awaken yet.", (LogCategories)268435456); return; } Color color = impactSettings.Color; Material val = CreateLegacyParticleMaterial(color); ImpactSparksHandler impactSparksHandler = new ImpactSparksHandler(Time.time, color, impactSettings, val); foreach (SparkInitialData sparkData in sparkDataGroup) { GameObject[] impactSparkObjs = SpawnImpactSparks(sparkData, impactSettings, sparkCount, val); impactSparksHandler.AddNewImpactEntry(new SparkData(sparkData, impactSparkObjs)); } ShotgunEffectsBehaviour.GroupedImpacts.Add(impactSparksHandler); } private static GameObject[] SpawnImpactSparks(SparkInitialData sparkData, IImpactSettings impactSettings, int sparkCount = 4, Material sharedMaterial = null) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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) Material val = (Material)(((object)sharedMaterial) ?? ((object)new Material(ShaderUtils.LegacyParticleShader.Value))); val.SetColor("_TintColor", impactSettings.Color); GameObject[] array = (GameObject[])(object)new GameObject[sparkCount]; for (int i = 0; i < sparkCount; i++) { Vector3 val2 = Random.onUnitSphere * 0.05f; GameObject val3 = (array[i] = MeshUtils.CreateQuadPrimitive("ImpactSpark", 1f, 1f, true)); val3.transform.position = sparkData.Position; val3.transform.rotation = Quaternion.LookRotation(val2); float num = Mathf.Max(sparkData.Distance / 10f, 1f); val3.transform.localScale = Vector3.one * impactSettings.BaseSize * num; val3.GetComponent().sharedMaterial = val; Rigidbody obj = val3.AddComponent(); obj.useGravity = false; float num2 = Random.Range(13f, 18f); obj.velocity = val2 * num2; } return array; } private static Material CreateLegacyParticleMaterial(Color color) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Material val = new Material(ShaderUtils.LegacyParticleShader.Value); val.SetColor("_TintColor", color); return val; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.FireEffects.Helpers.Model { public abstract class InterpolatedSmoke : ISmokeSettings, IInterpolatedParticle { public abstract float InterpolationCountPerDistanceUnit { get; } public abstract float MaxInterpolationDistance { get; } public abstract float MinStartSize { get; } public abstract float MaxStartSize { get; } public abstract float MinLifetime { get; } public abstract float MaxLifetime { get; } public abstract float MinAlpha { get; } public abstract float MaxAlpha { get; } public abstract Vector3 BaseVelocity { get; } public abstract float Spread { get; } } public abstract class InterpolatedMuzzleSmoke : InterpolatedSmoke, IMuzzleSmokeSettings, ISmokeSettings { public abstract float SmokeEffectTotalTime { get; } public abstract int MinSmokeParticles { get; } public abstract int MaxSmokeParticles { get; } public abstract float MinfloatSpeed { get; } public abstract float MaxFloatSpeed { get; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Definitions { public class ShotgunDefinition : IWeaponDefinition { public static ShotgunDefinition DefaultShotgunDefinition { get; } = new ShotgunDefinition(); public float RoundsPerSecond { get; } = 0.001f; public float SpreadAngle { get; } = 1.2f; public int ProjectileCount { get; } = 10; public int ProjectileMaxRange { get; } = 200; public float ProjectileSpeed { get; } = 800f; public ITracerSettings Tracers { get; } = new ShotgunTracerSettings(); public InterpolatedMuzzleSmoke MuzzleSmoke { get; } = new ShotgunTracerSettings.ShotgunMuzzleSmokeSettings(); } public class ShotgunTracerSettings : ITracerSettings { public class ShotgunTracerSmokeSettings : InterpolatedSmoke { public override float InterpolationCountPerDistanceUnit { get; } = 5f; public override float MaxInterpolationDistance { get; } = -1f; public override float MinStartSize { get; } = 0.014f; public override float MaxStartSize { get; } = 0.02f; public override float MinLifetime { get; } = 1.1f; public override float MaxLifetime { get; } = 1.5f; public override float MinAlpha { get; } = 0.32f; public override float MaxAlpha { get; } = 0.43f; public override Vector3 BaseVelocity { get; } = Vector3.forward * 0.25f; public override float Spread { get; } = 0.03f; } public class ShotgunMuzzleSmokeSettings : InterpolatedMuzzleSmoke { public override float MaxInterpolationDistance { get; } = -1f; public override float InterpolationCountPerDistanceUnit { get; } = 50f; public override float SmokeEffectTotalTime { get; } = 1.55f; public override float MinAlpha { get; } = 0.275f; public override float MaxAlpha { get; } = 0.39f; public override Vector3 BaseVelocity { get; } = Vector3.up; public override float Spread { get; } = 0.043f; public override int MinSmokeParticles { get; } = 3; public override int MaxSmokeParticles { get; } = 4; public override float MinStartSize { get; } = 0.032f; public override float MaxStartSize { get; } = 0.045f; public override float MinLifetime { get; } = 0.525f; public override float MaxLifetime { get; } = 0.6f; public override float MinfloatSpeed { get; } = 0.4f; public override float MaxFloatSpeed { get; } = 0.5f; } public class Spark : IImpactSettings { public Color Color { get; } = new Color(1f, 1f, 1f, 0.75f); public float BaseSize { get; } = 0.025f; public float FadeTime { get; } = 0.25f; public float MinFadeProgress { get; } = 0.5f; } public class HitMark : IImpactSettings { public Color Color { get; } = new Color(0.95f, 0.85f, 0.65f, 1f); public float BaseSize { get; } = 0.014f; public float FadeTime { get; } = 4.5f; public float MinFadeProgress { get; } } public Vector3 StartOffset { get; } = new Vector3(0f, 0f, 0.5f); public float LengthMultiplier { get; } = 1.6f; public float WidthStart { get; } = 0.009f; public float WidthEnd { get; } = 0.2f; public float MaxWidthDistance { get; } = 55f; public Color ColorStart { get; } = new Color(0.95f, 0.85f, 0.65f, 1f); public Color ColorEnd { get; } = new Color(0.9f, 0.75f, 0.5f, 1f); public float MuzzleFlashTime { get; } = 0.15f; public InterpolatedSmoke SmokeSettings { get; } = new ShotgunTracerSmokeSettings(); public IImpactSettings Sparks { get; } = new Spark(); public IImpactSettings HitMarks { get; } = new HitMark(); } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Definitions.Interfaces { public interface IWeaponDefinition { float RoundsPerSecond { get; } float SpreadAngle { get; } int ProjectileCount { get; } int ProjectileMaxRange { get; } float ProjectileSpeed { get; } ITracerSettings Tracers { get; } InterpolatedMuzzleSmoke MuzzleSmoke { get; } } public interface ITracerSettings { Vector3 StartOffset { get; } float LengthMultiplier { get; } float WidthStart { get; } float WidthEnd { get; } float MaxWidthDistance { get; } Color ColorStart { get; } Color ColorEnd { get; } float MuzzleFlashTime { get; } InterpolatedSmoke SmokeSettings { get; } IImpactSettings Sparks { get; } IImpactSettings HitMarks { get; } } public interface IInterpolatedParticle { float InterpolationCountPerDistanceUnit { get; } float MaxInterpolationDistance { get; } } public interface ISmokeSettings { float MinStartSize { get; } float MaxStartSize { get; } float MinLifetime { get; } float MaxLifetime { get; } float MinAlpha { get; } float MaxAlpha { get; } Vector3 BaseVelocity { get; } float Spread { get; } } public interface IMuzzleSmokeSettings : ISmokeSettings { float SmokeEffectTotalTime { get; } int MinSmokeParticles { get; } int MaxSmokeParticles { get; } float MinfloatSpeed { get; } float MaxFloatSpeed { get; } } public interface IImpactSettings { Color Color { get; } float BaseSize { get; } float FadeTime { get; } float MinFadeProgress { get; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs { public class EmployeeNPC : GenericNPC { public static readonly string QolNPC_GameObjectName = "SuperQolNPC_Data"; public static Dictionary AllEmployees; private uint _parentNetid; public uint ParentNetid { get { if (_parentNetid == 0) { _parentNetid = this.GetParentNetid(); } return _parentNetid; } } public EmployeeNPC() { AllEmployees = new Dictionary(); } public static GameObject CreateEmployeeGameObject() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown GameObject val = new GameObject(QolNPC_GameObjectName); val.SetActive(false); val.AddComponent(); val.AddComponent(); return val; } public static bool TryGetEmployeeFrom(GameObject employeeObj, out EmployeeNPC employeeNPC) { employeeNPC = null; if (!Object.op_Implicit((Object)(object)employeeObj)) { TimeLogger.Logger.LogDebug("Employee object cannot be null", (LogCategories)134217728); return false; } uint netId = employeeObj.GetComponent().netId; if (AllEmployees.TryGetValue(netId, out employeeNPC)) { if (Object.op_Implicit((Object)(object)employeeNPC)) { return true; } AllEmployees.Remove(netId); } else { UnityObjectExtensions.RemoveDeadValueReferences(AllEmployees); } GameObject val = UnityObjectExtensions.GameObject((Component)(object)employeeObj.transform.Find(QolNPC_GameObjectName)); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogDebug("Couldnt find GameObject \"" + QolNPC_GameObjectName + "\" " + $"as a children of {employeeObj}", (LogCategories)134217728); return false; } employeeNPC = val.GetComponent(); if (!Object.op_Implicit((Object)(object)employeeNPC)) { TimeLogger.Logger.LogError("Could not find EmployeeNPC component on the \"" + QolNPC_GameObjectName + "\" GameObject.", (LogCategories)134217728); return false; } AllEmployees.Add(netId, employeeNPC); return true; } public void MoveEmployeeTo(Vector3 destination, GameObject targetObject) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(destination, targetObject, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.NonReservable); } public void MoveEmployeeTo(Transform transformDestination, GameObject targetObject) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(transformDestination.position, targetObject, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.NonReservable); } public void MoveEmployeeTo(GameObject gameObjectDestination, GameObject targetObject) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(gameObjectDestination.transform.position, targetObject, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.NonReservable); } public void MoveSecurityAndScout(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(destination, null, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.NonReservable, scout: true); } public void MoveEmployeeToRestPosition() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(NPC_Manager.Instance.AttemptToGetRestPosition(), null, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.NonReservable); } public void MoveEmployeeToShelf(Vector3 destination, ProductShelfSlotInfo prodShelfTarget) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(destination, null, prodShelfTarget, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.ProdShelfSlot); } public void MoveEmployeeToStorage(Vector3 destination, StorageSlotInfo storageTarget) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(destination, null, storageTarget, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.StorageSlot); } public void MoveEmployeeToBox(GameObject gameObjectTarget) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) MoveEmployeeToBox(gameObjectTarget.transform.position, gameObjectTarget); } public void MoveEmployeeToBox(Vector3 destination, GameObject gameObjectTarget) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveEmployee(destination, gameObjectTarget, null, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType.GroundBox); } protected void MoveEmployee(Vector3 destination, GameObject gameObjectTarget, GenericShelfSlotInfo shelfTarget, SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking.TargetType targetType, bool scout = false) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (scout) { MoveToScout(destination); } else if (Object.op_Implicit((Object)(object)gameObjectTarget)) { MoveTo(destination, gameObjectTarget.transform.position); } else if (shelfTarget != null && shelfTarget.ExtraData.Position != Vector3.zero) { MoveTo(destination, shelfTarget.ExtraData.Position); } else { MoveTo(destination); } EmployeeTargetReservation.DeleteAllNPCTargets(ParentNetid); if (targetType != 0) { EmployeeTargetReservation.AddTargetReservation(ParentNetid, gameObjectTarget, shelfTarget, targetType); } } public void StartLookProcess(RotationSpeedMode rotationMode) { ((Component)this).GetComponent().StartLookTowardsProcess(rotationMode); } public void SetLookTowardsPosition(Vector3 lookPosition, RotationSpeedMode rotationMode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Component)this).GetComponent().SetLookTowardsPosition(lookPosition, rotationMode); } } public static class EmployeeNPC_Extension { public static uint GetParentNetid(this EmployeeNPC employeeNPC) { return ((Component)((Component)employeeNPC).transform.parent).GetComponent().netId; } } public enum NPCType { Dummy, Employee, Customer } public abstract class GenericNPC : MonoBehaviour { public Vector3 LastDestinationSet => ((Component)this).GetComponent().LastDestinationSet; protected void MoveTo(Vector3 destination, Vector3 targetObjectPosition) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) ((Component)this).GetComponent().MoveTo(destination, targetObjectPosition); } protected void MoveTo(Vector3 destination) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Component)this).GetComponent().MoveTo(destination); } protected void MoveToScout(Vector3 destination) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Component)this).GetComponent().MoveToScout(destination); } public static void AddSuperQolNpcObjects(GameObject npcObj, NPCType npcType) { if ((Object)(object)npcObj == (Object)null) { TimeLogger.Logger.LogFatal("The parameter npcObj is null", (LogCategories)134217728); return; } switch (npcType) { case NPCType.Dummy: throw new NotImplementedException("Dummy NPCs are not implemented."); case NPCType.Employee: { GameObject val = EmployeeNPC.CreateEmployeeGameObject(); val.transform.SetParent(npcObj.transform); val.SetActive(true); break; } case NPCType.Customer: throw new NotImplementedException("Customer NPCs are not implemented."); default: TimeLogger.Logger.LogFatal($"Unknown NPC type: {npcType}", (LogCategories)134217728); break; } } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Movement { public enum RotationSpeedMode { SecurityScout, EmployeeTarget } public class LookRotationHandler { private enum MotionType { None, LookAt } private enum ScoutMode { None, ScoutModePending, Scouting } private class RotationSpeedSettings { public float MaxRotationSpeed { get; } public float SmoothTime { get; } public RotationSpeedSettings(float maxRotationSpeed, float smoothTime) { MaxRotationSpeed = maxRotationSpeed; SmoothTime = smoothTime; } } private static readonly float ScoutIntervalSeconds = 9.5f; private static readonly float ScoutIntervalVariance = 4f; private static readonly float MinimumRandomTurnAngle = 30f; private static readonly float MaximumRandomTurnAngle = 170f; private static readonly Dictionary rotationSettings = new Dictionary { { RotationSpeedMode.SecurityScout, new RotationSpeedSettings(125f, 0.35f) }, { RotationSpeedMode.EmployeeTarget, new RotationSpeedSettings(300f, 0.15f) } }; private MotionType currentMotion; private ScoutMode currentScoutMode; private Transform baseTransform; private Vector3? previousMoveTargetObject; private Quaternion targetRotation; private RotationSpeedSettings rotateSettings; private float currentTurnVelocity; private float nextScoutTime = -1f; public bool IsRotationPending => currentMotion == MotionType.LookAt; public LookRotationHandler(Transform baseTransform) { this.baseTransform = baseTransform; } public void StartLookTowardsProcess(RotationSpeedMode rotationMode) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (currentScoutMode != 0) { currentScoutMode = ScoutMode.Scouting; } else if (previousMoveTargetObject.HasValue) { SetLookTowardsPosition(previousMoveTargetObject.Value, rotationMode); } } public void SetLookTowardsPosition(Vector3 lookPosition, RotationSpeedMode rotationMode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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) Vector3 val = lookPosition - baseTransform.position; Vector3 normalized = ((Vector3)(ref val)).normalized; Quaternion val2 = Quaternion.LookRotation(normalized); SetLookRotationParams(normalized, val2, rotationMode); } public void LookAtRandomPosition(RotationSpeedMode rotationMode) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((((Random.Range(0, 2) == 0) ? 1 : (-1)) == 1) ? Vector3.up : Vector3.down); float num = Random.Range(MinimumRandomTurnAngle, MaximumRandomTurnAngle); Quaternion val2 = Quaternion.Euler(val * num) * baseTransform.rotation; SetLookRotationParams(val, val2, rotationMode); } public void SetLookRotationParams(Vector3 yawVector, Quaternion targetRotation, RotationSpeedMode rotationMode) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!rotationSettings.TryGetValue(rotationMode, out rotateSettings)) { TimeLogger.Logger.LogFatal($"Rotation speed mode {rotationMode} " + "not found in rotation settings.", (LogCategories)134217728); return; } this.targetRotation = targetRotation; currentTurnVelocity = 0f; currentMotion = MotionType.LookAt; } public void RotateTowardsTarget(float deltaTime) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_006c: 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) Quaternion rotation = baseTransform.rotation; float num = Mathf.SmoothDampAngle(((Quaternion)(ref rotation)).eulerAngles.y, ((Quaternion)(ref targetRotation)).eulerAngles.y, ref currentTurnVelocity, rotateSettings.SmoothTime, rotateSettings.MaxRotationSpeed, deltaTime); baseTransform.rotation = Quaternion.Euler(0f, num, 0f); if (baseTransform.rotation == targetRotation) { currentMotion = MotionType.None; } } public void MoveOrderCalled(Vector3? targetObjectPosition, bool toScout) { previousMoveTargetObject = targetObjectPosition; currentMotion = MotionType.None; currentScoutMode = (toScout ? ScoutMode.ScoutModePending : ScoutMode.None); } public bool IsScoutTime() { if (currentScoutMode == ScoutMode.Scouting && (nextScoutTime == -1f || nextScoutTime <= Time.fixedTime)) { nextScoutTime = Time.fixedTime + ScoutIntervalSeconds + Random.Range(0f - ScoutIntervalVariance, ScoutIntervalVariance); return true; } return false; } } public class NPC_Movement : MonoBehaviour { private LookRotationHandler lookHandler; public Vector3 LastDestinationSet { get; private set; } public void Awake() { lookHandler = new LookRotationHandler(((Component)this).transform.parent); } public void FixedUpdate() { if (lookHandler.IsScoutTime()) { lookHandler.LookAtRandomPosition(RotationSpeedMode.SecurityScout); } if (lookHandler.IsRotationPending) { lookHandler.RotateTowardsTarget(Time.fixedDeltaTime); } } public void MoveTo(Vector3 destination, Vector3 targetObjectPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) MoveToInternal(destination, toScout: false, targetObjectPosition); } public void MoveTo(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveToInternal(destination, toScout: false); } public void MoveToScout(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) MoveToInternal(destination, toScout: true); } private void MoveToInternal(Vector3 destination, bool toScout, Vector3? targetObjectPosition = null) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent component = ((Component)((Component)this).gameObject.transform.parent).GetComponent(); LastDestinationSet = destination; component.destination = destination; lookHandler.MoveOrderCalled(targetObjectPosition, toScout); } public void SetLookTowardsPosition(Vector3 lookPosition, RotationSpeedMode rotationMode) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) lookHandler.SetLookTowardsPosition(lookPosition, rotationMode); } public void StartLookTowardsProcess(RotationSpeedMode rotationMode) { lookHandler.StartLookTowardsProcess(rotationMode); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler { public class AutoModeProcessor { private const string jobSchedulerHotkeyGroup = "jobSchedHotkeys"; private bool forceAutoModeRefresh; public static AutoModeProcessor Instance { get; private set; } public AutoModeData AutoModeData { get; set; } private AutoModeProcessor() { ModConfig.Instance.CustomEmployeeWaitTarget.SettingChanged += ForceUpdateAutoMode; ModConfig.Instance.CustomCustomerWaitTarget.SettingChanged += ForceUpdateAutoMode; ModConfig.Instance.CustomMinimumFrequencyMult.SettingChanged += ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyMult.SettingChanged += ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyReduction.SettingChanged += ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyIncrease.SettingChanged += ForceUpdateAutoMode; if (Plugin.IsSolutionInDebugMode && ModConfig.Instance.EnabledDevMode.Value) { UIPanelHandler.LoadUIPanel(); if (WorldState.IsWorldLoaded) { InitializeWithGameWorld(GameWorldEvent.WorldLoaded); } WorldState.OnGameWorldChange += InitializeWithGameWorld; } } public static void Initialize() { if (Instance == null) { Instance = new AutoModeProcessor(); } } private void ForceUpdateAutoMode(object sender, EventArgs e) { if (WorldState.IsWorldLoaded) { forceAutoModeRefresh = true; } } public static void Destroy() { if (Instance != null) { if (UIPanelHandler.IsPanelLoaded) { UIPanelHandler.DestroyPerformancePanel(); ((InputDetection)InputManagerSMT.Instance).RemoveHotkeyGroup("jobSchedHotkeys"); WorldState.OnGameWorldChange -= Instance.InitializeWithGameWorld; } ModConfig.Instance.CustomEmployeeWaitTarget.SettingChanged -= Instance.ForceUpdateAutoMode; ModConfig.Instance.CustomCustomerWaitTarget.SettingChanged -= Instance.ForceUpdateAutoMode; ModConfig.Instance.CustomMinimumFrequencyMult.SettingChanged -= Instance.ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyMult.SettingChanged -= Instance.ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyReduction.SettingChanged -= Instance.ForceUpdateAutoMode; ModConfig.Instance.CustomMaximumFrequencyIncrease.SettingChanged -= Instance.ForceUpdateAutoMode; } } public void SetAutoModeData(EnumJobFrequencyMultMode jobFreqMode) { if (AutoModeData == null || AutoModeData.JobFreqMode != jobFreqMode || forceAutoModeRefresh) { forceAutoModeRefresh = false; AutoModeData = GetAutoModeData(jobFreqMode); UIPanelHandler.SetFreqStepValues(new float[2] { AutoModeData.IncreaseStep, AutoModeData.DecreaseStep }); } } private static AutoModeData GetAutoModeData(EnumJobFrequencyMultMode jobFreqMode) { return jobFreqMode switch { EnumJobFrequencyMultMode.Auto_Performance => new PerformanceMode(), EnumJobFrequencyMultMode.Auto_Balanced => new BalancedMode(), EnumJobFrequencyMultMode.Auto_Aggressive => new AggressiveMode(), EnumJobFrequencyMultMode.Auto_Custom => new CustomMode(), _ => null, }; } private void InitializeWithGameWorld(GameWorldEvent gameEvent) { if (gameEvent == GameWorldEvent.WorldLoaded) { UIPanelHandler.InitializePerformancePanel(new float[2]); UIPanelHandler.ShowUIPanel(); InputManagerSMT.Instance.TryAddHotkey("jobSchedDebugPanelRiseCycleUp", (KeyCode)277, (InputState)2, HotkeyActiveContext.WorldLoaded, delegate { SetAndUpdatePerformanceUI(increase: true, rise: true); }, "jobSchedHotkeys"); InputManagerSMT.Instance.TryAddHotkey("jobSchedDebugPanelRiseCycleDown", (KeyCode)127, (InputState)2, HotkeyActiveContext.WorldLoaded, delegate { SetAndUpdatePerformanceUI(increase: false, rise: true); }, "jobSchedHotkeys"); InputManagerSMT.Instance.TryAddHotkey("jobSchedDebugPanelDropCycleUp", (KeyCode)278, (InputState)2, HotkeyActiveContext.WorldLoaded, delegate { SetAndUpdatePerformanceUI(increase: true, rise: false); }, "jobSchedHotkeys"); InputManagerSMT.Instance.TryAddHotkey("jobSchedDebugPanelDropCycleDown", (KeyCode)279, (InputState)2, HotkeyActiveContext.WorldLoaded, delegate { SetAndUpdatePerformanceUI(increase: false, rise: false); }, "jobSchedHotkeys"); } } private void SetAndUpdatePerformanceUI(bool increase, bool rise) { if (AutoModeData == null) { return; } if (rise) { if (increase) { AutoModeData.IncreaseRiseCyclePct(); } else { AutoModeData.DecreaseRiseCyclePct(); } } else if (increase) { AutoModeData.IncreaseDropCyclePct(); } else { AutoModeData.DecreaseDropCyclePct(); } UIPanelHandler.SetFreqStepValues(new float[2] { AutoModeData.IncreaseStep, AutoModeData.DecreaseStep }); } } public enum EnumJobFrequencyMultMode { [Description("Disabled")] Disabled, [Description("Auto - Prioritize system performance")] Auto_Performance, [Description("Auto - Balanced")] Auto_Balanced, [Description("Auto - Prioritize NPC responsiveness")] Auto_Aggressive, [Description("Auto - Custom dynamic multiplier")] Auto_Custom } public static class JobSchedulerManager { private const int LoopMultRounding = 3; private static SchedulerSessionVars sessionVars; private static bool IsEmployeeModuleEnabled; private static bool IsCustomerModuleEnabled; public static bool IsJobSchedulerActive { get; private set; } public static event Action OnNewJobFrequencyMultiplier; public static void InitializeJobSchedulerEvents() { IsEmployeeModuleEnabled = ModConfig.Instance.EnableEmployeeChanges.Value; IsCustomerModuleEnabled = ModConfig.Instance.EnableCustomerChanges.Value; WorldState.OnGameWorldChange += HandleWorldEvents; } private static void HandleWorldEvents(GameWorldEvent gameEvent) { switch (gameEvent) { case GameWorldEvent.LoadingWorld: LoadingWorldInit(); break; case GameWorldEvent.WorldLoaded: if (IsJobSchedulerActive) { FrequencyMult_Display.AllowDisplay(); } break; case GameWorldEvent.QuitOrMenu: FrequencyMult_Display.Destroy(); DestroyJobScheduler(); break; } } private static void LoadingWorldInit() { if (WorldState.CurrentOnlineMode == GameOnlineMode.Host) { sessionVars = new SchedulerSessionVars(); FrequencyMult_Display.Initialize(); IsJobSchedulerActive = true; } EmployeeTargetReservation.ClearAll(); } public static void DisableJobScheduler() { WorldState.OnGameWorldChange -= HandleWorldEvents; DestroyJobScheduler(); } private static void DestroyJobScheduler() { if (IsJobSchedulerActive) { IsJobSchedulerActive = false; sessionVars.DestroyAutoModeData(); sessionVars = null; } } private static JobModeType GetJobModeTypeSetting(EnumJobFrequencyMultMode jobFreqMode) { switch (jobFreqMode) { case EnumJobFrequencyMultMode.Disabled: return JobModeType.Other; case EnumJobFrequencyMultMode.Auto_Performance: case EnumJobFrequencyMultMode.Auto_Balanced: case EnumJobFrequencyMultMode.Auto_Aggressive: case EnumJobFrequencyMultMode.Auto_Custom: return JobModeType.Automatic; default: return JobModeType.Invalid; } } public static void ProcessNPCJobs(NPC_Manager __instance, bool canEmployeesDoSomething, bool canCustomersDoSomething) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (CheckScheduler()) { FixedTimes fixedTimeCachedValues = CachedTimeValues.GetFixedTimeCachedValues(); if (++sessionVars.CurrentFixedUpdateCounter >= ((FixedTimes)(ref fixedTimeCachedValues)).fixedUpdateCycleMax || sessionVars.InitialLoop) { _ = sessionVars.InitialLoop; StartNewFixedUpdateCycle(((FixedTimes)(ref fixedTimeCachedValues)).fixedDeltaTime); } double maxAllowedProcessingTime = GetMaxAllowedProcessingTime(sessionVars.CurrentCycleJobFreqMode); if (canEmployeesDoSomething) { ProcessNpcJobs(__instance, NPCType.Employee, maxAllowedProcessingTime, fixedTimeCachedValues); } if (canCustomersDoSomething) { ProcessNpcJobs(__instance, NPCType.Customer, maxAllowedProcessingTime, fixedTimeCachedValues); } } } public static void ProcessNpcJobs(NPC_Manager __instance, NPCType npcType, double maxProcessingTimeMillis, FixedTimes fixedTime) { StopwatchDiag processTime = StopwatchDiag.StartNew(); int loopCounter = 0; int workSkipCounter = 0; GameObject npcParentObj = SchedulerSessionVars.GetNpcParentObj(__instance, npcType); NpcLoopData npcLoopData = sessionVars.GetNpcLoopData(npcType); NpcWaitTimers npcWaitTimers = sessionVars.GetNpcWaitTimers(npcType); int childCount = npcParentObj.transform.childCount; int workSkipLimit = Math.Min(npcParentObj.transform.childCount, ((FixedTimes)(ref fixedTime)).fixedUpdateCycleMax); bool isLoopCounted = true; while (ShouldDoJob(ref loopCounter, ref workSkipCounter, npcLoopData, isLoopCounted, workSkipLimit)) { isLoopCounted = NpcWaitTimeAndJobControl(__instance, npcType, npcLoopData.CurrentNpcId, npcParentObj, npcWaitTimers, sessionVars.CurrentCycleJobModeType); if (++npcLoopData.CurrentNpcId >= childCount) { npcLoopData.CurrentNpcId = 0; } if (!IsProcessWithinTime(processTime, sessionVars.CurrentCycleJobFreqMode, maxProcessingTimeMillis, npcType)) { break; } } } private static bool CheckScheduler() { if (!IsJobSchedulerActive) { if (sessionVars.ShowSchedulerInactiveError) { TimeLogger.Logger.LogWarningShowInGame("The Job Scheduler is not currently active. Employees and customer will not work.", (LogCategories)16777216); sessionVars.ShowSchedulerInactiveError = false; } return false; } return true; } private static void StartNewFixedUpdateCycle(float fixedDeltaTime) { sessionVars.CurrentCycleJobFreqMode = ModConfig.Instance.NpcJobFrequencyMode.Value; sessionVars.CurrentCycleJobModeType = GetJobModeTypeSetting(sessionVars.CurrentCycleJobFreqMode); if (sessionVars.CurrentCycleJobModeType == JobModeType.Automatic) { if (IsEmployeeModuleEnabled) { sessionVars.InitializeNpcVarsFor(NPCType.Employee); } if (IsCustomerModuleEnabled) { sessionVars.InitializeNpcVarsFor(NPCType.Customer); } } else { if (sessionVars.CurrentCycleJobModeType != JobModeType.Other) { throw new NotSupportedException(sessionVars.CurrentCycleJobModeType.ToString()); } sessionVars.DestroyAutoModeData(); } sessionVars.Employee.LoopData.LoopMultiplierCycle = GetLoopMultiplier(sessionVars.CurrentCycleJobFreqMode, sessionVars.CurrentCycleJobModeType, NPCType.Employee, sessionVars.Employee, fixedDeltaTime); sessionVars.Customer.LoopData.LoopMultiplierCycle = GetLoopMultiplier(sessionVars.CurrentCycleJobFreqMode, sessionVars.CurrentCycleJobModeType, NPCType.Customer, sessionVars.Customer, fixedDeltaTime); JobSchedulerManager.OnNewJobFrequencyMultiplier?.Invoke(sessionVars.Employee.LoopData.LoopMultiplierCycle, sessionVars.Customer.LoopData.LoopMultiplierCycle); sessionVars.CurrentFixedUpdateCounter = 0; sessionVars.InitialLoop = false; } private static float GetLoopMultiplier(EnumJobFrequencyMultMode jobFreqMode, JobModeType jobModeType, NPCType npcType, NpcData npcData, float fixedDeltaTime) { return (float)Math.Round(jobModeType switch { JobModeType.Other => 1f, JobModeType.Automatic => npcData.IsJobSchedEnabled ? npcData.JobSchedProcessor.CalculateNextJobFreqMultiplier(jobFreqMode, npcType, npcData.WaitTimers, fixedDeltaTime) : 0f, JobModeType.Invalid => throw new InvalidOperationException("The job frequency mode hasnt been set."), _ => throw new NotImplementedException($"The job frequency mode \"{jobModeType}\" is not implemented."), }, 3); } private static bool NpcWaitTimeAndJobControl(NPC_Manager __instance, NPCType npcType, int npcIndex, GameObject npcParentObj, NpcWaitTimers npcWaitTimers, JobModeType currentCycleJobMode) { if (npcIndex >= npcParentObj.transform.childCount) { return false; } GameObject gameObject = ((Component)npcParentObj.transform.GetChild(npcIndex)).gameObject; NPC_Info component = gameObject.GetComponent(); bool flag = true; try { switch (npcType) { case NPCType.Employee: flag = EmployeeJobAIPatch.EmployeeNPCControl(__instance, gameObject, component); break; case NPCType.Customer: __instance.CustomerNPCControl(npcIndex); break; } } catch (Exception ex) { TimeLogger.Logger.LogExceptionWithMessage("Exception while processing job for " + $"{npcType} npc with id {npcIndex}.", ex, (LogCategories)134217728); } if (currentCycleJobMode == JobModeType.Automatic) { npcWaitTimers.StartTimer(((NetworkBehaviour)component).netId, flag); } return flag; } private static bool ShouldDoJob(ref int loopCounter, ref int workSkipCounter, NpcLoopData npcLoopData, bool isLoopCounted, int workSkipLimit) { if (!isLoopCounted) { if (++workSkipCounter > workSkipLimit) { workSkipCounter = 0; return false; } return true; } bool result = false; if (loopCounter < (int)npcLoopData.LoopMultiplierCycle) { result = true; } else if (!NumberExtensionMethods.IsInteger(npcLoopData.LoopMultiplierCycle)) { npcLoopData.LoopDecimalSurplus += npcLoopData.LoopMultiplierCycle % (float)Math.Max((int)npcLoopData.LoopMultiplierCycle, 1); if (npcLoopData.LoopDecimalSurplus >= 1f) { npcLoopData.LoopDecimalSurplus--; result = true; } } loopCounter++; return result; } private static double GetMaxAllowedProcessingTime(EnumJobFrequencyMultMode jobFreqMode) { return jobFreqMode switch { EnumJobFrequencyMultMode.Auto_Performance => PerformanceMode.MaxAllowedProcessingTime, EnumJobFrequencyMultMode.Auto_Balanced => BalancedMode.MaxAllowedProcessingTime, EnumJobFrequencyMultMode.Auto_Aggressive => AggressiveMode.MaxAllowedProcessingTime, EnumJobFrequencyMultMode.Auto_Custom => CustomMode.MaxAllowedProcessingTime, _ => -1f, }; } private static bool IsProcessWithinTime(StopwatchDiag processTime, EnumJobFrequencyMultMode jobFreqMode, double MaxNpcProcessingTimeMillis, NPCType npcType) { if (jobFreqMode == EnumJobFrequencyMultMode.Disabled) { return true; } if (MaxNpcProcessingTimeMillis <= 0.0) { return true; } if (!WorldState.IsWorldLoaded) { return false; } if (processTime.ElapsedMillisecondsPrecise >= MaxNpcProcessingTimeMillis) { if (!sessionVars.ProcessLimitCounter.Value.TryIncreaseCounter()) { string text = ((jobFreqMode == EnumJobFrequencyMultMode.Auto_Custom) ? ("It is recommended to adjust the settings in the \"" + ((ConfigEntryBase)ModConfig.Instance.CustomEmployeeWaitTarget).Definition.Section + "\" section.") : ((sessionVars.CurrentCycleJobModeType != JobModeType.Automatic) ? ("It is recommended to select a \"" + ((ConfigEntryBase)ModConfig.Instance.NpcJobFrequencyMode).Definition.Key + "\" in the settings.") : ("It is recommended to select a different \"" + ((ConfigEntryBase)ModConfig.Instance.NpcJobFrequencyMode).Definition.Key + "\" in the settings."))); string text2 = $"Processing {npcType} actions is taking too much time and its " + "being automatically limited by SuperQoLity to improve performance. "; bool flag = ModConfig.Instance.EnabledDevMode.Value && !sessionVars.ShowInGameProcessTimeExceededError; TimeLogger.Logger.Log((LogTier)4, text2 + text, (LogCategories)4, flag); if (flag) { sessionVars.ShowInGameProcessTimeExceededError = true; } } return false; } return true; } } public class JobSchedulerProcessor { private FrequencyTrendCalculation freqTrendCalc; private float lastAvgWaitTime; private float lastJobFreqMult; public JobSchedulerProcessor() { lastAvgWaitTime = -1f; freqTrendCalc = new FrequencyTrendCalculation(); AutoModeProcessor.Initialize(); } public float CalculateNextJobFreqMultiplier(EnumJobFrequencyMultMode jobFreqMode, NPCType npcType, NpcWaitTimers npcWaitTimers, float fixedDeltaTime) { AutoModeProcessor.Instance.SetAutoModeData(jobFreqMode); float num = npcWaitTimers.CalculateAvgWaitTimesAndReset(); float calculatedJobFreqMultiplier = GetCalculatedJobFreqMultiplier(num, jobFreqMode, fixedDeltaTime, npcType); UIPanelHandler.AddNewHistoricValue(num, calculatedJobFreqMultiplier); lastAvgWaitTime = num; lastJobFreqMult = calculatedJobFreqMultiplier; return calculatedJobFreqMultiplier; } private float GetCalculatedJobFreqMultiplier(float averageWaitTimeMillis, EnumJobFrequencyMultMode jobFreqMode, float fixedDeltaTime, NPCType npcType) { AutoModeData autoModeData = AutoModeProcessor.Instance.AutoModeData; if (lastAvgWaitTime == -1f) { return autoModeData.DefaultFrequencyMult; } float num = freqTrendCalc.CalculateJobFreqStepValue(averageWaitTimeMillis, lastAvgWaitTime, lastJobFreqMult, fixedDeltaTime, autoModeData, npcType); float jobFreqMultiplier = lastJobFreqMult + num; return autoModeData.Clamp(jobFreqMultiplier); } } public enum JobModeType { Invalid, Automatic, Other } public class SchedulerSessionVars { public Lazy> ProcessLimitCounter { get; set; } public bool InitialLoop { get; set; } public int CurrentFixedUpdateCounter { get; set; } public EnumJobFrequencyMultMode CurrentCycleJobFreqMode { get; set; } public JobModeType CurrentCycleJobModeType { get; set; } public bool ShowSchedulerInactiveError { get; set; } public bool ShowInGameProcessTimeExceededError { get; set; } public NpcData Employee { get; private set; } public NpcData Customer { get; private set; } public SchedulerSessionVars() { ProcessLimitCounter = new Lazy>((Func>)(() => new PeriodicTimeLimitedCounter(true, 30, 30000.0, true, true))); Employee = new NpcData(); Customer = new NpcData(); CurrentFixedUpdateCounter = 0; CurrentCycleJobFreqMode = EnumJobFrequencyMultMode.Disabled; CurrentCycleJobModeType = JobModeType.Invalid; InitialLoop = true; ShowSchedulerInactiveError = true; ShowInGameProcessTimeExceededError = true; } public void InitializeNpcVarsFor(NPCType npcType) { switch (npcType) { case NPCType.Employee: Employee.InitializeAutoModeData(); break; case NPCType.Customer: Customer.InitializeAutoModeData(); break; } } public void DestroyAutoModeData() { AutoModeProcessor.Destroy(); Employee?.DestroyAutoModeData(); Customer?.DestroyAutoModeData(); } public static GameObject GetNpcParentObj(NPC_Manager __instance, NPCType npcType) { return (GameObject)(npcType switch { NPCType.Employee => __instance.employeeParentOBJ, NPCType.Customer => __instance.customersnpcParentOBJ, _ => throw new NotImplementedException(npcType.ToString()), }); } public NpcLoopData GetNpcLoopData(NPCType npcType) { return npcType switch { NPCType.Employee => Employee.LoopData, NPCType.Customer => Customer.LoopData, _ => throw new NotImplementedException(npcType.ToString()), }; } public NpcWaitTimers GetNpcWaitTimers(NPCType npcType) { return npcType switch { NPCType.Employee => Employee.WaitTimers, NPCType.Customer => Customer.WaitTimers, _ => throw new NotImplementedException(npcType.ToString()), }; } } public class NpcData { public JobSchedulerProcessor JobSchedProcessor { get; set; } public NpcWaitTimers WaitTimers { get; set; } public NpcLoopData LoopData { get; set; } public bool IsJobSchedEnabled { get; private set; } public NpcData() { LoopData = new NpcLoopData(); } public void DestroyAutoModeData() { JobSchedProcessor = null; WaitTimers = null; } public void InitializeAutoModeData() { if (JobSchedProcessor == null) { JobSchedulerProcessor jobSchedulerProcessor2 = (JobSchedProcessor = new JobSchedulerProcessor()); } IsJobSchedEnabled = true; if (WaitTimers == null) { NpcWaitTimers npcWaitTimers2 = (WaitTimers = new NpcWaitTimers()); } } } public class NpcLoopData { public int CurrentNpcId { get; set; } public float LoopDecimalSurplus { get; set; } public float LoopMultiplierCycle { get; set; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.Helpers { public class FrequencyTrendCalculation { private static readonly int MaxAvgTimePoint = 750; private readonly int MaxAvgTimePointSquared; private readonly float DampeningBufferMult; private float coefficientCached; public FrequencyTrendCalculation() { MaxAvgTimePointSquared = MaxAvgTimePoint * MaxAvgTimePoint; DampeningBufferMult = 0.15f; coefficientCached = -1f; } public float CalculateJobFreqStepValue(float averageWaitTimeMillis, float lastAvgWaitTime, float lastJobFreqMult, float fixedDeltaTime, AutoModeData autoModeData, NPCType npcType) { float num = fixedDeltaTime * 1000f + 5f; float num2; if (autoModeData.AvgWaitTargetFromNpcType(npcType) >= 0f) { num2 = autoModeData.AvgEmployeeWaitTargetMillis; } else { num2 = num; num = 0f; } bool flag = averageWaitTimeMillis - num2 <= 0f; if ((flag && lastJobFreqMult <= autoModeData.MinFreqMult) || (!flag && lastJobFreqMult >= autoModeData.MaxFreqMult)) { return 0f; } float num3; float num4; if (flag) { num3 = CalculateStrengthMultiplier(averageWaitTimeMillis, num, num2, num2, inversed: true); num4 = autoModeData.DecreaseStep; } else { num3 = CalculateStrengthMultiplierCachedMax(averageWaitTimeMillis, num2); num4 = autoModeData.IncreaseStep; } float num5 = CalculateDampening(flag, averageWaitTimeMillis, num2, lastAvgWaitTime, num, MaxAvgTimePoint); return num4 * num3 * num5; } private float CalculateStrengthMultiplierCachedMax(float avgTimeTargetDiff, float avgWaitTimeTarget) { return CalculateStrengthMultiplier(avgTimeTargetDiff, avgWaitTimeTarget, avgWaitTimeTarget, MaxAvgTimePoint, inversed: false, saveCoefficient: true, coefficientCached, MaxAvgTimePointSquared); } private float CalculateStrengthMultiplier(float value, float Y_valueAtStartPoint, float Y_ValueAt_X_Intersect, float maxPointX, bool inversed = false, bool saveCoefficient = false, float coefficient = float.MinValue, float maxAvgTimePointSquared = float.MinValue) { if (maxAvgTimePointSquared == float.MinValue) { maxAvgTimePointSquared = maxPointX * maxPointX; } if (coefficient == float.MinValue) { coefficient = maxAvgTimePointSquared / (1f - Y_valueAtStartPoint / maxPointX) - maxAvgTimePointSquared; if (saveCoefficient) { coefficientCached = coefficient; } } float num = ((!inversed) ? 1 : (-1)); return value * value * num / (maxAvgTimePointSquared + coefficient) + Y_ValueAt_X_Intersect / maxPointX; } private float CalculateDampening(bool isAvgWaitBelowTarget, float averageWaitTimeMillis, float avgWaitTimeTarget, float lastAvgWaitTime, float minimumBaseline, float maxAvgTimePoint) { bool flag = false; float result = 1f; float num = (isAvgWaitBelowTarget ? maxAvgTimePoint : minimumBaseline); float num2 = avgWaitTimeTarget + (num - avgWaitTimeTarget) * DampeningBufferMult; if ((!isAvgWaitBelowTarget) ? (lastAvgWaitTime < num2) : (lastAvgWaitTime > num2)) { float num3 = 0.25f / (maxAvgTimePoint - minimumBaseline); result = 1f - num3 * Math.Abs(lastAvgWaitTime - averageWaitTimeMillis); } return result; } } public class NpcWaitTimers { private Dictionary waitTimers; private object syncLock; private double totalWaitElapsedMillis; private int totalHits; public NpcWaitTimers() { waitTimers = new Dictionary(); syncLock = new object(); } public void StartTimer(uint netId, bool includeResults) { if (waitTimers.ContainsKey(netId)) { UnityTimeStopwatch val = waitTimers[netId]; lock (syncLock) { if (val.IsRunning) { val.Stop(); if (includeResults) { totalWaitElapsedMillis += val.ElapsedMillisecondsPrecise; totalHits++; } } val.Restart(); return; } } waitTimers.Add(netId, UnityTimeStopwatch.StartNew()); } public float CalculateAvgWaitTimesAndReset() { double num = 0.0; lock (syncLock) { if (totalWaitElapsedMillis > 0.0 && totalHits > 0) { num = (float)totalWaitElapsedMillis / (float)totalHits; } totalWaitElapsedMillis = 0.0; totalHits = 0; } return (float)num; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.AutoMode { public abstract class AutoModeData { private const float StepChange = 0.01f; public EnumJobFrequencyMultMode JobFreqMode { get; init; } public float DefaultFrequencyMult { get; protected set; } public float AvgEmployeeWaitTargetMillis { get; init; } public float AvgCustomerWaitTargetMillis { get; init; } public float MinFreqMult { get; protected set; } public float MaxFreqMult { get; protected set; } public float DecreaseStep { get; protected set; } public float IncreaseStep { get; protected set; } public void IncreaseRiseCyclePct() { IncreaseStep += 0.01f; } public void DecreaseRiseCyclePct() { IncreaseStep -= 0.01f; } public void IncreaseDropCyclePct() { DecreaseStep -= 0.01f; } public void DecreaseDropCyclePct() { DecreaseStep += 0.01f; } protected AutoModeData(EnumJobFrequencyMultMode jobFreqMode, float defaultFrequencyMult, float avgEmployeeWaitTargetMillis, float avgCustomerWaitTargetMillis, float minFreqMult, float maxFreqMult, float decreaseStep, float increaseStep) { JobFreqMode = jobFreqMode; DefaultFrequencyMult = defaultFrequencyMult; AvgEmployeeWaitTargetMillis = avgEmployeeWaitTargetMillis; AvgCustomerWaitTargetMillis = avgCustomerWaitTargetMillis; MinFreqMult = minFreqMult; MaxFreqMult = maxFreqMult; DecreaseStep = decreaseStep; IncreaseStep = increaseStep; int num = VerifyLocalValues(); if (num > 0) { NotifyErrors(num); } } public float AvgWaitTargetFromNpcType(NPCType npcType) { return npcType switch { NPCType.Employee => AvgEmployeeWaitTargetMillis, NPCType.Customer => AvgCustomerWaitTargetMillis, _ => throw new NotSupportedException(npcType.ToString()), }; } private int VerifyLocalValues() { int num = 0; if (DecreaseStep < 0f) { DecreaseStep = Math.Abs(DecreaseStep); } if (DefaultFrequencyMult < MinFreqMult) { DefaultFrequencyMult = MinFreqMult; } else if (DefaultFrequencyMult > MaxFreqMult) { DefaultFrequencyMult = MaxFreqMult; } if (MinFreqMult > MaxFreqMult) { num++; MaxFreqMult = MinFreqMult; } (float, AutoModeValueLimit)[] array = new(float, AutoModeValueLimit)[7] { (DefaultFrequencyMult, AutoModeLimits.DefaultFrequencyMult), (AvgEmployeeWaitTargetMillis, AutoModeLimits.AvgNpcWaitTarget), (AvgCustomerWaitTargetMillis, AutoModeLimits.AvgNpcWaitTarget), (MinFreqMult, AutoModeLimits.MinFreqMult), (MaxFreqMult, AutoModeLimits.MaxFreqMult), (DecreaseStep, AutoModeLimits.DecreaseStep), (IncreaseStep, AutoModeLimits.IncreaseStep) }; for (int i = 0; i < array.Length; i++) { (float, AutoModeValueLimit) tuple = array[i]; float item = tuple.Item1; (BoundCheckResult, float) tuple2 = tuple.Item2.CheckBounds(item); if (tuple2.Item1 != BoundCheckResult.WithinBounds) { item = tuple2.Item2; num++; } } DecreaseStep *= -1f; return num; } private void NotifyErrors(int notificationCounter) { if (ModConfig.Instance.NpcJobFrequencyMode.Value == EnumJobFrequencyMultMode.Auto_Custom) { TimeLogger.Logger.LogWarningShowInGame($"{notificationCounter} value/s of Custom auto mode were " + "outside allowed limits", (LogCategories)16777216); return; } throw new InvalidOperationException($"{notificationCounter} value/s of the " + $"{ModConfig.Instance.NpcJobFrequencyMode.Value} mode were out of " + "bounds. Check the AutoModes class."); } public float Clamp(float jobFreqMultiplier) { if (float.IsNaN(jobFreqMultiplier)) { TimeLogger.Logger.LogWarning("Calculated Job Frency Multiplier is NaN. " + $"Its been automatically adjusted to {DefaultFrequencyMult} before clampling, " + "but it should not have happened.", (LogCategories)16777216); jobFreqMultiplier = DefaultFrequencyMult; } return Mathf.Clamp(jobFreqMultiplier, MinFreqMult, MaxFreqMult); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.JobScheduler.AutoMode.DataDefinition { [StructLayout(LayoutKind.Sequential, Size = 1)] public struct AutoModeLimits { private const float Frequency_MinLimit = 0.2f; private const float Frequency_MaxLimit = 25f; public static readonly AutoModeValueLimit DefaultFrequencyMult = new AutoModeValueLimit(0.2f, 25f); public static readonly AutoModeValueLimit AvgNpcWaitTarget = new AutoModeValueLimit(-1f, 1000f); public static readonly AutoModeValueLimit MinFreqMult = new AutoModeValueLimit(0.2f, 10f); public static readonly AutoModeValueLimit MaxFreqMult = new AutoModeValueLimit(0.5f, 25f); public static readonly AutoModeValueLimit DecreaseStep = new AutoModeValueLimit(0.1f, 5f); public static readonly AutoModeValueLimit IncreaseStep = new AutoModeValueLimit(0.1f, 5f); } public enum BoundCheckResult { LowerBoundBreach, UpperBoundBreach, WithinBounds } public class AutoModeValueLimit { public float MinLimit { get; init; } public float MaxLimit { get; private set; } public AutoModeValueLimit(float minLimit, float maxLimit) { MinLimit = minLimit; MaxLimit = maxLimit; } public (BoundCheckResult boundingCheck, float defaultValue) CheckBounds(float value) { BoundCheckResult item = BoundCheckResult.WithinBounds; float item2 = 0f; if (value < MinLimit) { item = BoundCheckResult.LowerBoundBreach; item2 = MinLimit; } else if (value > MaxLimit) { item = BoundCheckResult.UpperBoundBreach; item2 = MaxLimit; } return (item, item2); } } public class PerformanceMode : AutoModeData { public static readonly float MaxAllowedProcessingTime = 3f; public PerformanceMode() : base(EnumJobFrequencyMultMode.Auto_Performance, 1f, 150f, 400f, AutoModeLimits.MinFreqMult.MinLimit, 1f, 0.375f, 0.125f) { } } public class BalancedMode : AutoModeData { public static readonly float MaxAllowedProcessingTime = 5f; public BalancedMode() : base(EnumJobFrequencyMultMode.Auto_Balanced, 1f, 100f, 250f, 0.33f, 8f, 0.9f, 0.9f) { } } public class AggressiveMode : AutoModeData { public static readonly float MaxAllowedProcessingTime = 12f; public AggressiveMode() : base(EnumJobFrequencyMultMode.Auto_Aggressive, 1f, -1f, -1f, 0.5f, AutoModeLimits.MaxFreqMult.MaxLimit, 3.5f, 5f) { } } public class CustomMode : AutoModeData { public static readonly float MaxAllowedProcessingTime = 16.666666f; public CustomMode() : base(EnumJobFrequencyMultMode.Auto_Custom, 1f, ModConfig.Instance.CustomEmployeeWaitTarget.Value, ModConfig.Instance.CustomCustomerWaitTarget.Value, ModConfig.Instance.CustomMinimumFrequencyMult.Value, ModConfig.Instance.CustomMaximumFrequencyMult.Value, ModConfig.Instance.CustomMaximumFrequencyReduction.Value, ModConfig.Instance.CustomMaximumFrequencyIncrease.Value) { } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.TargetMarking { public enum TargetType { NonReservable, GroundBox, StorageSlot, ProdShelfSlot } public static class EmployeeTargetReservation { private static readonly Dictionary NpcBoxTargets = new Dictionary(); private static readonly HashSet groundboxesTargeted = new HashSet(); private static readonly Dictionary NpcStorageSlotTargets = new Dictionary(); private static readonly HashSet storageSlotsTargeted = new HashSet(new TargetContainerSlotComparer()); private static readonly Dictionary NpcShelfProductSlotTargets = new Dictionary(); private static readonly HashSet shelfProductSlotsTargeted = new HashSet(new TargetContainerSlotComparer()); public static void ClearAll() { NpcBoxTargets.Clear(); groundboxesTargeted.Clear(); NpcStorageSlotTargets.Clear(); storageSlotsTargeted.Clear(); NpcShelfProductSlotTargets.Clear(); shelfProductSlotsTargeted.Clear(); } public static void ClearNPCReservations(uint netidNPC) { DeleteAllNPCTargets(netidNPC); } public static bool IsGroundBoxTargeted(GameObject boxObj) { return groundboxesTargeted.Contains(boxObj); } public static bool IsShelfSlotTargeted(ShelfType shelfType, int ShelfIndex, int SlotIndex) { return shelfType switch { ShelfType.StorageSlot => IsStorageSlotTargeted(ShelfIndex, SlotIndex), ShelfType.ProdShelfSlot => IsProductShelfSlotTargeted(ShelfIndex, SlotIndex), _ => throw new NotImplementedException(shelfType.ToString()), }; } public static bool IsStorageSlotTargeted(int StorageIndex, int SlotIndex) { return IsStorageSlotTargeted(new StorageSlotInfo(StorageIndex, SlotIndex)); } public static bool IsProductShelfSlotTargeted(int ProdShelfIndex, int SlotIndex) { return IsProductShelfSlotTargeted(new ProductShelfSlotInfo(ProdShelfIndex, SlotIndex)); } public static bool IsStorageSlotTargeted(StorageSlotInfo storageSlotInfo) { return storageSlotsTargeted.Contains(storageSlotInfo); } public static bool IsProductShelfSlotTargeted(ProductShelfSlotInfo productShelfSlotInfo) { return shelfProductSlotsTargeted.Contains(productShelfSlotInfo); } public static bool HasTargetedStorage(this uint netidNPC, out StorageSlotInfo storageSlotInfo) { return NpcStorageSlotTargets.TryGetValue(netidNPC, out storageSlotInfo); } public static bool HasTargetedProductShelf(this uint netidNPC, out ProductShelfSlotInfo productShelfSlotInfo) { return NpcShelfProductSlotTargets.TryGetValue(netidNPC, out productShelfSlotInfo); } public static void DeleteAllNPCTargets(uint netidNPC) { DeleteNPCTarget(netidNPC, TargetType.GroundBox); DeleteNPCTarget(netidNPC, TargetType.StorageSlot); DeleteNPCTarget(netidNPC, TargetType.ProdShelfSlot); } public static void DeleteNPCTarget(uint netidNPC, TargetType targetType) { if (targetType == TargetType.GroundBox && NpcBoxTargets.TryGetValue(netidNPC, out var value)) { DeleteTarget(netidNPC, value, NpcBoxTargets, groundboxesTargeted, targetType); } if (targetType == TargetType.StorageSlot && NpcStorageSlotTargets.TryGetValue(netidNPC, out var value2)) { DeleteTarget(netidNPC, value2, NpcStorageSlotTargets, storageSlotsTargeted, targetType); } if (targetType == TargetType.ProdShelfSlot && NpcShelfProductSlotTargets.TryGetValue(netidNPC, out var value3)) { DeleteTarget(netidNPC, value3, NpcShelfProductSlotTargets, shelfProductSlotsTargeted, targetType); } } private static void DeleteTarget(uint netidNPC, T targetItem, Dictionary NPCTargets, HashSet targetedItems, TargetType targetType) { if (!NPCTargets.ContainsKey(netidNPC)) { throw new InvalidOperationException($"NPC {netidNPC} was found with a {targetType} as target, but the NPC is no longer on the NPC target list."); } if (!targetedItems.Contains(targetItem)) { throw new InvalidOperationException($"The {targetType} was expected to be in the list of targeted items, but its no longer there."); } targetedItems.Remove(targetItem); NPCTargets.Remove(netidNPC); } public static void AddTargetReservation(uint netidNPC, GameObject gameObjectTarget, GenericShelfSlotInfo shelfTarget, TargetType targetType) { switch (targetType) { case TargetType.GroundBox: AddTarget(netidNPC, gameObjectTarget, NpcBoxTargets, groundboxesTargeted, targetType); break; case TargetType.StorageSlot: AddTarget(netidNPC, (StorageSlotInfo)shelfTarget, NpcStorageSlotTargets, storageSlotsTargeted, targetType); break; case TargetType.ProdShelfSlot: AddTarget(netidNPC, (ProductShelfSlotInfo)shelfTarget, NpcShelfProductSlotTargets, shelfProductSlotsTargeted, targetType); break; } } private static void AddTarget(uint netidNPC, T targetItem, Dictionary NPCTargets, HashSet targetedItems, TargetType targetType) { if (targetItem == null) { throw new ArgumentNullException("targetItem"); } if (NPCTargets.ContainsKey(netidNPC)) { throw new InvalidOperationException($"NPC {netidNPC} still has a {targetType} as target, but it should not have any by now."); } if (targetedItems.Contains(targetItem)) { throw new InvalidOperationException($"A {targetType} was going to be marked as targeted, but it was found already marked."); } NPCTargets.Add(netidNPC, targetItem); targetedItems.Add(targetItem); } } public static class EmployeeReservationExtensions { public static void ClearNPCReservations(this EmployeeNPC employeeNPC) { EmployeeTargetReservation.ClearNPCReservations(employeeNPC.ParentNetid); } public static void AddExtraStorageTarget(this EmployeeNPC employeeNPC, StorageSlotInfo shelfTarget) { EmployeeTargetReservation.AddTargetReservation(employeeNPC.ParentNetid, null, shelfTarget, TargetType.StorageSlot); } public static void AddExtraProductShelfTarget(this EmployeeNPC employeeNPC, ProductShelfSlotInfo shelfTarget) { EmployeeTargetReservation.AddTargetReservation(employeeNPC.ParentNetid, null, shelfTarget, TargetType.ProdShelfSlot); } public static bool RefreshAndCheckValidTargetedStorage(this EmployeeNPC employeeNPC, NPC_Manager __instance, bool clearReservation, out StorageSlotInfo storageSlotInfo) { GenericShelfSlotInfo slotInfoBase; bool result = TargetMatching.RefreshAndCheckTargetedShelf(employeeNPC, __instance, clearReservation, -1, TargetType.StorageSlot, out slotInfoBase); storageSlotInfo = (StorageSlotInfo)slotInfoBase; return result; } public static bool RefreshAndCheckValidTargetedProductShelf(this EmployeeNPC employeeNPC, NPC_Manager __instance, RestockJobInfo jobInfo) { return TargetMatching.RefreshAndCheckValidTargetedProductShelf(employeeNPC, __instance, clearReservation: false, jobInfo); } public static bool HasTargetedStorage(this EmployeeNPC employeeNPC) { StorageSlotInfo storageSlotInfo; return employeeNPC.ParentNetid.HasTargetedStorage(out storageSlotInfo); } public static bool HasTargetedProductShelf(this EmployeeNPC employeeNPC) { ProductShelfSlotInfo productShelfSlotInfo; return employeeNPC.ParentNetid.HasTargetedProductShelf(out productShelfSlotInfo); } } public static class TargetMatching { private class ProductShelfSlotMatch : GenericShelfSlotInfo { public int MaxProductsPerRow { get; private set; } public ProductShelfSlotMatch(ProductShelfSlotInfo shelfSlotInfo, int maxProductsPerRow) : base(shelfSlotInfo.ShelfIndex, shelfSlotInfo.SlotIndex, shelfSlotInfo.ExtraData.ProductId, shelfSlotInfo.ExtraData.Quantity, shelfSlotInfo.ExtraData.Position, ShelfType.ProdShelfSlot) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) MaxProductsPerRow = maxProductsPerRow; } } public static bool RefreshAndCheckValidTargetedProductShelf(EmployeeNPC NPC, NPC_Manager __instance, bool clearReservation, RestockJobInfo jobInfo) { GenericShelfSlotInfo slotInfoBase; bool result = RefreshAndCheckTargetedShelf(NPC, __instance, clearReservation, jobInfo.MaxProductsPerRow, TargetType.ProdShelfSlot, out slotInfoBase); jobInfo.SetProductShelfExtraData((ProductShelfSlotInfo)slotInfoBase, jobInfo.MaxProductsPerRow); return result; } public static bool RefreshAndCheckTargetedShelf(EmployeeNPC employeeNPC, NPC_Manager __instance, bool clearReservation, int maxProductsPerRow, TargetType targetType, out GenericShelfSlotInfo slotInfoBase) { bool flag; bool flag2; switch (targetType) { case TargetType.StorageSlot: { flag = employeeNPC.ParentNetid.HasTargetedStorage(out var storageSlotInfo); flag2 = RefreshAndCheckStorageContents(__instance.storageOBJ, storageSlotInfo); slotInfoBase = storageSlotInfo; break; } case TargetType.ProdShelfSlot: { flag = employeeNPC.ParentNetid.HasTargetedProductShelf(out var productShelfSlotInfo); flag2 = RefreshAndCheckProdShelfContents(__instance.shelvesOBJ, productShelfSlotInfo, maxProductsPerRow); slotInfoBase = productShelfSlotInfo; break; } default: throw new InvalidOperationException($"Invalid target \"{targetType}\" for this method."); } if (clearReservation && flag) { EmployeeTargetReservation.DeleteNPCTarget(employeeNPC.ParentNetid, targetType); } return flag && flag2; } public static bool RefreshAndCheckTargetProductShelf(NPC_Manager __instance, RestockJobInfo jobInfo, int maxProductsPerRow) { ProductShelfSlotInfo prodShelf = jobInfo.ProdShelf; bool num = EmployeeTargetReservation.IsProductShelfSlotTargeted(prodShelf); bool flag = RefreshAndCheckProdShelfContents(__instance.shelvesOBJ, prodShelf, maxProductsPerRow); return !num && flag; } public static bool RefreshAndCheckTargetStorage(NPC_Manager __instance, RestockJobInfo jobInfo) { StorageSlotInfo storage = jobInfo.Storage; bool num = EmployeeTargetReservation.IsStorageSlotTargeted(storage); bool flag = RefreshAndCheckStorageContents(__instance.storageOBJ, storage); return !num && flag; } private static bool RefreshAndCheckProdShelfContents(GameObject gameObjectShelf, ProductShelfSlotInfo slotInfo, int maxProductsPerRow) { ProductShelfSlotMatch slotInfoBase = new ProductShelfSlotMatch(slotInfo, maxProductsPerRow); int currentTargetQuantity; bool result = ContentsMatchOrValid(gameObjectShelf, slotInfoBase, out currentTargetQuantity, TargetType.ProdShelfSlot); slotInfo.ExtraData.Quantity = currentTargetQuantity; return result; } private static bool RefreshAndCheckStorageContents(GameObject gameObjectStorage, StorageSlotInfo slotInfo) { int currentTargetQuantity; bool result = ContentsMatchOrValid(gameObjectStorage, slotInfo, out currentTargetQuantity, TargetType.StorageSlot); slotInfo.ExtraData.Quantity = currentTargetQuantity; return result; } private static bool ContentsMatchOrValid(GameObject gameObjectShelf, GenericShelfSlotInfo slotInfoBase, out int currentTargetQuantity, TargetType targetType) { if (gameObjectShelf.transform.childCount <= slotInfoBase.ShelfIndex) { currentTargetQuantity = -1; return false; } int[] productInfoArray = ((Component)gameObjectShelf.transform.GetChild(slotInfoBase.ShelfIndex)).GetComponent().productInfoArray; int num = productInfoArray[slotInfoBase.SlotIndex * 2]; currentTargetQuantity = productInfoArray[slotInfoBase.SlotIndex * 2 + 1]; if (num == slotInfoBase.ExtraData.ProductId) { switch (targetType) { case TargetType.StorageSlot: return currentTargetQuantity >= slotInfoBase.ExtraData.Quantity; case TargetType.ProdShelfSlot: if (!(slotInfoBase is ProductShelfSlotMatch)) { throw new InvalidOperationException("The target slot shelf parameter (slotInfoBase) must be an object of type ProductShelfSlotMatch"); } return currentTargetQuantity < ((ProductShelfSlotMatch)slotInfoBase).MaxProductsPerRow; } } return false; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch { public static class EmployeeRestockJobInfo { private static Dictionary npcRestockJobInfo = new Dictionary(); public static void SetRestockJobInfo(this NPC_Info npcInfo, RestockJobInfo jobInfo) { if (npcRestockJobInfo.TryGetValue(npcInfo, out var _)) { npcRestockJobInfo[npcInfo] = jobInfo; } else { npcRestockJobInfo.Add(npcInfo, jobInfo); } npcInfo.SetProductAvailableArray(jobInfo); } public static bool UpdateRestockJobInfo(this NPC_Info npcInfo, ProductShelfSlotInfo shelfSlotInfo, int maxProductsPerRow) { if (shelfSlotInfo == null) { TimeLogger.Logger.LogFatal($"The parameter shelfSlotInfo is null for npc {((NetworkBehaviour)npcInfo).netId}", (LogCategories)134217728); return false; } if (!npcRestockJobInfo.TryGetValue(npcInfo, out var value)) { TimeLogger.Logger.LogFatal($"An existing ProductAvailableInfo couldnt be found for npc {((NetworkBehaviour)npcInfo).netId}", (LogCategories)134217728); return false; } npcRestockJobInfo.Remove(npcInfo); RestockJobInfo restockJobInfo = new RestockJobInfo(shelfSlotInfo, value.Storage, value.MaxProductsPerRow); npcRestockJobInfo.Add(npcInfo, restockJobInfo); npcInfo.SetProductAvailableArray(restockJobInfo); return true; } private static void SetProductAvailableArray(this NPC_Info npcInfo, RestockJobInfo jobInfo) { ProductShelfSlotInfo prodShelf = jobInfo.ProdShelf; StorageSlotInfo storage = jobInfo.Storage; npcInfo.productAvailableArray = new int[10] { prodShelf.ShelfIndex, jobInfo.ShelfProdInfoIndex, storage.ShelfIndex, jobInfo.StorageProdInfoIndex, prodShelf.ExtraData.ProductId, storage.ExtraData.ProductId, prodShelf.SlotIndex, storage.SlotIndex, prodShelf.ExtraData.Quantity, storage.ExtraData.Quantity }; } public static RestockJobInfo GetRestockJobInfo(this NPC_Info npcInfo) { if (!npcRestockJobInfo.TryGetValue(npcInfo, out var value)) { throw new InvalidOperationException($"The NPC with netId {((NetworkBehaviour)npcInfo).netId} doesnt have any available product set yet."); } return value; } } public class RestockJobsManager { public enum JobFindStatus { FoundJob, JobNotValid, NoMoreJobs } public static readonly float RestockProcessInterval = 3f; public static readonly float RestockProcessNotPossibleInterval = 0.5f; public static readonly int MaxStorageJobsPerShelf = 1; public static readonly float StaticQueuedJobsPerEmployee = 1.25f; public static readonly float DynamicQueuedJobsPerEmployee = 0.9f; public static readonly int ExtraQueuedJobsBuffer = 5; public static readonly float NonCriticalJobsPerPriorityMultiplier = 1.25f; private static RestockJob availableRestockJobs; public static int JobCount => availableRestockJobs.Count; public static void Initialize() { availableRestockJobs = new RestockJob(); } public static bool GetAvailableRestockJob(NPC_Manager __instance, out RestockJobInfo restockJob) { restockJob = RestockJobInfo.Default; JobFindStatus jobFindStatus; do { if (availableRestockJobs.TryExtractPriorityJob(out var possibleRestockJob, out var _)) { if (TargetMatching.RefreshAndCheckTargetProductShelf(__instance, possibleRestockJob, possibleRestockJob.MaxProductsPerRow) && TargetMatching.RefreshAndCheckTargetStorage(__instance, possibleRestockJob)) { jobFindStatus = JobFindStatus.FoundJob; restockJob = possibleRestockJob; continue; } jobFindStatus = JobFindStatus.JobNotValid; LOG.TEMPDEBUG_FUNC((Func)(() => "GetAvailableRestockJob - Job was not valid anymore. " + $"Job info - {possibleRestockJob}."), false); } else { jobFindStatus = JobFindStatus.NoMoreJobs; } } while (jobFindStatus == JobFindStatus.JobNotValid); RestockJobInfo restockJobLog = restockJob; LOG.TEMPDEBUG_FUNC((Func)(() => $"GetAvailableRestockJob result: {jobFindStatus}, " + $"with job info - {restockJobLog}."), false); return jobFindStatus == JobFindStatus.FoundJob; } public static void AddAvailableJob(RestockPriority restockPriority, ShelfSlotData productShelfSlotData, ShelfSlotData storageSlotData, int maxProductsPerRow) { RestockJobInfo restockJob = new RestockJobInfo(productShelfSlotData.ToProdShelfSlotInfo(), storageSlotData.ToStorageSlotInfo(), maxProductsPerRow); availableRestockJobs.TryAddJob(restockPriority, restockJob); LOG.TEMPDEBUG_FUNC((Func)(() => $"Added new available job with info - {restockJob}."), false); } public static void ClearJobs() { availableRestockJobs.ClearJobs(); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Models { public struct RestockJobInfo { public ProductShelfSlotInfo ProdShelf { get; private set; } public StorageSlotInfo Storage { get; private set; } public int ShelfProdInfoIndex => ProdShelf.SlotIndex * 2; public int StorageProdInfoIndex => Storage.SlotIndex * 2; public int MaxProductsPerRow { get; set; } public static RestockJobInfo Default { get; } = new RestockJobInfo(); public RestockJobInfo() { ProdShelf = ProductShelfSlotInfo.Default; Storage = StorageSlotInfo.Default; MaxProductsPerRow = -1; } public RestockJobInfo(ProductShelfSlotInfo ProductShelf, StorageSlotInfo Storage, int MaxProductsPerRow) { ProdShelf = ProductShelf; this.Storage = Storage; this.MaxProductsPerRow = MaxProductsPerRow; } public void SetProductShelfExtraData(ProductShelfSlotInfo productShelf, int maxProductsPerRow) { ProdShelf.ExtraData = productShelf.ExtraData; MaxProductsPerRow = maxProductsPerRow; } public override string ToString() { return $"Product shelf: {ProdShelf} - Storage: {Storage} - MaxProductsPerRow: {MaxProductsPerRow}"; } } public readonly record struct ShelfSlotData(int ShelfIndex, int SlotIndex, int ProductId, int Quantity, Data_Container DataContainer, Vector3 Position) { public ShelfSlotData(int ShelfIndex, int SlotIndex, int ProductId, int Quantity, Data_Container DataContainer, Vector3 Position) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) this.ShelfIndex = ShelfIndex; this.SlotIndex = SlotIndex; this.ProductId = ProductId; this.Quantity = Quantity; this.DataContainer = DataContainer; this.Position = Position; } public ShelfSlotData(ShelfData shelfData, int slotIndex, int productId, int quantity) : this(shelfData.ShelfIndex, slotIndex, productId, quantity, shelfData.DataContainer, shelfData.Position) { }//IL_0015: Unknown result type (might be due to invalid IL or missing references) public StorageSlotInfo ToStorageSlotInfo() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) return new StorageSlotInfo(ShelfIndex, SlotIndex, ProductId, Quantity, Position); } public ProductShelfSlotInfo ToProdShelfSlotInfo() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) return new ProductShelfSlotInfo(ShelfIndex, SlotIndex, ProductId, Quantity, Position); } [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) builder.Append("ShelfIndex = "); builder.Append(ShelfIndex.ToString()); builder.Append(", SlotIndex = "); builder.Append(SlotIndex.ToString()); builder.Append(", ProductId = "); builder.Append(ProductId.ToString()); builder.Append(", Quantity = "); builder.Append(Quantity.ToString()); builder.Append(", DataContainer = "); builder.Append(DataContainer); builder.Append(", Position = "); Vector3 position = Position; builder.Append(((object)(Vector3)(ref position)).ToString()); return true; } } public readonly record struct ShelfData(int ShelfIndex, int[] ProductInfoArray, Data_Container DataContainer, Vector3 Position) { [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) builder.Append("ShelfIndex = "); builder.Append(ShelfIndex.ToString()); builder.Append(", ProductInfoArray = "); builder.Append(ProductInfoArray); builder.Append(", DataContainer = "); builder.Append(DataContainer); builder.Append(", Position = "); Vector3 position = Position; builder.Append(((object)(Vector3)(ref position)).ToString()); return true; } } public readonly record struct ProductShelfInfo(ShelfSlotData ShelfSlotData, int MaxProductsPerRow); } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Helpers { public class RestockJob where T : struct { protected Dictionary> restockJobs; private int jobCount; private Func> getNewQueueInstance; public bool HasJobsLeft => jobCount > 0; public int Count => jobCount; public RestockJob() { restockJobs = new Dictionary>(); getNewQueueInstance = () => (ICommonQueue)(object)new CommonConcurrentQueue(); InitializePriorities(); } public RestockJob(int fixedCapacity) { restockJobs = new Dictionary>(); getNewQueueInstance = () => (ICommonQueue)(object)new ConcurrentFixedCapacityQueue(fixedCapacity, false); InitializePriorities(); } public void InitializePriorities() { for (int i = 0; i < ThresholdHelper.ThresholdCount; i++) { RestockPriority key = ThresholdHelper.ThresholdEnumValues[i]; ICommonQueue value = getNewQueueInstance(); if (!restockJobs.ContainsKey(key)) { restockJobs.Add(key, value); } else { restockJobs[key] = value; } } jobCount = 0; } public bool TryAddJob(RestockPriority restockThreshold, T jobInfo) { bool num = restockJobs[restockThreshold].TryEnqueue(jobInfo); if (num) { jobCount++; } return num; } public bool TryExtractPriorityJob(out T job, out RestockPriority restockPriority) { foreach (KeyValuePair> restockJob in restockJobs) { if (restockJob.Value.TryDequeue(ref job)) { jobCount--; restockPriority = restockJob.Key; return true; } } job = default(T); restockPriority = RestockPriority.ShelfFull; return false; } public void ClearJobs() { InitializePriorities(); } } public enum RestockPriority { Critical, High, Medium, Low, ShelfFull } public class ThresholdHelper { private static readonly float[] restockThresholds = new float[4] { 0.1f, 0.33f, 0.66f, 1f }; public static readonly int ThresholdCount = restockThresholds.Length; public static readonly RestockPriority[] ThresholdEnumValues = (RestockPriority[])Enum.GetValues(typeof(RestockPriority)); public static bool IsShelfNotFull(int prodQuantity, int maxProductsPerRow, out RestockPriority restockPriority) { if (prodQuantity < maxProductsPerRow) { for (int i = 0; i < ThresholdCount; i++) { if (prodQuantity < (int)((float)maxProductsPerRow * restockThresholds[i])) { restockPriority = (RestockPriority)i; return true; } } } restockPriority = RestockPriority.ShelfFull; return false; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Employees.RestockMatch.Component { public class RestockMatcher : NetworkBehaviour { private class RestockStorageComparer : IComparer { private Vector3 shelfPosition; private int prodShelfLeftToFillCount; private bool useSimpleBoxQuantityComparison; private AnimationCurve quantVsDistPriorityThreshold; private static readonly float quantityPriorityPercent = 0.85f; public RestockStorageComparer(int prodShelfQuantity, int maxProductsPerRow, Vector3 shelfPosition, int boxMaxProductCount) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown this.shelfPosition = shelfPosition; prodShelfLeftToFillCount = maxProductsPerRow - prodShelfQuantity; useSimpleBoxQuantityComparison = prodShelfLeftToFillCount <= boxMaxProductCount; quantVsDistPriorityThreshold = new AnimationCurve(); for (int i = 0; i <= 10; i++) { float num = (float)i * 0.1f; float num2 = (1f - num) * quantityPriorityPercent; quantVsDistPriorityThreshold.AddKey((float)boxMaxProductCount * num, num2); } } public int Compare(ShelfSlotData xStorageSlot, ShelfSlotData yStorageSlot) { if (xStorageSlot.Quantity == yStorageSlot.Quantity) { return CompareShelfDistance(xStorageSlot, yStorageSlot); } if (useSimpleBoxQuantityComparison) { if (xStorageSlot.Quantity >= prodShelfLeftToFillCount && yStorageSlot.Quantity >= prodShelfLeftToFillCount) { return CompareDistanceVsQuantity(xStorageSlot, yStorageSlot); } if (xStorageSlot.Quantity >= prodShelfLeftToFillCount) { return -1; } if (yStorageSlot.Quantity >= prodShelfLeftToFillCount) { return 1; } } return CompareDistanceVsQuantity(xStorageSlot, yStorageSlot); } private int CompareDistanceVsQuantity(ShelfSlotData xStorageSlot, ShelfSlotData yStorageSlot) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) float num = Math.Abs(xStorageSlot.Quantity - yStorageSlot.Quantity); float num2 = quantVsDistPriorityThreshold.Evaluate(num); Vector3 val = xStorageSlot.Position - shelfPosition; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = yStorageSlot.Position - shelfPosition; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; if (((sqrMagnitude < sqrMagnitude2) ? (sqrMagnitude / sqrMagnitude2) : (sqrMagnitude2 / sqrMagnitude)) < num2) { return CompareShelfDistance(sqrMagnitude, sqrMagnitude2); } if (xStorageSlot.Quantity <= yStorageSlot.Quantity) { return 1; } return -1; } private int CompareShelfDistance(ShelfSlotData xStorageSlot, ShelfSlotData yStorageSlot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Vector3 val = xStorageSlot.Position - shelfPosition; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = yStorageSlot.Position - shelfPosition; float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude; return CompareShelfDistance(sqrMagnitude, sqrMagnitude2); } private static int CompareShelfDistance(float xShelfDistance, float yShelfDistance) { if (Math.Abs(xShelfDistance - yShelfDistance) < Mathf.Epsilon) { return 0; } return xShelfDistance.CompareTo(yShelfDistance); } } private double lastTimeCheck; private CancellableSingleTask restockJobGen; private Task restockTask; private static float currentRestockProcessInterval; public static void Enable() { WorldState.OnWorldLoaded += SetupRestockMatcher; } public static void Disable() { WorldState.OnWorldLoaded -= SetupRestockMatcher; } private static void SetupRestockMatcher() { ((Component)NPC_Manager.Instance).gameObject.AddComponent(); RestockJobsManager.Initialize(); } public void Awake() { restockJobGen = new CancellableSingleTask(false); lastTimeCheck = -1.0; currentRestockProcessInterval = RestockJobsManager.RestockProcessNotPossibleInterval; } public void FixedUpdate() { if (restockTask == null || (TaskExtensionMethods.IsTaskEnded(restockTask) && (lastTimeCheck == -1.0 || lastTimeCheck + (double)currentRestockProcessInterval < (double)Time.fixedUnscaledTime))) { if (IsRestockPossible(NPC_Manager.Instance)) { GenerateAvailableRestockProducts(NPC_Manager.Instance); currentRestockProcessInterval = RestockJobsManager.RestockProcessInterval; } else { currentRestockProcessInterval = RestockJobsManager.RestockProcessNotPossibleInterval; } lastTimeCheck = Time.fixedUnscaledTime; } } private bool IsRestockPossible(NPC_Manager __instance) { if (__instance.storageOBJ.transform.childCount > 0 && __instance.shelvesOBJ.transform.childCount > 0) { return EmployeeJobAIPatch.HasEmployeeAssignedTo(EmployeeJob.Restocker); } return false; } public void GenerateAvailableRestockProducts(NPC_Manager __instance) { Task task = restockTask; if (task != null) { TaskExtensionMethods.FireAndForgetCancels(task, (LogCategories)16777216, false); } List listStorageShelf = GetInitialShelfList(__instance, ShelfType.StorageSlot); List listProdShelf = GetInitialShelfList(__instance, ShelfType.ProdShelfSlot); LOG.TEMPDEBUG_FUNC((Func)(() => $"{RestockJobsManager.JobCount} jobs are going to be cleared."), false); RestockJobsManager.ClearJobs(); int maxJobsRestockCycle = CalculateMaxQueuedJobsForCycle(__instance); restockTask = restockJobGen.StartAwaitableThreadedTaskAsync((Func)(() => RestockJobGeneration(maxJobsRestockCycle, listStorageShelf, listProdShelf)), "Restock job generation", false); } private int CalculateMaxQueuedJobsForCycle(NPC_Manager __instance) { int employeeCount = EmployeeJobAIPatch.GetEmployeeCount(EmployeeJob.Restocker); float num = Time.timeScale * (EmployeeWalkSpeedPatch.IsWarpingEnabled() ? 15f : EmployeeWalkSpeedPatch.WalkSpeedMultiplier); return (int)Math.Ceiling(RestockJobsManager.StaticQueuedJobsPerEmployee * (float)employeeCount) + (int)Math.Ceiling(RestockJobsManager.DynamicQueuedJobsPerEmployee * (float)employeeCount * num) + RestockJobsManager.ExtraQueuedJobsBuffer; } private static Task RestockJobGeneration(int maxJobsRestockCycle, List listStorageShelf, List listProdShelf) { Math.Ceiling((float)maxJobsRestockCycle * RestockJobsManager.NonCriticalJobsPerPriorityMultiplier); RestockJob restockJob = new RestockJob(); Dictionary> dictStorageSlot = GenerateStorageSlotDictionary(listStorageShelf); foreach (ShelfData item in listProdShelf) { foreach (ShelfSlotData productShelfSlot in GetProductShelfSlotList(item)) { if (productShelfSlot.ProductId < 0) { continue; } int maxProductsPerRow = -1; RestockPriority restockPriority = ((productShelfSlot.Quantity != 0) ? RestockPriority.ShelfFull : RestockPriority.Critical); if (productShelfSlot.Quantity != 0) { maxProductsPerRow = PerformanceCachingPatch.GetMaxProductsPerRowCachedThreaded(productShelfSlot.DataContainer, productShelfSlot.ProductId, productShelfSlot.ShelfIndex); ThresholdHelper.IsShelfNotFull(productShelfSlot.Quantity, maxProductsPerRow, out restockPriority); } switch (restockPriority) { default: restockJob.TryAddJob(restockPriority, new ProductShelfInfo(productShelfSlot, maxProductsPerRow)); break; case RestockPriority.Critical: { if (GetStorageForProdShelf(dictStorageSlot, productShelfSlot, maxProductsPerRow, out var listNonEmptyStorageSlots)) { AddAvailableJobs(listNonEmptyStorageSlots, maxJobsRestockCycle, restockPriority, productShelfSlot, maxProductsPerRow); } if (RestockJobsManager.JobCount < maxJobsRestockCycle) { break; } goto end_IL_00e3; } case RestockPriority.ShelfFull: break; } continue; end_IL_00e3: break; } } ProductShelfInfo job; RestockPriority restockPriority2; while (RestockJobsManager.JobCount < maxJobsRestockCycle && restockJob.HasJobsLeft && restockJob.TryExtractPriorityJob(out job, out restockPriority2)) { if (GetStorageForProdShelf(dictStorageSlot, job.ShelfSlotData, job.MaxProductsPerRow, out var listNonEmptyStorageSlots2)) { AddAvailableJobs(listNonEmptyStorageSlots2, maxJobsRestockCycle, restockPriority2, job.ShelfSlotData, job.MaxProductsPerRow); } } LOG.TEMPDEBUG_FUNC((Func)(() => $"{RestockJobsManager.JobCount} jobs available after generation."), false); return Task.CompletedTask; } private static bool GetStorageForProdShelf(Dictionary> dictStorageSlot, ShelfSlotData prodShelfSlotData, int maxProductsPerRow, out List listNonEmptyStorageSlots) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!dictStorageSlot.TryGetValue(prodShelfSlotData.ProductId, out listNonEmptyStorageSlots)) { return false; } if (maxProductsPerRow == -1) { maxProductsPerRow = PerformanceCachingPatch.GetMaxProductsPerRowCachedThreaded(prodShelfSlotData.DataContainer, prodShelfSlotData.ProductId, prodShelfSlotData.ShelfIndex); } int maxItemsPerBox = ProductListing.Instance.productsData[prodShelfSlotData.ProductId].maxItemsPerBox; listNonEmptyStorageSlots.Sort(new RestockStorageComparer(prodShelfSlotData.Quantity, maxProductsPerRow, prodShelfSlotData.Position, maxItemsPerBox)); return true; } private static void AddAvailableJobs(List listNonEmptyStorageSlots, int maxJobsRestockCycle, RestockPriority restockPriority, ShelfSlotData prodShelfSlotData, int maxProductsPerRow) { if (maxProductsPerRow == -1) { maxProductsPerRow = PerformanceCachingPatch.GetMaxProductsPerRowCachedThreaded(prodShelfSlotData.DataContainer, prodShelfSlotData.ProductId, prodShelfSlotData.ShelfIndex); } int val = maxJobsRestockCycle - RestockJobsManager.JobCount; int num = Math.Min(RestockJobsManager.MaxStorageJobsPerShelf, val); for (int i = 0; i < num; i++) { RestockJobsManager.AddAvailableJob(restockPriority, prodShelfSlotData, listNonEmptyStorageSlots[i], maxProductsPerRow); } } private static List GetInitialShelfList(NPC_Manager __instance, ShelfType shelfType) { int capacity = __instance.shelvesOBJ.transform.childCount * 5; List listProdShelf = new List(capacity); ContainerSearchLambdas.ForEachShelfLambda(__instance, shelfType, delegate(int shelfIndex, int[] productInfoArray, Data_Container dataContainer, Vector3 position) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) listProdShelf.Add(new ShelfData(shelfIndex, productInfoArray, dataContainer, position)); return ContainerSearchLambdas.LoopAction.Nothing; }); LOG.TEMPDEBUG_FUNC((Func)(() => $"{listProdShelf.Count} initial shelfs of type " + $"{shelfType} obtained"), false); return listProdShelf; } private static List GetProductShelfSlotList(ShelfData productShelfData) { return ContainerSearchLambdas.GetShelfSlotsFromShelfData(productShelfData, ShelfType.ProdShelfSlot, ShelfSearchOptions.None).ToList(); } private static Dictionary> GenerateStorageSlotDictionary(List listStorageShelfData) { Dictionary> dictionary = new Dictionary>(); foreach (ShelfData listStorageShelfDatum in listStorageShelfData) { foreach (ShelfSlotData shelfSlotsFromShelfDatum in ContainerSearchLambdas.GetShelfSlotsFromShelfData(listStorageShelfDatum, ShelfType.StorageSlot, ShelfSearchOptions.SkipEmptySlots)) { if (!dictionary.TryGetValue(shelfSlotsFromShelfDatum.ProductId, out var value)) { dictionary.Add(shelfSlotsFromShelfDatum.ProductId, value = new List()); } value.Add(shelfSlotsFromShelfDatum); } } return dictionary; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.NPCs.Customers { public class TrappedCustomerDetection { private class NpcDetectionData { public NPC_Info NpcInfo { get; } public bool Active { get; private set; } public float TrapDetectedTimeStart { get; set; } public float TrapProtectionEndTime { get; set; } public NavMeshAgent NavMeshAgent { get { NPC_Info obj = UnityObjectExtensions.NullableObject(NpcInfo); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } } public NpcDetectionData(NPC_Info npcInfo, bool active) { NpcInfo = npcInfo; Active = active; TrapDetectedTimeStart = -1f; TrapProtectionEndTime = -1f; base..ctor(); } public void BeginDetection() { TrapProtectionEndTime = -1f; Active = true; } public void EndDetection() { ResetTrapDetection(); Active = false; } public void ResetTrapDetection() { TrapDetectedTimeStart = -1f; } public void SetTrapProtectionEndTime() { TrapProtectionEndTime = Time.time + npcTrapProtectionTime; } public bool ProcessProtection() { if (TrapProtectionEndTime == -1f) { return false; } if (TrapProtectionEndTime < Time.time) { TrapProtectionEndTime = -1f; NavMeshAgent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; NavMeshAgent.avoidancePriority = 50; return false; } return true; } } public static readonly float npcVelocityThreshold = 0.75f; public static readonly float npcTrapProtectionTime = 1.5f; public static readonly float npcPriorityTrappedTime = 1f; public static readonly float npcNoAvoidanceTrappedTime = 2f; public static readonly float npcNudgeTrappedTime = 3.5f; public static readonly float npcExtraNudgeTrappedTime = 5.5f; public static readonly float maxNudgeDistance = 1.5f; public static readonly float maxExtraNudgeDistance = 4f; private bool detectionEnabled; private Dictionary dictTrapData; public TrappedCustomerDetection() { dictTrapData = new Dictionary(); } public void EnableDetection() { detectionEnabled = true; TaskExtensionMethods.FireAndForget(DetectionLoop(), (LogCategories)134217728); } public void DisableDetection() { detectionEnabled = false; } public async Task DetectionLoop() { while (detectionEnabled) { if (dictTrapData.Count == 0 || !ModConfig.Instance.EnableCustomerStuckDetection.Value) { await UniTask.Delay(2000, false, (PlayerLoopTiming)8, default(CancellationToken), false); continue; } float detectionStartTime = Time.time; Dictionary dictionary = new Dictionary(dictTrapData); foreach (KeyValuePair item in dictionary) { NpcDetectionData value = item.Value; if (value.Active) { CheckNpcNav(value, Time.time); await UniTask.Delay(5, false, (PlayerLoopTiming)8, default(CancellationToken), false); } } UnityObjectExtensions.RemoveDeadKeyReferences(dictTrapData); float num = detectionStartTime - Time.time + GetTrapCheckInterval(); if (num > 0f) { await UniTask.Delay((int)(num * 1000f), false, (PlayerLoopTiming)8, default(CancellationToken), false); } else { await UniTask.DelayFrame(1, (PlayerLoopTiming)8, default(CancellationToken), false); } } dictTrapData.Clear(); } private static float GetTrapCheckInterval() { return ModConfig.Instance.NpcJobFrequencyMode.Value switch { EnumJobFrequencyMultMode.Auto_Performance => 0.5f, EnumJobFrequencyMultMode.Auto_Aggressive => 0.125f, _ => 0.25f, }; } public void BeginNpcNavDetection(NPC_Info npcInfo) { ChangeNpcTrapDetection(npcInfo, active: true); } public void StopNpcNavDetection(NPC_Info npcInfo) { ChangeNpcTrapDetection(npcInfo, active: false); } public bool IsNavDetectionActive(NPC_Info npcInfo) { if (Object.op_Implicit((Object)(object)npcInfo) && dictTrapData.TryGetValue(npcInfo, out var value)) { return value.Active; } return false; } private void ChangeNpcTrapDetection(NPC_Info npcInfo, bool active) { if (Object.op_Implicit((Object)(object)npcInfo)) { if (!dictTrapData.TryGetValue(npcInfo, out var value)) { value = new NpcDetectionData(npcInfo, active); dictTrapData.Add(npcInfo, value); } if (active && ModConfig.Instance.EnableCustomerStuckDetection.Value) { value.BeginDetection(); } else { value.EndDetection(); } } } private void CheckNpcNav(NpcDetectionData dd, float checkStartTime) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent navMeshAgent = dd.NavMeshAgent; if (!NPC_CustomerNavFixer.TestNavAgent(navMeshAgent)) { dd.EndDetection(); } if (dd.Active) { Vector3 velocity = dd.NavMeshAgent.velocity; if (((Vector3)(ref velocity)).magnitude < npcVelocityThreshold && !dd.NpcInfo.beingPushed && navMeshAgent.isOnNavMesh && navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance) { if (dd.TrapDetectedTimeStart < 0f) { dd.TrapDetectedTimeStart = checkStartTime; } if (!dd.ProcessProtection()) { float num = checkStartTime - dd.TrapDetectedTimeStart; if (num > npcExtraNudgeTrappedTime) { NudgeTowardsDestination(dd, smallNudge: false); dd.SetTrapProtectionEndTime(); } else if (num > npcNudgeTrappedTime) { NudgeTowardsDestination(dd, smallNudge: true); dd.SetTrapProtectionEndTime(); } else if (num > npcNoAvoidanceTrappedTime) { navMeshAgent.obstacleAvoidanceType = (ObstacleAvoidanceType)0; dd.SetTrapProtectionEndTime(); } else if (num > npcPriorityTrappedTime) { navMeshAgent.avoidancePriority = 0; dd.SetTrapProtectionEndTime(); } } return; } } dd.ResetTrapDetection(); dd.ProcessProtection(); } private void NudgeTowardsDestination(NpcDetectionData dd, bool smallNudge) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)dd.NpcInfo).transform.position; Vector3 val = dd.NavMeshAgent.destination - position; float magnitude = ((Vector3)(ref val)).magnitude; Vector3 normalized = ((Vector3)(ref val)).normalized; float num = Mathf.Min(smallNudge ? maxNudgeDistance : maxExtraNudgeDistance, magnitude); NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(position + normalized * num, ref val2, 2f, -1)) { TimeLogger.Logger.LogWarning("A valid nudge position couldnt be found for trapped npc " + EmployeeJobAIPatch.GetUniqueId(dd.NpcInfo), (LogCategories)134217728); } else { ((Component)dd.NpcInfo).transform.position = ((NavMeshHit)(ref val2)).position; } } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Networking.SyncVarBehaviours { public class BroomShotgunNetwork : SyncVarNetworkBehaviour { public static uint NetworkAssetId => 102201u; public static BroomShotgunNetwork LocalInstance { get; private set; } [SyncVarNetwork] public static BoolSyncVarSetting ShotgunModuleEnabledSync { get; private set; } [SyncVarNetwork] public SyncVar ShotgunCurrentStatus { get; set; } static BroomShotgunNetwork() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown ShotgunModuleEnabledSync = new BoolSyncVarSetting(false, ModConfig.Instance.BroomShotgunModeEnabled); RemoteProcedureCalls.RegisterCommand(typeof(BroomShotgunNetwork), "CmdPlayerFire", new RemoteCallDelegate(InvokeUserCode_CmdPlayerFire), true); RemoteProcedureCalls.RegisterRpc(typeof(BroomShotgunNetwork), "RpcPlayerFire", new RemoteCallDelegate(InvokeUserCode_RpcPlayerFire)); Writer.write = delegate(NetworkWriter writer, FireNetworkData[] value) { writer.WriteFireNetworkDataArray(value); }; Reader.read = (NetworkReader reader) => reader.ReadFireNetworkDataArray(); } public BroomShotgunNetwork() { ShotgunCurrentStatus = new SyncVar(ShotgunStatus.None); } protected override void Awake() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) base.StartNetworkSession(NetworkSpawnManager.GetCurrentNetworkMode()); base.Awake(); } public override void OnStartClient() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)this).isLocalPlayer) { LocalInstance = this; ((NetworkBehaviour)this).syncDirection = (SyncDirection)(WorldState.CurrentOnlineMode != GameOnlineMode.Host); } else { ((NetworkBehaviour)this).syncDirection = (SyncDirection)(WorldState.CurrentOnlineMode == GameOnlineMode.Host); } ((NetworkBehaviour)this).OnStartClient(); } public void CmdPlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetData) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) base.CmdCall("CmdPlayerFire", true, endPoint, playerSourceNetid, fireNetData); } protected static void InvokeUserCode_CmdPlayerFire(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { TimeLogger.Logger.LogError("Command CmdPlayerFire called on client.", (LogCategories)512); } else { ((BroomShotgunNetwork)(object)obj).UserCode_CmdPlayerFire(NetworkReaderExtensions.ReadVector3(reader), NetworkReaderExtensions.ReadUInt(reader), reader.Read()); } } protected void UserCode_CmdPlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) RpcPlayerFire(endPoint, playerSourceNetid, fireNetData); } public void RpcPlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetData) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) base.RpcCall("RpcPlayerFire", false, endPoint, playerSourceNetid, fireNetData); } protected static void InvokeUserCode_RpcPlayerFire(NetworkBehaviour obj, NetworkReader reader, NetworkConnectionToClient senderConnection) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) ((BroomShotgunNetwork)(object)obj).UserCode_RpcPlayerFire(NetworkReaderExtensions.ReadVector3(reader), NetworkReaderExtensions.ReadUInt(reader), reader.Read()); } protected void UserCode_RpcPlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetData) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) PlayerFire(endPoint, playerSourceNetid, fireNetData); } private void PlayerFire(Vector3 endPoint, uint playerSourceNetid, FireNetworkData[] fireNetData) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) WeaponManager.RemotePlayerFire(endPoint, playerSourceNetid, fireNetData); } } public static class CustomNetworkDataTransfer { public static void WriteFireNetworkData(this NetworkWriter writer, FireNetworkData value) { NetworkWriterExtensions.WriteUInt(writer, value.TargetNetid); NetworkWriterExtensions.WriteInt(writer, (int)value.TargetType); } public static FireNetworkData ReadFireNetworkData(this NetworkReader reader) { return new FireNetworkData(NetworkReaderExtensions.ReadUInt(reader), (SuperQoLity.SuperMarket.PatchClassHelpers.Weapons.Helpers.TargetType)NetworkReaderExtensions.ReadInt(reader)); } public static void WriteFireNetworkDataArray(this NetworkWriter writer, FireNetworkData[] value) { NetworkWriterExtensions.WriteInt(writer, value.Length); for (int i = 0; i < value.Length; i++) { writer.WriteFireNetworkData(value[i]); } } public static FireNetworkData[] ReadFireNetworkDataArray(this NetworkReader reader) { int num = NetworkReaderExtensions.ReadInt(reader); FireNetworkData[] array = new FireNetworkData[num]; for (int i = 0; i < num; i++) { array[i] = reader.ReadFireNetworkData(); } return array; } } public class ItemTransferNetwork : SyncVarNetworkBehaviour { public static uint NetworkAssetId => 871623u; [SyncVarNetwork] public static SyncVarSetting ItemTransferModeSync { get; private set; } [SyncVarNetwork] public static SyncVarSetting ItemTransferQuantitySync { get; private set; } static ItemTransferNetwork() { ItemTransferModeSync = new SyncVarSetting(EnumItemTransferMode.Disabled, ModConfig.Instance.ItemTransferMode); ItemTransferQuantitySync = new SyncVarSetting(EmployeeJobAIPatch.NumTransferItemsBase, ModConfig.Instance.NumTransferProducts); } } public class RadialWheelNetwork : SyncVarNetworkBehaviour { public static uint NetworkAssetId => 798271u; [SyncVarNetwork] public static BoolSyncVarSetting RadialEnabledSync { get; private set; } static RadialWheelNetwork() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown RadialEnabledSync = new BoolSyncVarSetting(false, ModConfig.Instance.EnableRadialWheelPatches); } } public class StoreStatusNetwork : SyncVarNetworkBehaviour { public static uint NetworkAssetId => 918219u; [SyncVarNetwork] public static SyncVar IsStoreOpenOrCustomersInsideSync { get; private set; } = new SyncVar(false); } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting { public static class BoxPrefabPatching { private enum BoxType { Ground, GroundNetworked, Held } private static Vector3 localScaleGroundBox; private static Mesh meshCubeGroundBoxCached; private static bool isBoxPrefabModded; private static bool isNetworkBoxPrefabModded; private static bool isDummyBoxPrefabModded; public static void PrepareBoxPrefabPatching() { WorldState.OnLoadingWorld += delegate { if (WorldState.CurrentOnlineMode == GameOnlineMode.Client) { InitializeBoxPrefabs(BoxType.GroundNetworked); } }; WorldState.OnFPControllerStarted += delegate { InitializeBoxPrefabs(BoxType.Ground); InitializeBoxPrefabs(BoxType.Held); }; } private static void InitializeBoxPrefabs(BoxType boxType) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if ((boxType == BoxType.Ground && isBoxPrefabModded) || (boxType == BoxType.GroundNetworked && isNetworkBoxPrefabModded) || (boxType == BoxType.Held && isDummyBoxPrefabModded)) { return; } Mesh val = null; if (FindBoxPrefab(boxType, out var boxPrefab)) { val = GetMeshFromPrefab(boxType, boxPrefab); } if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)boxPrefab)) { HighlightInitialization.InitializeBoxHighlight(boxPrefab.transform, val, localScaleGroundBox); TimeLogger.Logger.LogDebugFunc((Func)(() => $"Prefab for box '{boxType}' patched successfully."), (LogCategories)67108864); if (boxType == BoxType.Ground) { isBoxPrefabModded = true; } else if (boxType == BoxType.GroundNetworked) { isNetworkBoxPrefabModded = true; } else if (boxType == BoxType.Held) { isDummyBoxPrefabModded = true; } } } private static bool FindBoxPrefab(BoxType boxType, out GameObject boxPrefab) { boxPrefab = null; switch (boxType) { case BoxType.Ground: boxPrefab = UnityObjectExtensions.NullableObject(SMTInstances.ManagerBlackboard())?.boxPrefab; break; case BoxType.GroundNetworked: boxPrefab = NetworkClient.prefabs.FirstOrDefault((KeyValuePair k) => ((Object)k.Value).name.ToLower().Contains("1_box")).Value; break; case BoxType.Held: boxPrefab = UnityObjectExtensions.NullableObject(SMTInstances.LocalPlayerNetwork())?.dummyBoxPrefab; break; } if (!Object.op_Implicit((Object)(object)boxPrefab)) { TimeLogger.Logger.LogError($"The prefab for {boxType} box could not be found. " + "Highlight for these boxes wont work.", (LogCategories)67108864); } return Object.op_Implicit((Object)(object)boxPrefab); } private static Mesh GetMeshFromPrefab(BoxType boxType, GameObject boxPrefab) { //IL_0093: 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) if (boxType == BoxType.Ground || boxType == BoxType.GroundNetworked) { GroundBoxHighlightData groundBox = ContainerHighlightData.GroundBox; Transform val = UnityObjectExtensions.NullableObject(boxPrefab.transform.Find(groundBox.VanillaName)); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogError("The '" + groundBox.VanillaName + "' child GameObject for " + $"box {boxType} could not be found. Highlight for " + ((boxType == BoxType.Held) ? "held" : "ground") + " boxes wont work.", (LogCategories)67108864); return null; } localScaleGroundBox = val.localScale; MeshFilter obj = UnityObjectExtensions.NullableObject(((Component)val).GetComponent()); Mesh val2 = ((obj != null) ? obj.sharedMesh : null); if (Object.op_Implicit((Object)(object)val2)) { meshCubeGroundBoxCached = val2; return val2; } TimeLogger.Logger.LogError($"The MeshFilter for box {boxType}" + "could not be found. Highlight for held and ground boxes wont work.", (LogCategories)67108864); return null; } return meshCubeGroundBoxCached; } } public enum HighlightMode { [Description("Disabled")] Disabled, [Description("Outline only")] OutlineOnly, [Description("Outline & glow")] OutlineGlow, [Description("Outline & blurred glow")] OutlineBlurredGlow, [Description("See-through")] SeeThrough } public static class ContainerHighlightManager { private static readonly int maxHighlightEnumValue = Enum.GetValues(typeof(HighlightMode)).Cast().Max(); private static int highlightedProductId; public static HighlightContainerCache HighlightCache { get; private set; } public static void InitHighlightManager() { WorldState.OnLoadingWorld += delegate { HighlightCache = new HighlightContainerCache(); highlightedProductId = -1; }; WorldState.OnFPControllerStarted += delegate { HighlightInitialization.PopulateNonParentedBoxes(); }; BoxPrefabPatching.PrepareBoxPrefabPatching(); Material[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Material val in array) { if (((Object)val).name == "Back3 (Instance)") { val.shader = Shader.Find("Universal Render Pipeline/Lit"); break; } } } public static HighlightMode GetCurrentHighlightMode() { return ModConfig.Instance.HighlightVisualMode.Value; } public static bool IsAnyContainerHighlighted() { if (highlightedProductId >= 0) { return HighlightCache.HasActiveObjects(); } return false; } public static void ChangeToNextHighlightMode() { ConfigEntry highlightVisualMode = ModConfig.Instance.HighlightVisualMode; if ((int)highlightVisualMode.Value >= maxHighlightEnumValue) { highlightVisualMode.Value = HighlightMode.Disabled; } else { HighlightMode value = highlightVisualMode.Value; highlightVisualMode.Value = value + 1; } TimeLogger.Logger.SendMessageNotification((LogTier)16, "Highlight mode => '" + EnumExtension.GetDescription((Enum)highlightVisualMode.Value) + "'", true); ConfigManagerController.RefreshGUI(); } public static void UpdateHighlightMode() { Dictionary dictionary = null; if (IsAnyContainerHighlighted()) { dictionary = new Dictionary(HighlightCache.GetActiveCachedObjects()); ClearHighlightedContainers(clearProductIdFlag: false); } if (GetCurrentHighlightMode() == HighlightMode.Disabled) { return; } HighlightInitialization.ReinitializeAllContainerHighlights(); if (dictionary != null) { foreach (KeyValuePair item in dictionary) { HighlightLogic.SetHighlighting(item.Key, item.Value); } return; } if (GetCurrentHighlightMode() != 0 && AuxUtils.IsPlayerHoldingBox(out var productId)) { HighlightContainersByProduct(productId); } } public static void ToggleCrosshairInProductHighlight() { if (GetCurrentHighlightMode() == HighlightMode.Disabled) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "Highlight is currently disabled in the settings", true); return; } PlayerNetwork val = SMTInstances.LocalPlayerNetwork(); bool flag = IsAnyContainerHighlighted(); ClearHighlightedContainers(clearProductIdFlag: true); int targetedProductId = val.oldCanvasProductID; int productId; if (targetedProductId >= 0 || IsGroundBoxOnCrosshair(val, out targetedProductId)) { HighlightContainersByProduct(targetedProductId); } else if (!flag && AuxUtils.IsPlayerHoldingBox(out productId)) { HighlightContainersByProduct(productId); } } private static bool IsGroundBoxOnCrosshair(PlayerNetwork pNetwork, out int targetedProductId) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) targetedProductId = -1; RaycastHit val = default(RaycastHit); BoxData val2 = default(BoxData); if (Physics.Raycast(((Component)Camera.main).transform.position, ((Component)Camera.main).transform.forward, ref val, 4f, LayerMask.op_Implicit(pNetwork.interactableMask)) && ((Component)((RaycastHit)(ref val)).transform).TryGetComponent(ref val2)) { int productID = val2.productID; if (productID >= 0) { targetedProductId = productID; return true; } } return false; } public static void UpdateHighlightColorsFromSettings(ContainerTypeFlags containerTypeFlags) { if (GetCurrentHighlightMode() == HighlightMode.Disabled) { return; } foreach (KeyValuePair activeCachedObject in HighlightCache.GetActiveCachedObjects()) { ContainerType containerType = activeCachedObject.Value.ContainerType; if (containerTypeFlags.HasFlag((ContainerTypeFlags)containerType)) { HighlightLogic.SetChangeableHighlightProperties(activeCachedObject.Key, containerType); } } } public static void AddHighlightMarkersToStorage(Transform storage) { StorageShelfHighlightData storage2 = ContainerHighlightData.Storage; Transform val = storage.Find(storage2.SQoLName); if (Object.op_Implicit((Object)(object)val)) { return; } val = Object.Instantiate(((Component)storage.Find(storage2.VanillaName)).gameObject, storage).transform; ((Object)val).name = storage2.SQoLName; HighlightTargetCollection highlightTargets = new HighlightTargetCollection(ContainerType.StorageSlot); HighlightEffect val2 = default(HighlightEffect); for (int i = 0; i < val.childCount; i++) { Transform child = val.GetChild(i).GetChild(0); if (((Component)child).TryGetComponent(ref val2)) { Object.Destroy((Object)(object)val2); } highlightTargets.TryAddHighlightTarget(child, isEnableHighlight: false); } HighlightInitialization.InitializeHighlightProperties(((Component)val).gameObject.AddComponent(), highlightTargets); HighlightInitialization.InitializeSingleTransformHighlightProperties(storage, ContainerType.Storage); } public static void UpdateBoxHighlight(Transform box) { if (!Object.op_Implicit((Object)(object)box)) { TimeLogger.Logger.LogError("Box spawned but transform parameter is null.", (LogCategories)67108864); } else { UpdateContainerHighlighting(box, ParentContainerType.GroundBox); } } public static void ClearHighlightedContainers(bool clearProductIdFlag) { if (!IsAnyContainerHighlighted()) { return; } if (clearProductIdFlag) { highlightedProductId = -1; } foreach (KeyValuePair activeCachedObject in HighlightCache.GetActiveCachedObjects()) { HighlightLogic.SetHighlighting(activeCachedObject.Key, activeCachedObject.Value, false); } HighlightCache.ClearCache(); } public static void HighlightContainersByProduct(int productID) { if (GetCurrentHighlightMode() != 0) { highlightedProductId = productID; HighlightContainerTypeByProduct(productID, ParentContainerType.ProductDisplay); HighlightContainerTypeByProduct(productID, ParentContainerType.Storage); HighlightContainerTypeByProduct(productID, ParentContainerType.GroundBox); UpdateAllPlayersAndEmployeesHeldBoxes(); } } private static void HighlightContainerTypeByProduct(int productID, ParentContainerType parentContainerType) { Transform[] gameObjectFromParentContainerType = ContainerHighlightData.GetGameObjectFromParentContainerType(parentContainerType); for (int i = 0; i < gameObjectFromParentContainerType.Length; i++) { UpdateContainerHighlighting(gameObjectFromParentContainerType[i], productID, parentContainerType); } if (parentContainerType != ParentContainerType.GroundBox || WorldState.CurrentOnlineMode != GameOnlineMode.Client) { return; } foreach (Transform nonParentedBox in HighlightInitialization.GetNonParentedBoxes()) { UpdateContainerHighlighting(nonParentedBox, productID, parentContainerType); } } public static void UpdateContainerHighlighting(Transform container, ParentContainerType parentContainerType) { if (GetCurrentHighlightMode() != 0) { UpdateContainerHighlighting(container, highlightedProductId, parentContainerType); } } private static void UpdateContainerHighlighting(Transform container, int productID, ParentContainerType parentContainerType) { switch (parentContainerType) { case ParentContainerType.GroundBox: { bool flag = productID >= 0 && ((Component)container).GetComponent().productID == productID; GroundBoxHighlightData groundBox = ContainerHighlightData.GroundBox; Transform val2 = container.Find(groundBox.SQoLName); if (!Object.op_Implicit((Object)(object)val2)) { TimeLogger.Logger.LogError("The highlightsMarker object for this box could not be found. Highlighting wont work in this ground box.", (LogCategories)67108864); break; } HighlightEffect component = ((Component)val2).GetComponent(); if (HasDifferentHighlightState(flag, val2, component, (ContainerType)parentContainerType)) { HighlightLogic.SetSingleTransformHighlighting(val2, (ContainerType)parentContainerType, flag); } break; } case ParentContainerType.ProductDisplay: case ParentContainerType.Storage: { int[] productInfoArray = ((Component)container).GetComponent().productInfoArray; int num = productInfoArray.Length / 2; bool isEnableHighlight = false; ContainerHighlightData fromContainerParentType = ContainerHighlightData.GetFromContainerParentType(parentContainerType); Transform val = container.Find(fromContainerParentType.SQoLName); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogError($"The highlightsMarker object for this container '{container}' " + $"(instanceId {((Object)container).GetInstanceID()}) of type {fromContainerParentType.ParentContainerType} " + "could not be found. Highlighting wont work in this object.", (LogCategories)67108864); break; } ContainerType containerType = parentContainerType switch { ParentContainerType.ProductDisplay => ContainerType.ProdShelfSlot, ParentContainerType.Storage => ContainerType.StorageSlot, _ => throw new NotSupportedException($"Container type {parentContainerType} is not valid here."), }; HighlightTargetCollection highlightTargetCollection = new HighlightTargetCollection(containerType); for (int i = 0; i < num; i++) { bool enableSlotHighlight = false; if (productID >= 0 && productInfoArray[i * 2] == productID) { enableSlotHighlight = true; isEnableHighlight = true; } ProcessShelfSlotHighlight(val, i, containerType, enableSlotHighlight, highlightTargetCollection); } if (parentContainerType == ParentContainerType.Storage) { HighlightLogic.SetHighlighting(((Component)val).GetComponent(), highlightTargetCollection); } HighlightLogic.SetSingleTransformHighlighting(container, (ContainerType)parentContainerType, isEnableHighlight); break; } } } public static void UpdateHeldBoxHighlighting(Transform charTransform, Transform boxTransform, int productIdBox, CharacterSourceType charSource) { UpdateHeldBoxHighlighting(charTransform, charSource, productIdBox); } public static void UpdateAllPlayersAndEmployeesHeldBoxes() { foreach (CharacterData allHeldBoxesDatum in HighlightInitialization.GetAllHeldBoxesData()) { UpdateHeldBoxHighlighting(allHeldBoxesDatum.CharTransform, allHeldBoxesDatum.CharSource, allHeldBoxesDatum.HeldProductId); } } public static void UpdateHeldBoxHighlighting(Transform charTransform, CharacterSourceType charSource, int productIdBox) { if (HighlightInitialization.GetBoxDataFromCharacter(charTransform, charSource, out var boxHighlightT, out var _) && IsHeldBoxNeedUpdate(boxHighlightT, productIdBox, out var enableHighlight)) { HighlightLogic.SetSingleTransformHighlighting(boxHighlightT, ContainerType.GroundBox, enableHighlight); } } private static bool IsHeldBoxNeedUpdate(Transform boxHighlightT, int productIdBox, out bool enableHighlight) { HighlightEffect highlightEffect = default(HighlightEffect); if (Object.op_Implicit((Object)(object)boxHighlightT) && ((Component)boxHighlightT).TryGetComponent(ref highlightEffect)) { enableHighlight = productIdBox == highlightedProductId; bool flag = HighlightLogic.IsHighlightActive(boxHighlightT, highlightEffect, ContainerType.GroundBox); return enableHighlight != flag; } enableHighlight = false; return false; } private static void ProcessShelfSlotHighlight(Transform highlightsMarker, int slotIndex, ContainerType containerType, bool enableSlotHighlight, HighlightTargetCollection objCollection) { Transform child; HighlightEffect component; switch (containerType) { case ContainerType.StorageSlot: child = highlightsMarker.GetChild(slotIndex).GetChild(0); component = ((Component)highlightsMarker).GetComponent(); break; case ContainerType.ProdShelfSlot: child = highlightsMarker.GetChild(slotIndex); component = ((Component)child).GetComponent(); break; default: throw new NotSupportedException($"Container {containerType} is not valid."); } if (HasDifferentHighlightState(enableSlotHighlight, child, component, containerType)) { if (containerType == ContainerType.StorageSlot) { objCollection.TryAddHighlightTarget(highlightsMarker.GetChild(slotIndex).GetChild(0), enableSlotHighlight); } else { HighlightLogic.SetSingleTransformHighlighting(highlightsMarker.GetChild(slotIndex), ContainerType.ProdShelfSlot, enableSlotHighlight); } } } private static bool HasDifferentHighlightState(bool enableSlotHighlight, Transform transform, HighlightEffect highlightEffect, ContainerType containerType) { if (!Object.op_Implicit((Object)(object)highlightEffect) && HighlightInitialization.IsPreinitializedContainer(containerType)) { TimeLogger.Logger.LogError($"The HighlightEffect object for this container '{transform}' " + $"container of type {containerType} could not be found but it should exist.", (LogCategories)67108864); } bool flag = Object.op_Implicit((Object)(object)highlightEffect) && HighlightLogic.IsHighlightActive(transform, highlightEffect, containerType); return enableSlotHighlight != flag; } } public record struct CharacterData(Transform CharTransform, CharacterSourceType CharSource, int HeldProductId); public class HighlightInitialization { private class PropertiesInitializer { public static void SetInitialSingleTransformHighlightProperties(Transform t, HighlightEffect highlightEffect, ContainerType containerType, bool forceInitialization) { if (SetInitialHighlightProperties(highlightEffect, containerType, forceInitialization)) { InitializeTransformRenderer(t); HighlightLogic.SetToBaseHighlightState(t, highlightEffect, containerType); } } public static void SetInitialHighlightProperties(HighlightEffect highlightEffect, HighlightTargetCollection highlightTargets, bool forceInitialization) { if (!SetInitialHighlightProperties(highlightEffect, highlightTargets.ContainerType, forceInitialization)) { return; } foreach (HighlightTarget item in highlightTargets.GetActiveObjectSet()) { InitializeTransformRenderer(item.Transform); HighlightLogic.SetToBaseHighlightState(item.Transform, highlightEffect, highlightTargets.ContainerType); } } private static bool SetInitialHighlightProperties(HighlightEffect highlightEffect, ContainerType containerType, bool forceInitialization) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)highlightEffect)) { TimeLogger.Logger.LogError("The highlightEffect parameter cannot be null.", (LogCategories)67108864); return false; } if (!forceInitialization && IsHighlightEffectInitialized(highlightEffect)) { TimeLogger.Logger.LogError($"The highlightEffect '{((Component)highlightEffect).transform}' of type " + $"'{containerType}' tried to be initialized again.", (LogCategories)67108864); return false; } highlightEffect.outlineQuality = (QualityLevel)1; highlightEffect.useSmoothOutline = true; highlightEffect.outlineMaskMode = (MaskMode)2; highlightEffect.outlineIndependent = true; highlightEffect.outlineContourStyle = (ContourStyle)1; highlightEffect.constantWidth = true; highlightEffect.glowWidth = 0.0001f; highlightEffect.effectNameFilter = null; highlightEffect.glowMaskMode = (MaskMode)2; highlightEffect.normalsOption = (NormalsOption)1; highlightEffect.fadeInDuration = 0.2f; highlightEffect.fadeOutDuration = 0.15f; HighlightMode currentHighlightMode = ContainerHighlightManager.GetCurrentHighlightMode(); highlightEffect.outlineVisibility = HighlightValueDefinitions.GetOutlineVisibility(currentHighlightMode, containerType); highlightEffect.glowVisibility = HighlightValueDefinitions.GetGlowVisibility(currentHighlightMode, containerType); highlightEffect.glowBlurMethod = HighlightValueDefinitions.GetGlowBlurMethod(currentHighlightMode, containerType); highlightEffect.glowQuality = HighlightValueDefinitions.GetGlowQuality(currentHighlightMode, containerType); highlightEffect.glowDownsampling = HighlightValueDefinitions.GetGlowDownsampling(currentHighlightMode, containerType); highlightEffect.seeThrough = HighlightValueDefinitions.GetSeeThrough(currentHighlightMode, containerType); if (currentHighlightMode == HighlightMode.SeeThrough) { highlightEffect.seeThrough = (SeeThroughMode)0; highlightEffect.seeThroughNoise = 0f; } if (HighlightLogic.IsSeparatedHighlightAndRender(containerType) || containerType == ContainerType.ProdShelf) { highlightEffect.effectGroup = (TargetOptions)0; } else { highlightEffect.effectGroup = (TargetOptions)1; } if (containerType == ContainerType.ProdShelf) { MeshCombiner val = default(MeshCombiner); foreach (Transform item in ((Component)highlightEffect).transform.Find("ProductContainer")) { if (((Component)item).TryGetComponent(ref val) && Object.op_Implicit((Object)(object)val)) { MeshCombiner obj = val; obj.OnRenderersUpdated = (UnityAction)(object)Delegate.Combine((Delegate?)(object)obj.OnRenderersUpdated, (Delegate?)(object)(UnityAction)delegate(Renderer[] r) { RefreshHighlightRenderers(highlightEffect, r); }); } } } ((Behaviour)highlightEffect).enabled = true; highlightEffect.targetFXGroundMaxDistance = InitializedHighlightEffectValue; return true; } private static void RefreshHighlightRenderers(HighlightEffect highlightEffect, Renderer[] renderers) { if (Object.op_Implicit((Object)(object)highlightEffect) && highlightEffect.highlighted) { highlightEffect.Refresh(false); } } private static void InitializeTransformRenderer(Transform t) { if (!IsHighlightTransformInitialized(t)) { Material[] materials = ((Component)t).GetComponent().materials; for (int i = 0; i < materials.Length; i++) { materials[i].renderQueue = 1000; } ((Component)t).gameObject.AddComponent(); } } } private class HighlightInitialized : MonoBehaviour { } public static readonly float InitializedHighlightEffectValue = 55224.312f; private static List nonParentedBoxes; public static bool IsHighlightTransformInitialized(Transform t) { return Object.op_Implicit((Object)(object)((Component)t).GetComponent()); } public static bool IsHighlightEffectInitialized(HighlightEffect he) { return he.targetFXGroundMaxDistance == InitializedHighlightEffectValue; } public static bool IsPreinitializedContainer(ContainerType containerType) { if (containerType == ContainerType.Storage || containerType == ContainerType.StorageSlot || containerType == ContainerType.GroundBox) { return true; } return false; } public static void ReinitializeAllContainerHighlights() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown foreach (Transform item in NPC_Manager.Instance.shelvesOBJ.transform) { ReinitializeSingleTransformHighlightProperties(item, ContainerType.ProdShelf); Transform val2 = item.Find(ContainerHighlightData.Products.SQoLName); if (!Object.op_Implicit((Object)(object)val2)) { continue; } foreach (Transform item2 in val2) { ReinitializeSingleTransformHighlightProperties(item2, ContainerType.ProdShelfSlot); } } foreach (Transform item3 in NPC_Manager.Instance.storageOBJ.transform) { ReinitializeSingleTransformHighlightProperties(item3, ContainerType.Storage); Transform val4 = item3.Find(ContainerHighlightData.Storage.SQoLName); if (Object.op_Implicit((Object)(object)val4)) { HighlightTargetCollection highlightTargets = new HighlightTargetCollection(ContainerType.StorageSlot); foreach (Transform item4 in val4) { Transform val5 = item4; highlightTargets.TryAddHighlightTarget(val5.GetChild(0), isEnableHighlight: false); } ReinitializeHighlightProperties(((Component)val4).GetComponent(), highlightTargets); } else { TimeLogger.Logger.LogError("The highlightsMarker object for the storage could not be found. Storage slot highlighting wont work.", (LogCategories)67108864); } } Transform[] existingParentedBoxes = ContainerHighlightData.GetExistingParentedBoxes(); int i; for (i = 0; i < existingParentedBoxes.Length; i++) { Transform val6 = existingParentedBoxes[i].Find(ContainerHighlightData.GroundBox.SQoLName); if (Object.op_Implicit((Object)(object)val6)) { ReinitializeSingleTransformHighlightProperties(val6, ContainerType.GroundBox); } else { TimeLogger.Logger.LogError("The highlightsMarker object for the ground box could not be found. Ground box highlighting wont work.", (LogCategories)67108864); } } if (WorldState.CurrentOnlineMode == GameOnlineMode.Client) { foreach (Transform nonParentedBox in GetNonParentedBoxes()) { Transform val7 = nonParentedBox.Find(ContainerHighlightData.GroundBox.SQoLName); if (Object.op_Implicit((Object)(object)val7)) { ReinitializeSingleTransformHighlightProperties(val7, ContainerType.GroundBox); } } } foreach (CharacterData allHeldBoxesDatum in GetAllHeldBoxesData()) { if (GetBoxDataFromCharacter(allHeldBoxesDatum.CharTransform, allHeldBoxesDatum.CharSource, out var _, out i)) { ReinitializeSingleTransformHighlightProperties(allHeldBoxesDatum.CharTransform, ContainerType.GroundBox); } } } public static void InitializeHighlightProperties(HighlightEffect highlightEffect, HighlightTargetCollection highlightTargets) { PropertiesInitializer.SetInitialHighlightProperties(highlightEffect, highlightTargets, forceInitialization: false); } public static void InitializeSingleTransformHighlightProperties(Transform t, ContainerType containerType) { InitializeSingleTransformHighlightProperties(t, containerType, forceInitialization: false); } private static void ReinitializeHighlightProperties(HighlightEffect highlightEffect, HighlightTargetCollection highlightTargets) { PropertiesInitializer.SetInitialHighlightProperties(highlightEffect, highlightTargets, forceInitialization: true); } private static void ReinitializeSingleTransformHighlightProperties(Transform t, ContainerType containerType) { InitializeSingleTransformHighlightProperties(t, containerType, forceInitialization: true); } private static void InitializeSingleTransformHighlightProperties(Transform t, ContainerType containerType, bool forceInitialization) { HighlightEffect highlightEffect = default(HighlightEffect); if (((Component)t).TryGetComponent(ref highlightEffect)) { PropertiesInitializer.SetInitialSingleTransformHighlightProperties(t, highlightEffect, containerType, forceInitialization); } else { CreateInitializedSingleTransformHighlight(t, containerType); } } public static HighlightEffect CreateInitializedSingleTransformHighlight(Transform t, ContainerType containerType) { HighlightEffect result = default(HighlightEffect); if (((Component)t).TryGetComponent(ref result)) { TimeLogger.Logger.LogWarning($"Transform {t} already has an HighlightEffect component", (LogCategories)67108864); return result; } if (HighlightLogic.IsSeparatedHighlightAndRender(containerType)) { TimeLogger.Logger.LogWarning("Something went wrong. This transform was set to be initialized, but this type of highlight should have been already initialized.", (LogCategories)67108864); return null; } result = ((Component)t).gameObject.AddComponent(); PropertiesInitializer.SetInitialSingleTransformHighlightProperties(t, result, containerType, forceInitialization: false); return result; } public static void InitializeSingleTransformHighlightIfNeeded(Transform t, HighlightEffect highlightEffect, ContainerType containerType) { if (!IsHighlightTransformInitialized(t)) { PropertiesInitializer.SetInitialSingleTransformHighlightProperties(t, highlightEffect, containerType, forceInitialization: false); } } public static void PopulateNonParentedBoxes() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) nonParentedBoxes = new List(); Scene activeScene = SceneManager.GetActiveScene(); Transform[] array = (from g in ((Scene)(ref activeScene)).GetRootGameObjects() where ((Object)g).name == "1_Box(Clone)" select g.transform).ToArray(); foreach (Transform item in array) { nonParentedBoxes.Add(item); } TimeLogger.Logger.LogDebugFunc((Func)(() => $"{nonParentedBoxes.Count} non parented boxes populated."), (LogCategories)67108864); } public static List GetNonParentedBoxes() { if (nonParentedBoxes == null) { return new List(); } nonParentedBoxes = nonParentedBoxes.Where((Transform g) => Object.op_Implicit((Object)(object)g)).ToList(); return nonParentedBoxes; } public static bool GetBoxDataFromCharacter(Transform charTransform, CharacterSourceType charSource, out Transform boxHighlightT, out int boxProductId) { boxHighlightT = null; boxProductId = -1; GroundBoxHighlightData groundBox = ContainerHighlightData.GroundBox; switch (charSource) { case CharacterSourceType.Employee: { NPC_Info val = default(NPC_Info); if (((Component)charTransform).TryGetComponent(ref val) && val.equippedItem == 1) { GameObject obj3 = UnityObjectExtensions.NullableObject(val.instantiatedOBJ); boxHighlightT = ((obj3 != null) ? obj3.transform.Find(groundBox.SQoLName) : null); boxProductId = val.boxProductID; } break; } case CharacterSourceType.LocalPlayer: { PlayerNetwork component3 = ((Component)charTransform).GetComponent(); if (Object.op_Implicit((Object)(object)component3) && component3.equippedItem == 1) { GameObject obj2 = UnityObjectExtensions.NullableObject(component3.instantiatedOBJ); boxHighlightT = ((obj2 != null) ? obj2.transform.Find(groundBox.SQoLName) : null); boxProductId = component3.extraParameter1; } break; } case CharacterSourceType.RemotePlayer: { PlayerNetwork component = ((Component)charTransform).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.equippedItem == 1) { GameObject obj = UnityObjectExtensions.NullableObject(component.instantiatedOBJ); boxHighlightT = ((obj != null) ? obj.transform.Find(groundBox.SQoLName) : null); PlayerSyncCharacter component2 = ((Component)charTransform).GetComponent(); boxProductId = component2.syncedProductID; } break; } } return Object.op_Implicit((Object)(object)boxHighlightT); } public static List GetAllHeldBoxesData() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown List list = new List(); Transform boxHighlightT; foreach (Transform item in NPC_Manager.Instance.employeeParentOBJ.transform) { Transform charTransform = item; GetBoxDataFromCharacter(charTransform, CharacterSourceType.Employee, out boxHighlightT, out var boxProductId); list.Add(new CharacterData(charTransform, CharacterSourceType.Employee, boxProductId)); } foreach (GameObject remotePlayerObject in AuxUtils.GetRemotePlayerObjects()) { GetBoxDataFromCharacter(remotePlayerObject.transform, CharacterSourceType.RemotePlayer, out boxHighlightT, out var boxProductId2); list.Add(new CharacterData(remotePlayerObject.transform, CharacterSourceType.RemotePlayer, boxProductId2)); } return list; } public static void InitializeBoxHighlight(Transform box, Mesh cubeMesh, Vector3 highLightLocalScale) { //IL_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0060: 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_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references) GroundBoxHighlightData groundBox = ContainerHighlightData.GroundBox; if (Object.op_Implicit((Object)(object)box) && !Object.op_Implicit((Object)(object)box.Find(groundBox.SQoLName))) { GameObject val = new GameObject(ContainerHighlightData.GroundBox.SQoLName); val.AddComponent(); val.AddComponent().sharedMesh = cubeMesh; val.transform.parent = box; val.transform.localPosition = Vector3.zero; val.transform.localScale = highLightLocalScale; val.transform.rotation = Quaternion.identity; val.SetActive(true); CreateInitializedSingleTransformHighlight(val.transform, ContainerType.GroundBox); } } } public static class HighlightLogic { public static bool IsHighlightActive(Transform t, HighlightEffect highlightEffect, ContainerType containerType) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 if (containerType.UsesObjActivation()) { if (!IsSeparatedHighlightAndRender(containerType) || !((Component)t).gameObject.activeSelf) { if (!IsSeparatedHighlightAndRender(containerType)) { return ((Component)highlightEffect).gameObject.activeSelf; } return false; } return true; } if (highlightEffect.highlighted) { return (int)highlightEffect.fading != -1; } return false; } private static bool UsesObjActivation(this ContainerType containerType) { if (containerType != ContainerType.StorageSlot) { return containerType == ContainerType.GroundBox; } return true; } public static bool IsSlotOrBox(this ContainerType containerType) { if (containerType != ContainerType.StorageSlot && containerType != ContainerType.ProdShelfSlot) { return containerType == ContainerType.GroundBox; } return true; } public static bool IsBox(this ContainerType containerType) { if (containerType != ContainerType.StorageSlot) { return containerType == ContainerType.GroundBox; } return true; } public static bool IsSeparatedHighlightAndRender(ContainerType containerType) { return containerType == ContainerType.StorageSlot; } public static void SetHighlighting(HighlightEffect highlightEffect, HighlightTargetCollection highlightTargets, bool? isEnableHighlight = null) { if (!HighlightInitialization.IsHighlightEffectInitialized(highlightEffect)) { TimeLogger.Logger.LogError($"Highlight '{((Component)highlightEffect).transform.parent}' of type " + $"{highlightTargets.ContainerType} should have been initialized already but its not.", (LogCategories)67108864); } bool flag = false; foreach (HighlightTarget item in highlightTargets.GetActiveObjectSet()) { bool isEnableHighlight2 = isEnableHighlight ?? item.HighlightStatus; flag |= SetHighlighting(item.Transform, highlightEffect, isEnableHighlight2, highlightTargets.ContainerType); } if (flag) { SetChangeableHighlightProperties(highlightEffect, highlightTargets.ContainerType); } } public static void SetSingleTransformHighlighting(Transform t, ContainerType containerType, bool isEnableHighlight) { if (!GetInitializedSingleTransformHighlight(t, containerType, out var highlightEffect)) { highlightEffect = HighlightInitialization.CreateInitializedSingleTransformHighlight(t, containerType); } if (SetHighlighting(t, highlightEffect, isEnableHighlight, containerType)) { SetChangeableHighlightProperties(highlightEffect, containerType); } } private static bool SetHighlighting(Transform t, HighlightEffect highlightEffect, bool isEnableHighlight, ContainerType containerType) { if (CanSkipHighlighting(t, highlightEffect, isEnableHighlight, containerType)) { return false; } SetHighlightState(t, highlightEffect, isEnableHighlight, containerType, initialization: false); return true; } private static bool CanSkipHighlighting(Transform t, HighlightEffect highlightEffect, bool isEnableHighlight, ContainerType containerType) { if (isEnableHighlight && ContainerHighlightManager.GetCurrentHighlightMode() == HighlightMode.Disabled) { TimeLogger.Logger.LogWarning($"Transform {t} was going to enable its highlighting but the " + "current highlight mode is Disabled. Skipping.Make sure to check earlier in the call chain if highlights are disabled to avoid unnecessary work.", (LogCategories)67108864); return true; } if (IsHighlightActive(t, highlightEffect, containerType) == isEnableHighlight) { return true; } return false; } public static void SetToBaseHighlightState(Transform t, HighlightEffect highlightEffect, ContainerType containerType) { SetHighlightState(t, highlightEffect, isEnableHighlight: false, containerType, initialization: true); } private static void SetHighlightState(Transform t, HighlightEffect highlightEffect, bool isEnableHighlight, ContainerType containerType, bool initialization) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((int)highlightEffect.fading == -1 && isEnableHighlight) { highlightEffect.ImmediateFadeOut(); } else if ((int)highlightEffect.fading == 1 && !isEnableHighlight) { highlightEffect.fading = (FadingState)0; } if (containerType.UsesObjActivation()) { if (initialization) { highlightEffect.Refresh(false); highlightEffect.SetHighlighted(true); } ((Component)t).gameObject.SetActive(isEnableHighlight); } else { highlightEffect.SetHighlighted(isEnableHighlight); } if (isEnableHighlight) { ContainerHighlightManager.HighlightCache.TryAddHighlightedTarget(highlightEffect, t, containerType); } UpdateTransformHighlightRendering(t, highlightEffect, containerType, isEnableHighlight); } private static bool GetInitializedSingleTransformHighlight(Transform t, ContainerType containerType, out HighlightEffect highlightEffect) { if (IsSeparatedHighlightAndRender(containerType)) { TimeLogger.Logger.LogError("This method is for single transforms and not valid " + $"for object type {containerType}.", (LogCategories)67108864); } if (!((Component)t).TryGetComponent(ref highlightEffect)) { return false; } HighlightInitialization.InitializeSingleTransformHighlightIfNeeded(t, highlightEffect, containerType); return true; } public static void SetChangeableHighlightProperties(HighlightEffect highlightEffect, ContainerType containerType) { if (ContainerHighlightManager.GetCurrentHighlightMode() == HighlightMode.Disabled) { return; } ChangeHighlightColor(highlightEffect, containerType); highlightEffect.Refresh(false); if (containerType != ContainerType.ProdShelf) { return; } for (int i = 0; i < highlightEffect.rmsCount; i++) { Renderer renderer = highlightEffect.rms[i].renderer; if (renderer.enabled) { bool flag = IsHighlightActive(((Component)highlightEffect).transform, highlightEffect, containerType); renderer.allowOcclusionWhenDynamic = !flag; } } } private static void ChangeHighlightColor(HighlightEffect highlightEffect, ContainerType containerType) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0090: 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_0093: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) float a = (highlightEffect.seeThroughTintColor = (highlightEffect.glowHQColor = (highlightEffect.outlineColor = (Color)(containerType switch { ContainerType.ProdShelf => ModConfig.Instance.ShelfHighlightColorRGBA.Value, ContainerType.ProdShelfSlot => ModConfig.Instance.ShelfLabelHighlightColorRGBA.Value, ContainerType.Storage => ModConfig.Instance.StorageHighlightColorRGBA.Value, ContainerType.StorageSlot => ModConfig.Instance.StorageSlotHighlightColorRGBA.Value, ContainerType.GroundBox => ModConfig.Instance.StorageSlotHighlightColorRGBA.Value, _ => throw new NotImplementedException(containerType.ToString()), })))).a; HighlightMode currentHighlightMode = ContainerHighlightManager.GetCurrentHighlightMode(); highlightEffect.outline = a * HighlightValueDefinitions.GetOutlineStrength(currentHighlightMode, containerType); highlightEffect.glow = a * HighlightValueDefinitions.GetGlowStrength(currentHighlightMode, containerType, a); highlightEffect.outlineWidth = HighlightValueDefinitions.GetOutlineWidth(currentHighlightMode, containerType, a); if (currentHighlightMode == HighlightMode.SeeThrough) { highlightEffect.seeThroughTintAlpha = Mathf.Lerp(0f, 0.8f, a); highlightEffect.seeThroughIntensity = a; } } private static void UpdateTransformHighlightRendering(Transform t, HighlightEffect highlightEffect, ContainerType containerType, bool isEnableHighlight) { ((Component)t).GetComponent().allowOcclusionWhenDynamic = !isEnableHighlight; LODGroup val = default(LODGroup); if (containerType == ContainerType.ProdShelfSlot && ((Component)t).TryGetComponent(ref val)) { val.enabled = !isEnableHighlight; } } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting.Definitions { public abstract class ContainerHighlightData { public static ProductShelfHighlightData Products { get; } = new ProductShelfHighlightData(); public static StorageShelfHighlightData Storage { get; } = new StorageShelfHighlightData(); public static GroundBoxHighlightData GroundBox { get; } = new GroundBoxHighlightData(); public abstract string SQoLName { get; } public abstract string VanillaName { get; } public abstract ParentContainerType ParentContainerType { get; } public static ContainerHighlightData GetFromContainerParentType(ParentContainerType parentContainerType) { return parentContainerType switch { ParentContainerType.ProductDisplay => Products, ParentContainerType.Storage => Storage, ParentContainerType.GroundBox => GroundBox, _ => throw new NotImplementedException(parentContainerType.ToString()), }; } public static ContainerHighlightData GetFromContainerType(ContainerType parentContainerType) { switch (parentContainerType) { case ContainerType.ProdShelf: case ContainerType.ProdShelfSlot: return Products; case ContainerType.Storage: case ContainerType.StorageSlot: return Storage; case ContainerType.GroundBox: return GroundBox; default: throw new NotImplementedException(parentContainerType.ToString()); } } public static Transform[] GetGameObjectFromParentContainerType(ParentContainerType parentContainerType) { IEnumerable source; switch (parentContainerType) { case ParentContainerType.ProductDisplay: { NPC_Manager instance2 = NPC_Manager.Instance; source = ((instance2 != null) ? ((IEnumerable)instance2.shelvesOBJ.transform).Cast() : null); break; } case ParentContainerType.Storage: { NPC_Manager instance = NPC_Manager.Instance; source = ((instance != null) ? ((IEnumerable)instance.storageOBJ.transform).Cast() : null); break; } case ParentContainerType.GroundBox: source = GetExistingParentedBoxes(); break; default: throw new NotImplementedException($"The container type '{parentContainerType}' is not implemented."); } return source.ToArray(); } public static Transform[] GetExistingParentedBoxes() { ManagerBlackboard val = SMTInstances.ManagerBlackboard(); NPC_Manager instance = NPC_Manager.Instance; if (instance == null) { return null; } return ((IEnumerable)instance.boxesOBJ.transform).Cast().Concat(((IEnumerable)val.boxParent).Cast().Concat(((IEnumerable)val.manufacturingBoxParent).Cast())).ToArray(); } } public class ProductShelfHighlightData : ContainerHighlightData { public override string SQoLName { get; } = "Labels"; public override string VanillaName { get; } = ""; public override ParentContainerType ParentContainerType { get; } = ParentContainerType.ProductDisplay; } public class StorageShelfHighlightData : ContainerHighlightData { public override string SQoLName { get; } = "SQoL_StorageBoxHighlights"; public override string VanillaName { get; } = "Highlights"; public override ParentContainerType ParentContainerType { get; } = ParentContainerType.Storage; } public class GroundBoxHighlightData : ContainerHighlightData { public override string SQoLName { get; } = "SQoL_BoxHighlight"; public override string VanillaName { get; } = "Highlight"; public override ParentContainerType ParentContainerType { get; } = ParentContainerType.GroundBox; } public static class HighlightValueDefinitions { public static float GetOutlineStrength(HighlightMode highlightMode, ContainerType containerType) { switch (highlightMode) { case HighlightMode.OutlineOnly: return 1f; case HighlightMode.OutlineGlow: case HighlightMode.OutlineBlurredGlow: case HighlightMode.SeeThrough: return containerType.IsSlotOrBox() ? 1f : 1.4f; default: throw new NotImplementedException(string.Format("{0} ({1})", "GetOutlineStrength", highlightMode)); } } public static Visibility GetOutlineVisibility(HighlightMode highlightMode, ContainerType containerType) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if ((highlightMode == HighlightMode.OutlineOnly || highlightMode == HighlightMode.SeeThrough) && !containerType.IsBox()) { return (Visibility)1; } return (Visibility)0; } public static float GetOutlineWidth(HighlightMode highlightMode, ContainerType containerType, float colorAlpha) { float num = 1f; float num2 = colorAlpha - 0.85f; if (num2 > 0f) { num = 1f + num2 * 5f; } return ((containerType == ContainerType.ProdShelfSlot) ? 0.5f : 0.3f) * num; } public static float GetGlowStrength(HighlightMode highlightMode, ContainerType containerType, float colorAlpha) { float num = 1f; float num2 = colorAlpha - 0.9f; if (num2 > 0f) { num = 1f + num2 * 10f; } float num3 = num; float num4; if ((highlightMode == HighlightMode.OutlineOnly || highlightMode == HighlightMode.SeeThrough) && !containerType.IsBox()) { num4 = 0f; } else { float num5; switch (containerType) { case ContainerType.ProdShelfSlot: num5 = 2.4f; break; case ContainerType.StorageSlot: case ContainerType.GroundBox: num5 = 1f; break; case ContainerType.ProdShelf: case ContainerType.Storage: num5 = 1.4f; break; default: throw new NotImplementedException(string.Format("{0} ({1})", "GetGlowStrength", containerType)); } num4 = num5; } return num3 * num4; } public static Visibility GetGlowVisibility(HighlightMode highlightMode, ContainerType containerType) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if ((highlightMode == HighlightMode.OutlineOnly || highlightMode == HighlightMode.SeeThrough) && !containerType.IsBox()) { return (Visibility)0; } return (Visibility)2; } public static BlurMethod GetGlowBlurMethod(HighlightMode highlightMode, ContainerType containerType) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return (BlurMethod)(highlightMode switch { HighlightMode.OutlineBlurredGlow => 0, HighlightMode.OutlineGlow => 1, _ => 0, }); } public static int GetGlowDownsampling(HighlightMode highlightMode, ContainerType containerType) { if ((uint)(highlightMode - 2) <= 1u) { return 1; } return 1; } public static QualityLevel GetGlowQuality(HighlightMode highlightMode, ContainerType containerType) { return (QualityLevel)2; } public static SeeThroughMode GetSeeThrough(HighlightMode highlightMode, ContainerType containerType) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (highlightMode == HighlightMode.SeeThrough) { return (SeeThroughMode)0; } return (SeeThroughMode)2; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Highlighting.Caching { public class HighlightContainerCache { private sealed class HighlightEffectComparer : IEqualityComparer { public bool Equals(HighlightEffect o1, HighlightEffect o2) { return ((Object)o1).GetInstanceID() == ((Object)o2).GetInstanceID(); } public int GetHashCode(HighlightEffect o) { return 349513 + ((Object)o).GetInstanceID(); } } private Dictionary ObjectCache; public HighlightContainerCache() { ObjectCache = new Dictionary(new HighlightEffectComparer()); } public bool HasActiveObjects() { if (ObjectCache.Count > 0) { return ObjectCache.Any((KeyValuePair o) => o.Value.HasActiveObjects()); } return false; } public bool TryAddHighlightedTarget(HighlightEffect he, Transform t, ContainerType containerType) { if (!ObjectCache.TryGetValue(he, out var value)) { value = new HighlightTargetCollection(containerType); ObjectCache.Add(he, value); } return value.TryAddHighlightTarget(t, isEnableHighlight: true); } public Dictionary GetActiveCachedObjects() { RemoveDeadReferences(); return ObjectCache; } private void RemoveDeadReferences() { ObjectCache = ObjectCache.Where((KeyValuePair pair) => pair.Value.HasActiveObjects()).ToDictionary((KeyValuePair pair) => pair.Key, (KeyValuePair pair) => pair.Value.GetActiveObjectCollection()); } public void ClearCache() { ObjectCache.Clear(); } } public readonly struct HighlightTargetCollection { private sealed class HighlightTargetComparer : IEqualityComparer { public bool Equals(HighlightTarget o1, HighlightTarget o2) { return o1.Equals(o2); } public int GetHashCode(HighlightTarget o) { return o.GetHashCode(); } } public ContainerType ContainerType { get; } private HashSet ObjectCollection { get; } public HighlightTargetCollection(ContainerType containerType) { ContainerType = containerType; ObjectCollection = new HashSet(new HighlightTargetComparer()); } public bool TryAddHighlightTarget(Transform t, bool isEnableHighlight) { return ObjectCollection.Add(new HighlightTarget(t, isEnableHighlight)); } public bool HasActiveObjects() { return ObjectCollection.Any((HighlightTarget ho) => Object.op_Implicit((Object)(object)ho.Transform)); } public void RemoveDeadReferences() { ObjectCollection.RemoveWhere((HighlightTarget ho) => !Object.op_Implicit((Object)(object)ho.Transform)); } public HighlightTargetCollection GetActiveObjectCollection() { RemoveDeadReferences(); return this; } public IReadOnlyCollection GetActiveObjectSet() { return GetActiveObjectCollection().ObjectCollection; } } public readonly struct HighlightTarget : IEquatable { public Transform Transform { get; } public bool HighlightStatus { get; } public HighlightTarget(Transform transform, bool highlightStatus) { Transform = transform; HighlightStatus = highlightStatus; } public override bool Equals(object obj) { return Equals((HighlightTarget)obj); } public bool Equals(HighlightTarget obj) { return ((Object)Transform).GetInstanceID() == ((Object)obj.Transform).GetInstanceID(); } public override int GetHashCode() { return 248253 + ((Object)Transform).GetInstanceID(); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Equipment { public enum ToolIndexes { [Description("Nothing")] Nothing, [Description("Box")] Box, [Description("Pricing Scanner")] PricingScanner, [Description("Broom")] Broom, [Obsolete("Replaced with PaintablesTablet")] [Description("Decoration Tablet")] DecoTablet, [Description("Paintables Tablet")] PaintablesTablet, [Description("Order Device")] OrderingDevice, [Description("SledgeHammer")] SledgeHammer, [Description("Ladder")] Ladder, [Description("Blue Tray")] BlueTray, [Description("Sales Device")] SalesDevice, [Description("Cardboard Bale")] CardboardBale, [Description("Order Box")] OrderBox, [Description("Net Catcher")] NetCatcher, [Description("Toolbox")] Toolbox, [Description("Fire Extinguisher")] Extinguisher } public static class EquipmentManager { private class PropsCache { private static GameObject usablePropsObjCache; private static GameObject decoPropsObjCache; private static readonly string usablePropsPath = "Level_SupermarketProps/UsableProps"; private static readonly string decorationPropsPath = "Level_SupermarketProps/DecorationProps"; public static GameObject UsablePropsObjReference => GeGameObjectReference(ref usablePropsObjCache, usablePropsPath); public static GameObject DecoPropsObjCache => GeGameObjectReference(ref decoPropsObjCache, decorationPropsPath); private static GameObject GeGameObjectReference(ref GameObject propsObjCache, string propsPath) { if (!Object.op_Implicit((Object)(object)propsObjCache)) { propsObjCache = GameObject.Find(propsPath); if (!Object.op_Implicit((Object)(object)propsObjCache)) { TimeLogger.Logger.LogError("A GameObject couldnt be found with path " + propsPath, (LogCategories)2); return null; } } return propsObjCache; } } public static bool ExistsUnusedToolOfIndex(PlayerNetwork pNetwork, int toolIndex, out Func toolRequestMethod) { toolRequestMethod = null; ToolWheelDefinition toolData = ToolWheelDefinitions.FromIndex(toolIndex); if (!((Component)FirstPersonController.Instance).GetComponent().RequestGP()) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "You do not have the basic multiplayer permission to equip any tools", true); return false; } if (!HostPermissions.HasPermission(toolData.RequiredPermission)) { TimeLogger.Logger.SendMessageNotification((LogTier)8, $"You need '{toolData.RequiredPermission}' permission to equip this tool", true); return false; } if (FindToolInWorld(toolData, out var toolObj)) { toolRequestMethod = () => RequestToolFromWorld(pNetwork, toolObj, toolData); return true; } if (FindToolInOrganizer(toolData, out toolRequestMethod)) { return true; } TimeLogger.Logger.SendMessageNotification((LogTier)8, "No free " + toolData.DisplayName + " found in map or organizer", true); return false; } private static bool RequestToolFromWorld(PlayerNetwork pNetwork, GameObject toolObj, ToolWheelDefinition toolData) { if (toolData.Index == ToolIndexes.Extinguisher) { AchievementsManager.Instance.grabbedAnExtinguisher = true; } else if (toolData.Index == ToolIndexes.BlueTray) { TrayData val = default(TrayData); if (!toolObj.TryGetComponent(ref val)) { TimeLogger.Logger.SendMessageNotification((LogTier)2, "Error reading tray contents", true); return false; } pNetwork.trayData = val.itemsData; } SMTInstances.NetworkSpawner().CmdDestroyBox(toolObj); return true; } public static bool FindToolInWorld(ToolWheelDefinition toolData, out GameObject foundObj) { //IL_0090: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown bool flag = false; foundObj = null; string usablePropName = toolData.ToolGameObjects.UsablePropName; if (usablePropName == null) { return false; } if (Object.op_Implicit((Object)(object)PropsCache.UsablePropsObjReference)) { foreach (Transform item in PropsCache.UsablePropsObjReference.transform) { Transform val = item; if (Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeSelf && ((Object)val).name.Contains(usablePropName)) { flag = true; foundObj = ((Component)val).gameObject; break; } } } if (!flag) { Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); foreach (GameObject val2 in rootGameObjects) { if (Object.op_Implicit((Object)(object)val2) && val2.activeSelf && ((Object)val2).name.Contains(usablePropName)) { flag = true; foundObj = val2.gameObject; break; } } } return flag; } public static bool FindToolInOrganizer(ToolWheelDefinition toolData, out Func toolRequestMethod) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) bool flag = false; toolRequestMethod = null; string organizerName = toolData.ToolGameObjects.OrganizerName; if (organizerName == null) { return false; } if (Object.op_Implicit((Object)(object)PropsCache.DecoPropsObjCache)) { foreach (Transform item in PropsCache.DecoPropsObjCache.transform) { if (IsRequestedToolMethod(((Component)item).gameObject, organizerName, toolData, out toolRequestMethod)) { flag = true; break; } } } if (!flag) { Scene activeScene = SceneManager.GetActiveScene(); GameObject[] rootGameObjects = ((Scene)(ref activeScene)).GetRootGameObjects(); for (int i = 0; i < rootGameObjects.Length; i++) { if (IsRequestedToolMethod(rootGameObjects[i], organizerName, toolData, out toolRequestMethod)) { flag = true; break; } } } return flag; } private static bool IsRequestedToolMethod(GameObject orgPropsContainer, string orgObjName, ToolWheelDefinition toolData, out Func toolRequestMethod) { toolRequestMethod = null; if (!Object.op_Implicit((Object)(object)orgPropsContainer) || !orgPropsContainer.activeSelf || !((Object)orgPropsContainer).name.Contains(orgObjName)) { return false; } ToolsOrganizer toolOrg = default(ToolsOrganizer); if (toolData.Index == ToolIndexes.Extinguisher) { FireExtinguisherTake fireExt = default(FireExtinguisherTake); if (orgPropsContainer.TryGetComponent(ref fireExt) && !fireExt.extinguisherTaken) { toolRequestMethod = delegate { fireExt.CmdRequestItem(true); AchievementsManager.Instance.grabbedAnExtinguisher = true; return true; }; return true; } } else if (orgPropsContainer.TryGetComponent(ref toolOrg) && toolOrg.itemsInOrganizer > 0) { toolRequestMethod = delegate { toolOrg.CmdRequestItem(true); return true; }; return true; } return false; } public static bool CanDropItemInFront(PlayerNetwork pNetwork, out Vector3 dropPosition, out ToolWheelDefinition equippedTool) { //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) //IL_0091: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) dropPosition = Vector3.zero; equippedTool = null; if (Object.op_Implicit((Object)(object)pNetwork) && pNetwork.equippedItem > 0) { if (!Enum.IsDefined(typeof(ToolIndexes), pNetwork.equippedItem)) { TimeLogger.Logger.LogFatal($"Player has the item '{pNetwork.equippedItem}' " + "equipped, but it has not beed added yet to the definitions.", (LogCategories)2); return false; } equippedTool = ToolWheelDefinitions.FromIndex(pNetwork.equippedItem); if (equippedTool.CmdSpawnMethod == null) { return false; } Transform transform = ((Component)Camera.main).transform; Vector3 position = transform.position; RaycastHit val = default(RaycastHit); if (Physics.Raycast(position, transform.forward, ref val, 4f, LayerMask.op_Implicit(pNetwork.lMask))) { Vector3 point = ((RaycastHit)(ref val)).point; Vector3 normal = ((RaycastHit)(ref val)).normal; dropPosition = point + ((Vector3)(ref normal)).normalized * 0.5f; RaycastHit val2 = default(RaycastHit); if ((((Component)((RaycastHit)(ref val)).transform).gameObject.tag == Tags.Interactable && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).transform).GetComponent())) || (Physics.Raycast(position, transform.forward, ref val2, 4f, LayerMask.op_Implicit(pNetwork.interactableMask)) && ((Component)((RaycastHit)(ref val2)).transform).gameObject.tag == Tags.Interactable)) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "Item cant be dropped here", true); return false; } } else { dropPosition = position + transform.forward * 3.5f; } return true; } return false; } public static bool DropCurrentEquippedItem(PlayerNetwork pNetwork, Vector3 dropPosition, ToolWheelDefinition equippedTool) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (pNetwork.equippedItem > 0) { equippedTool.CmdSpawnMethod(SMTInstances.NetworkSpawner(), pNetwork, dropPosition); pNetwork.CmdChangeEquippedItem(0); return true; } return false; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.RadialWheel { public record RadialRefs(GameObject RadialObj, RadialMenu RadialMenu, Dictionary IndexMapping); public static class RadialWheelInitialization { private static readonly string iconBundlePath = "Assets\\EquipmentWheel\\WheelIcons"; private static readonly string baseUnityPath = "assets\\RadialWheel\\"; public static RadialRefs LoadEquipmentWheel(out Dictionary quickKeysData) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_013b: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { AssetBundleElement val2 = new AssetBundleElement(typeof(RadialWheelManager), iconBundlePath); val = GameObjectManager.CreateSuperQoLGameObject("RadialWheel", TargetObject.UI_MasterCanvas, new CreationSettings(true, TransformType.RectTransformUI, TransformLocals.Generic)); GameObject val3 = GameObjectManager.CreateSuperQoLGameObject("GearWheel", val, new CreationSettings(true, TransformType.RectTransformUI, TransformLocals.Generic)); GameObject arrowObj = GenerateWheelGameObjectWithSprite(val2, val, baseUnityPath + "Arrow_512.png", "RadialArrow", active: false); GameObject centerXObj = GenerateWheelGameObjectWithSprite(val2, val, baseUnityPath + "CenterX_512.png", "RadialCenterX", active: false); GameObject val4 = GenerateWheelGameObjectWithSprite(val2, val3, baseUnityPath + "BackgroundCircle.png", "WheelBackground", active: true); if (Object.op_Implicit((Object)(object)val4)) { ((Graphic)val4.GetComponent()).color = new Color(0.08f, 0.08f, 0.08f, 0.85f); val4.transform.localScale = new Vector3(8.26f, 8.26f, 8.26f); val4.transform.SetAsFirstSibling(); } GameObject pieceSampleObj = GenerateWheelGameObjectWithSprite(val2, val, baseUnityPath + "Square_512.png", "pieceSample", active: false); Dictionary indexMapping; List list = LoadSpawnableToolIcons(val2, out indexMapping); RadialMenu val5 = InitializeRadialComponent(val3, list, arrowObj, centerXObj, pieceSampleObj, out quickKeysData); val5.SetPieceImageSprites(list.ToArray()); return new RadialRefs(val3, val5, indexMapping); } catch { if (Object.op_Implicit((Object)(object)val)) { val.SetActive(false); } throw; } } private static RadialMenu InitializeRadialComponent(GameObject radialObj, List sprites, GameObject arrowObj, GameObject centerXObj, GameObject pieceSampleObj, out Dictionary quickKeysData) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) Font builtinResource = Resources.GetBuiltinResource("Arial.ttf"); TextSettings val = default(TextSettings); ((TextSettings)(ref val))..ctor(builtinResource, 20, (FontStyle)0, new Color(0.9f, 0.9f, 0.92f), new Color(0.125f, 0.125f, 0.14f), (AnchorPresets)7, new Vector2(0f, -15f), new Vector2(150f, 25f)); RadialMenu.InitializeProperties(sprites.Count, pieceSampleObj, Object.op_Implicit((Object)(object)arrowObj) ? arrowObj.GetComponent() : null, Object.op_Implicit((Object)(object)centerXObj) ? centerXObj.GetComponent() : null, ModConfig.Instance.EnableRadialQuickToolsKeys.Value, (KeyCode[])(object)new KeyCode[1] { (KeyCode)ModConfig.Instance.RadialQuickToolsModifierKey.Value }, val, ref quickKeysData, 325f, 0.1725f, (MainType)2, 0.6f, (AppearanceType)2, (EasingType)2, 0.1f, (AppearanceType)1, (EasingType)7); return radialObj.AddComponent(); } private static GameObject GenerateWheelGameObjectWithSprite(AssetBundleElement bundleElement, GameObject mainRadialObj, string iconName, string objectName, bool active) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Texture2D val = default(Texture2D); if (bundleElement.TryLoadObject(iconName, ref val)) { Sprite spriteFromTexture = AssetLoading.GetSpriteFromTexture(val, Vector2.zero); GameObject obj = GameObjectManager.CreateSuperQoLGameObject(objectName, mainRadialObj, new CreationSettings(active, TransformType.RectTransformUI, TransformLocals.Generic)); obj.AddComponent().sprite = spriteFromTexture; return obj; } return null; } private static List LoadSpawnableToolIcons(AssetBundleElement bundleElement, out Dictionary indexMapping) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) List list = new List(); indexMapping = new Dictionary(); int num = 0; if (!GetUserConfigToolDisplayList(out var toolDisplayList)) { toolDisplayList = ToolWheelDefinitions.GetAllSpawnableToolDefinitions().ToList(); } Texture2D val = default(Texture2D); foreach (ToolWheelDefinition item in toolDisplayList) { if (item.IsRadialSpawnable && bundleElement.TryLoadObject(item.IconUnityPath, ref val)) { Sprite spriteFromTexture = AssetLoading.GetSpriteFromTexture(val, Vector2.zero); list.Add(spriteFromTexture); indexMapping.Add(num++, (int)item.Index); } } return list; } private static bool GetUserConfigToolDisplayList(out List toolDisplayList) { toolDisplayList = null; string value = ModConfig.Instance.RadialDisplayControl.Value; if (!string.IsNullOrEmpty(value)) { string[] array = (from t in value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select GetComparableDisplayName(t)).ToArray(); Dictionary dictionary = ToolWheelDefinitions.GetAllSpawnableToolDefinitions().ToDictionary((ToolWheelDefinition t) => GetComparableDisplayName(t.DisplayName), (ToolWheelDefinition t) => t); toolDisplayList = new List(); string[] array2 = array; foreach (string text in array2) { if (dictionary.TryGetValue(text, out var value2)) { toolDisplayList.Add(value2); continue; } string key = ((ConfigEntryBase)ModConfig.Instance.RadialDisplayControl).Definition.Key; TimeLogger.Logger.LogWarning("The user defined value '" + text + "' in the setting '" + key + "' is not a valid tool name.", (LogCategories)2048); toolDisplayList.Clear(); return false; } return toolDisplayList.Count > 0; } return false; } private static string GetComparableDisplayName(string toolDisplayName) { return toolDisplayName.Replace(" ", "").ToLower(); } } public enum QuickToolKeyModifiers { [Description("None")] None = 0, [Description("Left Control")] LeftControl = 306, [Description("Right Control")] RightControl = 305, [Description("Left Shift")] LeftShift = 304, [Description("Right Shift")] RightShift = 303, [Description("Left Alt")] LeftAlt = 308, [Description("Right Alt")] RightAlt = 307 } public static class RadialWheelManager { private enum PendingToolAction { None, Drop, equip } private class ToolActionStatus { public PendingToolAction PendingAction { get; set; } public Func ChangeEquipmentFunc { get; set; } } private const string hotkeyGroupName = "radialHotkeys"; private const string hotkeyQuickGroupName = "RadialQuickKeys"; private static RadialRefs radialInstances; private static ToolActionStatus toolActionStatus; public static bool BlockCameraMovement { get; private set; } public static bool IsRadialShowing() { return radialInstances.RadialMenu.IsRadialShowing(); } public static void Initialize() { toolActionStatus = new ToolActionStatus(); BoolSyncVarSetting radialEnabledSync = RadialWheelNetwork.RadialEnabledSync; ((SyncVar)(object)radialEnabledSync).OnFinishSyncing = (Action)Delegate.Combine(((SyncVar)(object)radialEnabledSync).OnFinishSyncing, (Action)delegate { if (RadialWheelNetwork.RadialEnabledSync.IsEnabledLocally) { if (WorldState.IsGameWorldAtOrAfter(GameWorldEvent.CanvasAwake)) { InitializeRadialWheel(); } else { WorldState.SubscribeToWorldStateEvent(GameWorldEvent.CanvasAwake, InitializeRadialWheel); } ModConfig.Instance.EnableRadialQuickToolsKeys.SettingChanged += UpdateQuickTools; ModConfig.Instance.RadialQuickToolsModifierKey.SettingChanged += UpdateQuickTools; } }); InputManagerSMT.Instance.AddHotkeyFromConfig(ModConfig.Instance.RadialEquipmentWheelHotkey, (InputState)0, HotkeyActiveContext.WorldLoadedNotPaused, RadialOpen); InputManagerSMT.Instance.AddHotkeyFromConfig(ModConfig.Instance.RadialEquipmentWheelHotkey, (InputState)1, HotkeyActiveContext.WorldLoadedNotPaused, RadialCloseNormal); } private static void InitializeRadialWheel() { WorldState.UnsubscribeFromWorldStateEvent(GameWorldEvent.CanvasAwake, InitializeRadialWheel); radialInstances = RadialWheelInitialization.LoadEquipmentWheel(out var quickKeysData); SetWheelQuickKeys(quickKeysData); InputManagerSMT.Instance.TryAddHotkey("RadialSelect", (KeyCode)323, (InputState)0, HotkeyActiveContext.RadialWheelOpen, RadialCloseIfSelection, "radialHotkeys"); InputManagerSMT.Instance.TryAddHotkey("RadialCancelEsc", (KeyCode)27, (InputState)0, HotkeyActiveContext.RadialWheelOpen, RadialCancelEsc, "radialHotkeys"); InputManagerSMT.Instance.TryAddHotkey("RadialCancelMouse", (KeyCode)324, (InputState)0, HotkeyActiveContext.RadialWheelOpen, RadialCancel, "radialHotkeys"); radialInstances.RadialMenu.OnDestroyEvent += OnDestroy; } private static void SetWheelQuickKeys(Dictionary quickKeysData) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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) if (quickKeysData != null) { ((InputDetection)InputManagerSMT.Instance).RemoveHotkeyGroup("RadialQuickKeys"); { foreach (KeyValuePair quickKey in quickKeysData) { InputManagerSMT instance = InputManagerSMT.Instance; string hotkeyName = $"RadialItemKey{quickKey.Key + 1}"; WheelKeyBind value = quickKey.Value; KeyCode keyCode = ((WheelKeyBind)(ref value)).KeyCode; value = quickKey.Value; instance.TryAddHotkey(hotkeyName, keyCode, ((WheelKeyBind)(ref value)).Modifiers, (InputState)0, HotkeyActiveContext.WheelHotkeysEnabled, delegate { HotkeyItemSelection(quickKey.Key); }, "RadialQuickKeys"); } return; } } ((InputDetection)InputManagerSMT.Instance).RemoveHotkeyGroup("RadialQuickKeys"); } private static void HotkeyItemSelection(int indexSelection) { TaskExtensionMethods.FireAndForget(ToolSelected(indexSelection), (LogCategories)2048); } public static void OnDestroy() { ((InputDetection)InputManagerSMT.Instance).RemoveHotkeyGroup("radialHotkeys"); ((InputDetection)InputManagerSMT.Instance).RemoveHotkeyGroup("RadialQuickKeys"); ModConfig.Instance.EnableRadialQuickToolsKeys.SettingChanged -= UpdateQuickTools; ModConfig.Instance.RadialQuickToolsModifierKey.SettingChanged -= UpdateQuickTools; radialInstances = null; } private static void UpdateQuickTools(object sender, EventArgs e) { Dictionary dictionary = default(Dictionary); RadialMenu.UpdateQuickTools(ModConfig.Instance.EnableRadialQuickToolsKeys.Value, (KeyCode[])(object)new KeyCode[1] { (KeyCode)ModConfig.Instance.RadialQuickToolsModifierKey.Value }, ref dictionary); if (dictionary != null) { SetWheelQuickKeys(dictionary); } } public static void RadialOpen() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 if (!WorldState.IsWorldLoaded || !RadialWheelNetwork.RadialEnabledSync.IsEnabledLocally || !FirstPersonController.Instance.allowPlayerInput) { return; } if (WorldState.IsClient) { if ((int)RadialWheelNetwork.RadialEnabledSync.Status == 1) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "Equipment Wheel is disabled. Host does not have SuperQoLity or this feature enabled", true); return; } if (radialInstances == null) { TimeLogger.Logger.SendMessageNotification((LogTier)8, "Equipment Wheel is disabled. Host needs this feature enabled while you join", true); return; } } if (radialInstances.RadialMenu.Show()) { ChangeWheelControlStatus(isOpenWheelAction: true, skipCursorChanges: false); } } public static void RadialCloseNormal() { RadialClose(withSelection: true, skipCursorChanges: false); } public static void RadialCloseIfSelection() { if (radialInstances.RadialMenu.IsPieceSelected()) { RadialClose(withSelection: true, skipCursorChanges: false); } } private static void RadialCancel() { RadialClose(withSelection: false, skipCursorChanges: false); } private static void RadialCancelEsc() { RadialClose(withSelection: false, skipCursorChanges: true); } private static async void RadialClose(bool withSelection, bool skipCursorChanges) { CustomCameraController customCameraController = SMTInstances.GetCustomCameraController(); if (!WorldState.IsWorldLoaded || radialInstances == null || !((Behaviour)radialInstances.RadialMenu).isActiveAndEnabled) { return; } if (Object.op_Implicit((Object)(object)customCameraController) && (customCameraController.inVehicle || customCameraController.isInCameraEvent)) { radialInstances.RadialMenu.Hide(); return; } try { int num = radialInstances.RadialMenu.Hide(); if (withSelection && num >= 0) { await ToolSelected(num); } } catch (Exception ex) { if (Object.op_Implicit((Object)(object)radialInstances.RadialObj)) { radialInstances.RadialObj.SetActive(false); } TimeLogger.Logger.LogExceptionWithMessage("Radial wheel close error:", ex, (LogCategories)2048); } finally { ChangeWheelControlStatus(isOpenWheelAction: false, skipCursorChanges); } } private static void ChangeWheelControlStatus(bool isOpenWheelAction, bool skipCursorChanges) { if (!skipCursorChanges) { Cursor.lockState = (CursorLockMode)((!isOpenWheelAction) ? 1 : 2); Cursor.visible = isOpenWheelAction; } BlockCameraMovement = isOpenWheelAction; } private static async Task ToolSelected(int selectedIndex) { if (toolActionStatus.PendingAction != 0) { TimeLogger.Logger.SendMessageNotification((LogTier)4, "Tool equip process still pending.", true); return; } PlayerNetwork pNetwork = SMTInstances.LocalPlayerNetwork(); int requestedToolIndex = radialInstances.IndexMapping[selectedIndex]; int equippedItem = pNetwork.equippedItem; if (requestedToolIndex == equippedItem || !EquipmentManager.ExistsUnusedToolOfIndex(pNetwork, requestedToolIndex, out var toolRequestMethod)) { return; } bool flag = true; bool flag2 = false; if (equippedItem > 0) { if (EquipmentManager.CanDropItemInFront(pNetwork, out var dropPosition, out var equippedTool)) { if (EquipmentManager.DropCurrentEquippedItem(pNetwork, dropPosition, equippedTool)) { flag2 = true; } else { flag = false; } } else { flag = false; } } if (!flag) { return; } if (flag2) { toolActionStatus.PendingAction = PendingToolAction.Drop; toolActionStatus.ChangeEquipmentFunc = async delegate { await UniTask.DelayFrame(1, (PlayerLoopTiming)8, default(CancellationToken), false); await RequestAndChangeEquipment(pNetwork, requestedToolIndex, toolRequestMethod); }; } else { await RequestAndChangeEquipment(pNetwork, requestedToolIndex, toolRequestMethod); } } private static async Task RequestAndChangeEquipment(PlayerNetwork pNetwork, int requestedToolIndex, Func toolRequestMethod) { if (toolRequestMethod()) { await UniTask.DelayFrame(1, (PlayerLoopTiming)8, default(CancellationToken), false); toolActionStatus.PendingAction = PendingToolAction.equip; pNetwork.CmdChangeEquippedItem(requestedToolIndex); } else { toolActionStatus.PendingAction = PendingToolAction.None; } } public static async void OnChangedEquipment(PlayerNetwork __instance, Transform previousEquipped, Transform newEquipped, int previousIndex, int newIndex, bool isLocalPlayer) { if (toolActionStatus.PendingAction == PendingToolAction.Drop && isLocalPlayer) { await toolActionStatus.ChangeEquipmentFunc(); } else if (toolActionStatus.PendingAction == PendingToolAction.equip) { toolActionStatus.PendingAction = PendingToolAction.None; } } } public static class ToolWheelDefinitions { private static readonly string baseAssetsPath = "assets\\RadialWheel\\Equipment\\"; private static readonly Lazy> toolIndexes = new Lazy>(GenerateToolIndexDictionary); public static ToolWheelDefinition Nothing { get; } = new ToolWheelDefinition(ToolIndexes.Nothing, isRadialSpawnable: false, PlayerPermissionsEnum.None, null, null, null); public static ToolWheelDefinition Box { get; } = new ToolWheelDefinition(ToolIndexes.Box, isRadialSpawnable: false, PlayerPermissionsEnum.Restocker, null, null, delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) ((Component)GameData.Instance).GetComponent().CmdSpawnBoxFromPlayer(dropPos, pNet.extraParameter1, pNet.extraParameter2, ((Component)pNet).transform.eulerAngles.y); }); public static ToolWheelDefinition PricingScanner { get; } = new ToolWheelDefinition(ToolIndexes.PricingScanner, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("2_PricingScanner", "Organizer_PriceScanner"), baseAssetsPath + "UI_OrganizerPriceScanner.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 90f); }); public static ToolWheelDefinition Broom { get; } = new ToolWheelDefinition(ToolIndexes.Broom, isRadialSpawnable: true, PlayerPermissionsEnum.Security, new ToolGameObjects("3_Broom", "Organizer_Brooms"), baseAssetsPath + "UI_OrganizerBroom.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 270f, 0f); }); [Obsolete("Replaced with PaintablesTablet")] public static ToolWheelDefinition DecoTablet { get; } = new ToolWheelDefinition(ToolIndexes.DecoTablet, isRadialSpawnable: false, PlayerPermissionsEnum.Manager, null, null, null); public static ToolWheelDefinition PaintablesTablet { get; } = new ToolWheelDefinition(ToolIndexes.PaintablesTablet, AuxUtils.IsDLCSubscribed(), PlayerPermissionsEnum.Manager, new ToolGameObjects("5_PaintablesTablet", null), baseAssetsPath + "UI_PaintPalette.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 270f, 0f); }); public static ToolWheelDefinition OrderingDevice { get; } = new ToolWheelDefinition(ToolIndexes.OrderingDevice, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("6_OrderingDevice", "Organizer_OrderingTablet"), baseAssetsPath + "UI_OrganizerOrderTablet.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 180f, 0f); }); public static ToolWheelDefinition SledgeHammer { get; } = new ToolWheelDefinition(ToolIndexes.SledgeHammer, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("7_Sledgehammer", "Organizer_Sledgehammer"), baseAssetsPath + "UI_OrganizerSledge.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 0f); }); public static ToolWheelDefinition Ladder { get; } = new ToolWheelDefinition(ToolIndexes.Ladder, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("8_Ladder", null), baseAssetsPath + "UI_Ladder.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 15f, 0f); }); public static ToolWheelDefinition BlueTray { get; } = new ToolWheelDefinition(ToolIndexes.BlueTray, isRadialSpawnable: true, PlayerPermissionsEnum.None, new ToolGameObjects("9_OrderingTray", "Organizer_Trays"), baseAssetsPath + "UI_Tray.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) net.CmdSpawnTrayFromPlayer(dropPos, pNet.trayData, ((Component)pNet).transform.eulerAngles.y); }); public static ToolWheelDefinition SalesDevice { get; } = new ToolWheelDefinition(ToolIndexes.SalesDevice, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("10_SalesDevice", "Organizer_SalesTablet"), baseAssetsPath + "UI_OrganizerSales.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 180f, 0f); }); public static ToolWheelDefinition CardboardBale { get; } = new ToolWheelDefinition(ToolIndexes.CardboardBale, isRadialSpawnable: false, PlayerPermissionsEnum.None, null, null, delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 0f); }); public static ToolWheelDefinition OrderBox { get; } = new ToolWheelDefinition(ToolIndexes.OrderBox, isRadialSpawnable: false, PlayerPermissionsEnum.None, null, null, delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) net.CmdSpawnOrderBoxFromPlayer(dropPos, ((Component)pNet).transform.eulerAngles.y, pNet.orderNumberData, pNet.orderCustomerNameData, pNet.orderItemsInBoxData); }); public static ToolWheelDefinition NetCatcher { get; } = new ToolWheelDefinition(ToolIndexes.NetCatcher, isRadialSpawnable: false, PlayerPermissionsEnum.None, null, null, delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 0f); }); public static ToolWheelDefinition Toolbox { get; } = new ToolWheelDefinition(ToolIndexes.Toolbox, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("14_Toolbox", "Organizer_Toolbox"), baseAssetsPath + "UI_Toolbox.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 0f); }); public static ToolWheelDefinition Extinguisher { get; } = new ToolWheelDefinition(ToolIndexes.Extinguisher, isRadialSpawnable: true, PlayerPermissionsEnum.Manager, new ToolGameObjects("15_Extinguisher", "FireExtinguisher"), baseAssetsPath + "UI_Extinguisher.png", delegate(NetworkSpawner net, PlayerNetwork pNet, Vector3 dropPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) GenericSpawnMethod(net, pNet, dropPos, 0f, 0f); }); private static Dictionary GenerateToolIndexDictionary() { Dictionary dictionary = new Dictionary(); BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; PropertyInfo[] properties = typeof(ToolWheelDefinitions).GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.PropertyType != typeof(ToolWheelDefinition))) { ToolWheelDefinition toolWheelDefinition = (ToolWheelDefinition)propertyInfo.GetValue(null); dictionary.Add(toolWheelDefinition.Index, toolWheelDefinition); } } return dictionary; } public static ToolWheelDefinition FromIndex(int index) { return toolIndexes.Value[(ToolIndexes)index]; } public static List GetAllToolDefinitions() { return toolIndexes.Value.Values.ToList(); } public static IEnumerable GetAllSpawnableToolDefinitions() { return toolIndexes.Value.Values.Where((ToolWheelDefinition t) => t.IsRadialSpawnable); } public static string GetDefaultDisplayControlString() { return string.Join(",", (from t in GetAllSpawnableToolDefinitions() select t.DisplayName.Replace(" ", "")).ToArray()); } private static void GenericSpawnMethod(NetworkSpawner netSpawner, PlayerNetwork pNetwork, Vector3 dropPosition, float xRotation, float zRotation) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) netSpawner.CmdSpawnProp(pNetwork.equippedItem, dropPosition, new Vector3(xRotation, ((Component)pNetwork).transform.eulerAngles.y, zRotation)); } private static void GenericSpawnZeroPosMethod(NetworkSpawner netSpawner, PlayerNetwork pNetwork) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) netSpawner.CmdSpawnProp(pNetwork.equippedItem, Vector3.zero, Vector3.zero); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.RadialWheel.Model { public delegate void CmdSpawnMethodDelegate(NetworkSpawner netSpawner, PlayerNetwork pNetwork, Vector3 dropPosition); public class ToolWheelDefinition : ToolDefinition { public bool IsRadialSpawnable { get; } public PlayerPermissionsEnum RequiredPermission { get; } public ToolGameObjects ToolGameObjects { get; } public string IconUnityPath { get; } public CmdSpawnMethodDelegate CmdSpawnMethod { get; } public ToolWheelDefinition(ToolIndexes index, bool isRadialSpawnable, PlayerPermissionsEnum requiredPermission, ToolGameObjects toolGameObjects, string iconUnityPath, CmdSpawnMethodDelegate cmdSpawnMethod, string displayName = null) { IsRadialSpawnable = isRadialSpawnable; RequiredPermission = requiredPermission; ToolGameObjects = toolGameObjects; IconUnityPath = iconUnityPath; CmdSpawnMethod = cmdSpawnMethod; base..ctor(index, displayName); } } public record ToolGameObjects(string UsablePropName, string OrganizerName); } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Equipment.Model { public class ToolDefinition { public ToolIndexes Index { get; } public string DisplayName { get; } public ToolDefinition(ToolIndexes index, string displayName = null) { Index = index; DisplayName = displayName ?? EnumExtension.GetDescription((Enum)index); base..ctor(); } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities { public enum ParentContainerType { ProductDisplay = 1, Storage = 4, GroundBox = 0x10 } public enum ContainerType { ProdShelf = 1, ProdShelfSlot = 2, Storage = 4, StorageSlot = 8, GroundBox = 0x10 } [Flags] public enum ContainerTypeFlags { None = 0, Storage = 4, StorageSlot = 8, ProdShelf = 1, ProdShelfSlot = 2, GroundBox = 0x10 } public static class DataContainerType { public enum TypeIndex { ProductShelf, StorageShelf, Checkout, SelfCheckout, Unknown } public static TypeIndex GetContainerType(int containerID, out int parentIndex) { parentIndex = -1; if ((Object)(object)GameData.Instance == (Object)null) { TimeLogger.Logger.LogError("The GameData.Instance is null.", (LogCategories)int.MinValue); return TypeIndex.Unknown; } NetworkSpawner val = default(NetworkSpawner); if (!((Component)GameData.Instance).TryGetComponent(ref val)) { TimeLogger.Logger.LogError("There is no NetworkSpawner Component in GameData.", (LogCategories)int.MinValue); return TypeIndex.Unknown; } if (val.buildables.Length < containerID) { TimeLogger.Logger.LogError($"The containerId {containerID} is out of bounds for " + $"the length ({val.buildables.Length}) of networkSpawner.buildables.", (LogCategories)int.MinValue); return TypeIndex.Unknown; } Data_Container val2 = default(Data_Container); if (val.buildables[containerID].TryGetComponent(ref val2)) { parentIndex = val2.parentIndex; return val2.GetContainerType(); } TimeLogger.Logger.LogError("There is no Data_Container Component in " + $"the buildable for containerId {containerID}.", (LogCategories)int.MinValue); return TypeIndex.Unknown; } public static TypeIndex GetContainerType(this Data_Container dataContainer) { if (dataContainer.parentIndex >= 0 && dataContainer.parentIndex < 4) { return (TypeIndex)dataContainer.parentIndex; } TimeLogger.Logger.LogWarning("Returned unknown parentIndex type with " + $"value {dataContainer.parentIndex} for Data_Container.", (LogCategories)int.MinValue); return TypeIndex.Unknown; } public static ParentContainerType ToParentContainerType(this TypeIndex typeIndex) { return typeIndex switch { TypeIndex.ProductShelf => ParentContainerType.ProductDisplay, TypeIndex.StorageShelf => ParentContainerType.Storage, _ => throw new NotImplementedException($"No ParentContainerType for typeIndex {typeIndex}"), }; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.ShelfSlotInfo { public enum ShelfType { StorageSlot, ProdShelfSlot } public abstract class GenericShelfSlotInfo { public class ExtraDataClass { public int ProductId { get; set; } public int Quantity { get; set; } public Vector3 Position { get; set; } } private ExtraDataClass _extraData; public int ShelfIndex { get; init; } public int SlotIndex { get; init; } public ShelfType ShelfType { get; init; } public bool ShelfFound { get { if (ShelfIndex >= 0) { return SlotIndex >= 0; } return false; } } public ExtraDataClass ExtraData { get { if (_extraData == null) { _extraData = new ExtraDataClass(); } return _extraData; } set { _extraData = value; } } public GenericShelfSlotInfo(int shelfIndex, int slotIndex, int productId, int quantity, Vector3 position, ShelfType shelfType) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) ShelfIndex = shelfIndex; SlotIndex = slotIndex; ShelfType = shelfType; ExtraData.ProductId = productId; ExtraData.Quantity = quantity; ExtraData.Position = position; } public GenericShelfSlotInfo(int shelfIndex, int slotIndex, ShelfType shelfType) { ShelfIndex = shelfIndex; SlotIndex = slotIndex; ShelfType = shelfType; } public void SetExtraDataValues(int shelfIndex, int slotIndex, int productId, int Quantity, Vector3 Position) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) ExtraData.ProductId = productId; ExtraData.Quantity = Quantity; ExtraData.Position = Position; } public void SetExtraDataValues(GenericShelfSlotInfo SlotInfoBase) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) ExtraData.ProductId = SlotInfoBase.ExtraData.ProductId; ExtraData.Quantity = SlotInfoBase.ExtraData.Quantity; ExtraData.Position = SlotInfoBase.ExtraData.Position; } public override string ToString() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) return $"Shelf {ShelfIndex}, Slot {SlotIndex} (ProdID: {ExtraData.ProductId}, Amount: {ExtraData.Quantity}, Position: {ExtraData.Position})"; } } public class TargetContainerSlotComparer : IEqualityComparer { public bool Equals(GenericShelfSlotInfo o1, GenericShelfSlotInfo o2) { if (o1.ShelfIndex == o2.ShelfIndex) { return o1.SlotIndex == o2.SlotIndex; } return false; } public int GetHashCode(GenericShelfSlotInfo o) { if (o == null) { throw new ArgumentNullException("The GenericShelfSlotInfo object cant be null."); } return (83 * 3323 + o.ShelfIndex.GetHashCode()) * 3323 + o.SlotIndex.GetHashCode(); } } public class ProductShelfSlotInfo : GenericShelfSlotInfo { public static ProductShelfSlotInfo Default => new ProductShelfSlotInfo(-1, -1, -1, -1, Vector3.zero); public ProductShelfSlotInfo(int shelfIndex, int slotIndex, int productId, int quantity, Vector3 position) : base(shelfIndex, slotIndex, productId, quantity, position, ShelfType.ProdShelfSlot) { }//IL_0006: Unknown result type (might be due to invalid IL or missing references) public ProductShelfSlotInfo(int shelfIndex, int slotIndex) : base(shelfIndex, slotIndex, ShelfType.ProdShelfSlot) { } } public class StorageSlotInfo : GenericShelfSlotInfo { public static StorageSlotInfo Default => new StorageSlotInfo(-1, -1, -1, -1, Vector3.zero); public StorageSlotInfo(int shelfIndex, int slotIndex, int productId, int quantity, Vector3 position) : base(shelfIndex, slotIndex, productId, quantity, position, ShelfType.StorageSlot) { }//IL_0006: Unknown result type (might be due to invalid IL or missing references) public StorageSlotInfo(int shelfIndex, int slotIndex) : base(shelfIndex, slotIndex, ShelfType.StorageSlot) { } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.ContainerEntities.Search { public enum EnumFreeStoragePriority { [Description("1.Assigned labeled > 2.Labeled > 3.Unlabeled")] Labeled, [Description("1.Assigned labeled > 2.Unlabeled > 3.Labeled")] Unlabeled, [Description("1.Assigned labeled > 2.Labeled")] OnlyLabeled, [Description("1.Unlabeled")] OnlyUnlabeled } public class ContainerSearch { public static bool CheckIfProdShelfWithSameProduct(NPC_Manager __instance, int productIDToCheck, NPC_Info npcInfoComponent, out (ProductShelfSlotInfo productShelfSlotInfo, int maxProductsPerRow) result) { result.productShelfSlotInfo = null; result.maxProductsPerRow = -1; List<(ProductShelfSlotInfo shelfSlotInfo, int maxProductsPerRow)> productsPriority = new List<(ProductShelfSlotInfo, int)>(); float[] productsThreshholdArray = __instance.productsThreshholdArray; foreach (float currentLoopProdThreshold in productsThreshholdArray) { ContainerSearchLambdas.ForEachProductShelfSlotLambda(__instance, checkNPCProdShelfTarget: true, delegate(int prodShelfIndex, int slotIndex, int productId, int quantity, Transform prodShelfObjT) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) if (productId == productIDToCheck) { Data_Container component = ((Component)__instance.shelvesOBJ.transform.GetChild(prodShelfIndex)).GetComponent(); int maxProductsPerRowCached = PerformanceCachingPatch.GetMaxProductsPerRowCached(__instance, component, productIDToCheck, prodShelfIndex); int num = Mathf.FloorToInt((float)maxProductsPerRowCached * currentLoopProdThreshold); if (quantity == 0 || quantity < num) { productsPriority.Add((new ProductShelfSlotInfo(prodShelfIndex, slotIndex, productId, quantity, prodShelfObjT.position), maxProductsPerRowCached)); } } return ContainerSearchLambdas.LoopAction.Nothing; }); if (productsPriority.Count > 0) { result = productsPriority.OrderBy(((ProductShelfSlotInfo shelfSlotInfo, int maxProductsPerRow) p) => p.shelfSlotInfo.ExtraData.Quantity).First(); return true; } } return false; } public static StorageSlotInfo GetStorageContainerWithBoxToMerge(NPC_Manager __instance, int boxIDProduct) { int maxItemsPerBox = ProductListing.Instance.productsData[boxIDProduct].maxItemsPerBox; return ContainerSearchLambdas.FindStorageSlotLambda(__instance, checkNPCStorageTarget: true, (int storageId, int slotId, int productId, int quantity, Transform storageObjT) => (productId == boxIDProduct && quantity > 0 && quantity < maxItemsPerBox && IsStorageAllowedForMerge(__instance, storageObjT)) ? ContainerSearchLambdas.LoopStorageAction.SaveAndExit : ContainerSearchLambdas.LoopStorageAction.Nothing); } public static StorageSlotInfo FreeUnassignedStorageContainer(NPC_Manager __instance, Transform employeeT) { return GetFreeStorageContainer(__instance, employeeT, -1); } public static bool MoreThanOneBoxToMergeCheck(NPC_Manager __instance, int boxIDProduct) { int maxItemsPerBox = ProductListing.Instance.productsData[boxIDProduct].maxItemsPerBox; int boxCount = 0; ContainerSearchLambdas.ForEachStorageSlotLambda(__instance, checkNPCStorageTarget: true, skipEmptyBoxes: false, delegate(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT) { if (productId == boxIDProduct && quantity < maxItemsPerBox && IsStorageAllowedForMerge(__instance, storageObjT)) { boxCount++; if (boxCount > 1) { return ContainerSearchLambdas.LoopAction.Exit; } } return ContainerSearchLambdas.LoopAction.Nothing; }); return boxCount > 1; } public static StorageSlotInfo GetFreeStorageContainer(NPC_Manager __instance, Transform employeeT, int boxIDProduct) { StorageSlotInfo result = StorageSlotInfo.Default; List assignedPriorityStorage = new List(); List highPriorityStorage = new List(); List lowPriorityStorage = new List(); bool allowsAssignedStorage = IsAssignedStorageAllowed(); bool allowsLowPriorityStorage = IsAllStorageTypesAllowed(); ContainerSearchLambdas.ForEachStorageSlotLambda(__instance, checkNPCStorageTarget: true, skipEmptyBoxes: false, delegate(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (allowsAssignedStorage && boxIDProduct >= 0 && productId == boxIDProduct && quantity < 0) { assignedPriorityStorage.Add(new StorageSlotInfo(storageIndex, slotIndex, productId, quantity, storageObjT.position)); } else if (productId == -1 && assignedPriorityStorage.Count == 0) { StorageSlotInfo item = new StorageSlotInfo(storageIndex, slotIndex, productId, quantity, storageObjT.position); if (IsStorageTypePrioritized(__instance, storageObjT)) { highPriorityStorage.Add(item); } else if (allowsLowPriorityStorage && highPriorityStorage.Count == 0) { lowPriorityStorage.Add(item); } } return ContainerSearchLambdas.LoopAction.Nothing; }); List list = assignedPriorityStorage; if (list != null && list.Count > 0) { result = GetClosestStorageFromList(assignedPriorityStorage, employeeT); } else { List list2 = highPriorityStorage; if (list2 != null && list2.Count > 0) { result = GetClosestStorageFromList(highPriorityStorage, employeeT); } else { List list3 = lowPriorityStorage; if (list3 != null && list3.Count > 0) { result = GetClosestStorageFromList(lowPriorityStorage, employeeT); } } } return result; } public static GenericShelfSlotInfo GetFirstOfAnyShelfWithProduct(NPC_Manager __instance, int boxIDProduct) { GenericShelfSlotInfo shelfSlotInfo = ContainerSearchLambdas.FindStorageSlotLambda(__instance, checkNPCStorageTarget: true, (int storageId, int slotId, int productId, int quantity, Transform storageObjT) => (productId == boxIDProduct && quantity > 0) ? ContainerSearchLambdas.LoopStorageAction.SaveAndExit : ContainerSearchLambdas.LoopStorageAction.Nothing); if (shelfSlotInfo.ShelfFound) { return shelfSlotInfo; } ContainerSearchLambdas.ForEachProductShelfSlotLambda(__instance, checkNPCProdShelfTarget: true, delegate(int prodShelfIndex, int slotIndex, int productId, int quantity, Transform prodShelfObjT) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (productId == boxIDProduct && quantity > 0) { shelfSlotInfo = new ProductShelfSlotInfo(prodShelfIndex, slotIndex, productId, quantity, prodShelfObjT.position); return ContainerSearchLambdas.LoopAction.Exit; } return ContainerSearchLambdas.LoopAction.Nothing; }); return shelfSlotInfo; } private static StorageSlotInfo GetClosestStorageFromList(List listStorage, Transform employee) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (listStorage == null || listStorage.Count <= 0) { return null; } StorageSlotInfo result = null; float num = float.MaxValue; foreach (StorageSlotInfo item in listStorage) { Vector3 val = item.ExtraData.Position - employee.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = item; } } return result; } private static bool IsStorageTypePrioritized(NPC_Manager __instance, Transform storageObjT) { EnumFreeStoragePriority value = ModConfig.Instance.FreeStoragePriority.Value; bool flag = IsLabeledStorage(__instance, storageObjT); if (!flag || (value != 0 && value != EnumFreeStoragePriority.OnlyLabeled)) { if (!flag) { if (value != EnumFreeStoragePriority.Unlabeled) { return value == EnumFreeStoragePriority.OnlyUnlabeled; } return true; } return false; } return true; } private static bool IsStorageAllowedForMerge(NPC_Manager __instance, Transform storageObjT) { EnumFreeStoragePriority value = ModConfig.Instance.FreeStoragePriority.Value; if (IsAllStorageTypesAllowed()) { return true; } bool flag = IsLabeledStorage(__instance, storageObjT); if (!flag || value != EnumFreeStoragePriority.OnlyLabeled) { if (!flag) { return value == EnumFreeStoragePriority.OnlyUnlabeled; } return false; } return true; } public static bool IsAssignedStorageAllowed() { return ModConfig.Instance.FreeStoragePriority.Value != EnumFreeStoragePriority.OnlyUnlabeled; } private static bool IsAllStorageTypesAllowed() { if (ModConfig.Instance.FreeStoragePriority.Value != EnumFreeStoragePriority.OnlyLabeled) { return ModConfig.Instance.FreeStoragePriority.Value != EnumFreeStoragePriority.OnlyUnlabeled; } return false; } private static bool IsLabeledStorage(NPC_Manager __instance, Transform storageObjT) { return Object.op_Implicit((Object)(object)storageObjT.Find("CanvasSigns")); } } [Flags] public enum ShelfSearchOptions { None = 0, CheckNPCShelfTarget = 1, SkipEmptySlots = 2 } public class ContainerSearchLambdas { public enum LoopStorageAction { Nothing, SaveLowPrio, SaveHighPrio, SaveAndExit } public enum LoopAction { Nothing, Nothing2, Nothing3, Exit } public delegate LoopStorageAction StorageSlotFunction(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT); public delegate LoopAction StorageLoopFunction(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT); public delegate LoopAction ProdShelfLoopFunction(int prodShelfIndex, int slotIndex, int productId, int quantity, Transform prodShelfObjT); public delegate LoopAction ShelfLoopFunction(int shelfIndex, int[] productInfoArray, Data_Container dataContainer, Vector3 position); public delegate LoopAction SlotLoopFunction(int slotIndex, int productId, int quantity); [CompilerGenerated] private sealed class d__11 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private ShelfSlotData <>2__current; private int <>l__initialThreadId; private ShelfData shelfData; public ShelfData <>3__shelfData; private ShelfSearchOptions searchOptions; public ShelfSearchOptions <>3__searchOptions; private ShelfType shelfType; public ShelfType <>3__shelfType; private int[] 5__2; private int 5__3; private int 5__4; ShelfSlotData IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__11(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_00c8; } <>1__state = -1; 5__2 = shelfData.ProductInfoArray; 5__3 = 5__2.Length / 2; 5__4 = 0; goto IL_00d8; IL_00c8: 5__4++; goto IL_00d8; IL_00d8: if (5__4 < 5__3) { int num2 = 5__2[5__4 * 2 + 1]; if (((searchOptions & ShelfSearchOptions.SkipEmptySlots) == 0 || num2 > 0) && ((searchOptions & ShelfSearchOptions.CheckNPCShelfTarget) == 0 || !EmployeeTargetReservation.IsShelfSlotTargeted(shelfType, shelfData.ShelfIndex, 5__4))) { int productId = 5__2[5__4 * 2]; <>2__current = new ShelfSlotData(shelfData, 5__4, productId, num2); <>1__state = 1; return true; } goto IL_00c8; } 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(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__11 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__11(0); } d__.shelfData = <>3__shelfData; d__.shelfType = <>3__shelfType; d__.searchOptions = <>3__searchOptions; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static void ForEachStorageSlotLambda(NPC_Manager __instance, bool checkNPCStorageTarget, bool skipEmptyBoxes, StorageLoopFunction storageSlotLambda) { for (int i = 0; i < __instance.storageOBJ.transform.childCount; i++) { Transform child = __instance.storageOBJ.transform.GetChild(i); int[] productInfoArray = ((Component)child).GetComponent().productInfoArray; int num = productInfoArray.Length / 2; for (int j = 0; j < num; j++) { int num2 = -1; if ((!skipEmptyBoxes || (num2 = productInfoArray[j * 2 + 1]) > 0) && (!checkNPCStorageTarget || !EmployeeTargetReservation.IsStorageSlotTargeted(i, j))) { int productId = productInfoArray[j * 2]; if (num2 == -1) { num2 = productInfoArray[j * 2 + 1]; } if (storageSlotLambda(i, j, productId, num2, child) == LoopAction.Exit) { return; } } } } } public static StorageSlotInfo FindStorageSlotLambda(NPC_Manager __instance, bool checkNPCStorageTarget, StorageSlotFunction storageSlotLambda) { StorageSlotInfo freeStorageSlot = StorageSlotInfo.Default; if (__instance.storageOBJ.transform.childCount == 0) { return freeStorageSlot; } ForEachStorageSlotLambda(__instance, checkNPCStorageTarget, skipEmptyBoxes: false, delegate(int storageId, int slotId, int productId, int quantity, Transform storageObjT) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) LoopStorageAction loopStorageAction = storageSlotLambda(storageId, slotId, productId, quantity, storageObjT); switch (loopStorageAction) { case LoopStorageAction.SaveHighPrio: case LoopStorageAction.SaveAndExit: freeStorageSlot = new StorageSlotInfo(storageId, slotId, productId, quantity, storageObjT.position); break; case LoopStorageAction.SaveLowPrio: if (!freeStorageSlot.ShelfFound) { freeStorageSlot = new StorageSlotInfo(storageId, slotId, productId, quantity, storageObjT.position); } break; } return (LoopAction)loopStorageAction; }); return freeStorageSlot; } public static void ForEachProductShelfSlotLambda(NPC_Manager __instance, bool checkNPCProdShelfTarget, ProdShelfLoopFunction prodShelfSlotLambda) { for (int i = 0; i < __instance.shelvesOBJ.transform.childCount; i++) { Transform child = __instance.shelvesOBJ.transform.GetChild(i); int[] productInfoArray = ((Component)child).GetComponent().productInfoArray; int num = productInfoArray.Length / 2; for (int j = 0; j < num; j++) { if (!checkNPCProdShelfTarget || !EmployeeTargetReservation.IsProductShelfSlotTargeted(i, j)) { int productId = productInfoArray[j * 2]; int quantity = productInfoArray[j * 2 + 1]; if (prodShelfSlotLambda(i, j, productId, quantity, child) == LoopAction.Exit) { return; } } } } } public static void ForEachShelfLambda(NPC_Manager __instance, ShelfType shelfType, ShelfLoopFunction productShelfLambda) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) Transform val = ((shelfType == ShelfType.ProdShelfSlot) ? __instance.shelvesOBJ.transform : __instance.storageOBJ.transform); int childCount = val.childCount; for (int i = 0; i < childCount; i++) { Transform child = val.GetChild(i); Data_Container component = ((Component)child).GetComponent(); int[] productInfoArray = component.productInfoArray; if (productShelfLambda(i, productInfoArray, component, child.position) == LoopAction.Exit) { break; } } } [IteratorStateMachine(typeof(d__11))] public static IEnumerable GetShelfSlotsFromShelfData(ShelfData shelfData, ShelfType shelfType, ShelfSearchOptions searchOptions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__11(-2) { <>3__shelfData = shelfData, <>3__shelfType = shelfType, <>3__searchOptions = searchOptions }; } } public class GroundBoxSearch { private class GroundBoxStorageList { private enum RelationshipMode { SingleStorage, StoragePerBox } private RelationshipMode relMode; private List groundBoxStorage; private List groundBoxList; private StorageSlotInfo unassignedStorageSlot; public GroundBoxStorageList() { groundBoxStorage = new List(); relMode = RelationshipMode.StoragePerBox; } public GroundBoxStorageList(List groundBoxList, StorageSlotInfo unassignedStorageSlot) { this.groundBoxList = groundBoxList; this.unassignedStorageSlot = unassignedStorageSlot; relMode = RelationshipMode.SingleStorage; } public void Add(GameObject groundBox) { if (relMode == RelationshipMode.SingleStorage) { throw new InvalidOperationException("You must initialize GroundBoxStorageList using the empty constructor to use this method."); } groundBoxStorage.Add(new GroundBoxStorageTarget(groundBox)); } public void Add(GameObject groundBox, StorageSlotInfo storageSlot) { if (storageSlot == null) { throw new ArgumentNullException("The parameter storageSlot cant be null. Use \"Add(GameObject groundBox)\" instead if this is intended."); } if (relMode == RelationshipMode.SingleStorage) { throw new InvalidOperationException("You must initialize GroundBoxStorageList using the empty constructor to use this method."); } groundBoxStorage.Add(new GroundBoxStorageTarget(groundBox, storageSlot)); } public bool HasItems() { switch (relMode) { case RelationshipMode.StoragePerBox: { List list2 = groundBoxStorage; return list2 != null && list2.Count > 0; } case RelationshipMode.SingleStorage: { List list = groundBoxList; return list != null && list.Count > 0; } default: throw new InvalidOperationException($"Non implemented enum switch {relMode}"); } } public List GetItems() { return relMode switch { RelationshipMode.StoragePerBox => groundBoxStorage, RelationshipMode.SingleStorage => groundBoxList.Select((GameObject box) => new GroundBoxStorageTarget(box, unassignedStorageSlot)).ToList(), _ => throw new InvalidOperationException($"Non implemented enum switch {relMode}"), }; } } public static GroundBoxStorageTarget GetClosestGroundBox(NPC_Manager __instance, Transform employeeT) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) List listUntargetedStationaryBoxes = GetListUntargetedStationaryBoxes(__instance.boxesOBJ); if (listUntargetedStationaryBoxes.Count == 0) { return GroundBoxStorageTarget.Default; } GroundBoxStorageList groundBoxStorageList = new GroundBoxStorageList(); Dictionary productIdListOfFreeStorage = GetProductIdListOfFreeStorage(__instance); if (productIdListOfFreeStorage.Count > 0) { groundBoxStorageList = GetStorableGroundBoxList(productIdListOfFreeStorage, listUntargetedStationaryBoxes); } if (!groundBoxStorageList.HasItems()) { StorageSlotInfo storageSlotInfo = ContainerSearch.FreeUnassignedStorageContainer(__instance, employeeT); if (storageSlotInfo.ShelfFound) { groundBoxStorageList = new GroundBoxStorageList(listUntargetedStationaryBoxes, storageSlotInfo); } } if (!groundBoxStorageList.HasItems()) { groundBoxStorageList = GetEmptyGroundBoxList(listUntargetedStationaryBoxes); } return GetClosestGroundBox(groundBoxStorageList, employeeT.position); } private static List GetListUntargetedStationaryBoxes(GameObject allGroundBoxes) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) List list = new List(); foreach (Transform item in allGroundBoxes.transform) { Transform val = item; if (!EmployeeTargetReservation.IsGroundBoxTargeted(((Component)val).gameObject)) { Vector3 velocity = ((Component)val).gameObject.GetComponent().velocity; if (((Vector3)(ref velocity)).sqrMagnitude < 1.5f) { list.Add(((Component)val).gameObject); } } } return list; } private static Dictionary GetProductIdListOfFreeStorage(NPC_Manager __instance) { Dictionary storableProducts = new Dictionary(); if (!ContainerSearch.IsAssignedStorageAllowed()) { return storableProducts; } ContainerSearchLambdas.ForEachStorageSlotLambda(__instance, checkNPCStorageTarget: true, skipEmptyBoxes: false, delegate(int storageIndex, int slotIndex, int productId, int quantity, Transform storageObjT) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (quantity <= 0 && productId >= 0 && !storableProducts.ContainsKey(productId)) { storableProducts.Add(productId, new StorageSlotInfo(storageIndex, slotIndex, productId, quantity, storageObjT.position)); } return ContainerSearchLambdas.LoopAction.Nothing; }); return storableProducts; } private static GroundBoxStorageList GetStorableGroundBoxList(Dictionary storableProducts, List untargetedGroundBoxes) { GroundBoxStorageList groundBoxStorageList = new GroundBoxStorageList(); foreach (GameObject untargetedGroundBox in untargetedGroundBoxes) { int productID = untargetedGroundBox.GetComponent().productID; foreach (KeyValuePair storableProduct in storableProducts) { if (productID == storableProduct.Key) { groundBoxStorageList.Add(untargetedGroundBox, storableProduct.Value); break; } } } return groundBoxStorageList; } private static GroundBoxStorageList GetEmptyGroundBoxList(List untargetedGroundBoxes) { GroundBoxStorageList groundBoxStorageList = new GroundBoxStorageList(); foreach (GameObject untargetedGroundBox in untargetedGroundBoxes) { if (untargetedGroundBox.GetComponent().numberOfProducts == 0) { groundBoxStorageList.Add(untargetedGroundBox); } } return groundBoxStorageList; } private static GroundBoxStorageTarget GetClosestGroundBox(GroundBoxStorageList groundBoxesTargets, Vector3 sourcePos) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!groundBoxesTargets.HasItems()) { return GroundBoxStorageTarget.Default; } GroundBoxStorageTarget result = null; float num = float.MaxValue; foreach (GroundBoxStorageTarget item in groundBoxesTargets.GetItems()) { Vector3 val = item.GroundBoxObject.transform.position - sourcePos; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = item; } } return result; } } public class GroundBoxStorageTarget { public static GroundBoxStorageTarget Default => new GroundBoxStorageTarget { FoundGroundBox = false, HasStorageTarget = false }; public bool FoundGroundBox { get; private set; } public GameObject GroundBoxObject { get; private set; } public bool HasStorageTarget { get; private set; } public StorageSlotInfo StorageSlot { get; private set; } private GroundBoxStorageTarget() { } public GroundBoxStorageTarget(GameObject GroundBoxObject) { if ((Object)(object)GroundBoxObject == (Object)null) { throw new ArgumentNullException("GroundBoxObject"); } FoundGroundBox = true; this.GroundBoxObject = GroundBoxObject; } public GroundBoxStorageTarget(GameObject GroundBoxObject, StorageSlotInfo StorageSlot) { if ((Object)(object)GroundBoxObject == (Object)null) { throw new ArgumentNullException("GroundBoxObject"); } if (StorageSlot == null) { throw new ArgumentNullException("StorageSlot"); } FoundGroundBox = true; this.GroundBoxObject = GroundBoxObject; HasStorageTarget = true; this.StorageSlot = StorageSlot; } } } namespace SuperQoLity.SuperMarket.PatchClassHelpers.Components { public class EmployeeWarpSound : MonoBehaviour { private static readonly Lazy> warpAudioClip = new Lazy>(() => GetWarpAudioClip()); private GameObject warpAudioGameObject; private static UnityTimeStopwatch warpGlobalCooldownTimer = new UnityTimeStopwatch(); private UnityTimeStopwatch warpLocalCooldownTimer = new UnityTimeStopwatch(); private const int warpGlobalCooldownMillis = 100; private const int warLocalCooldownMillis = 250; public static void PlayEmployeeWarpSound(NPC_Info employee) { EmployeeWarpSound employeeWarpSound = default(EmployeeWarpSound); if (!((Component)employee).gameObject.TryGetComponent(ref employeeWarpSound)) { employeeWarpSound = ((Component)employee).gameObject.AddComponent(); employeeWarpSound.Initialize(((Component)employee).gameObject.transform); } employeeWarpSound.PlayWarpSound(); } public void Initialize(Transform employeeTransform) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown warpAudioGameObject = new GameObject("WarpAudioGameObject"); warpAudioGameObject.transform.SetParent(employeeTransform); } private static async Task GetWarpAudioClip() { string combinedPathFromAssemblyFolder = AssemblyUtils.GetCombinedPathFromAssemblyFolder(typeof(EmployeeWarpSound), "SoundEffects\\Warp.mp3"); UnityWebRequest audioWebRequest = UnityWebRequestMultimedia.GetAudioClip(combinedPathFromAssemblyFolder, (AudioType)13); Awaiter val = AsyncOperationAwaitableExtensions.GetAwaiter((AsyncOperation)(object)audioWebRequest.SendWebRequest()); if (!((Awaiter)(ref val)).IsCompleted) { await val; Awaiter val2 = default(Awaiter); val = val2; } ((Awaiter)(ref val)).GetResult(); if ((int)audioWebRequest.result == 1) { return DownloadHandlerAudioClip.GetContent(audioWebRequest); } throw new InvalidOperationException($"Request ended with result {audioWebRequest.result} and error: {audioWebRequest.error}."); } private async Task PlayWarpSound() { AudioSource val = default(AudioSource); if (!warpAudioGameObject.TryGetComponent(ref val)) { val = await AddAudioSourceComponent(); } if ((!warpLocalCooldownTimer.IsRunning || warpLocalCooldownTimer.ElapsedMillisecondsPrecise >= 100.0) && (!warpGlobalCooldownTimer.IsRunning || warpGlobalCooldownTimer.ElapsedMillisecondsPrecise >= 250.0)) { warpLocalCooldownTimer.Restart(); warpGlobalCooldownTimer.Restart(); val.volume = 0.1f * ModConfig.Instance.TeleportSoundVolume.Value; val.Play(); return true; } return false; } private async Task AddAudioSourceComponent() { AudioSource warpSound = warpAudioGameObject.AddComponent(); AudioSource val = warpSound; val.clip = await warpAudioClip.Value; warpSound.playOnAwake = false; warpSound.priority = 256; warpSound.spatialBlend = 1f; warpSound.rolloffMode = (AudioRolloffMode)1; warpSound.maxDistance = 19f; warpSound.minDistance = 1f; return warpSound; } } } namespace SuperQoLity.SuperMarket.ModUtils { public static class Tags { public static string Interactable { get; } = "Interactable"; public static string Movable { get; } = "Movable"; public static string Decoration { get; } = "Decoration"; } public static class AuxUtils { [CompilerGenerated] private sealed class d__1 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private GameObject[] <>7__wrap1; private int <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0073; } <>1__state = -1; if (WorldState.CurrentGameWorldState == GameWorldEvent.QuitOrMenu) { return false; } Scene activeScene = SceneManager.GetActiveScene(); <>7__wrap1 = ((Scene)(ref activeScene)).GetRootGameObjects(); <>7__wrap2 = 0; goto IL_0081; IL_0073: <>7__wrap2++; goto IL_0081; IL_0081: if (<>7__wrap2 < <>7__wrap1.Length) { GameObject val = <>7__wrap1[<>7__wrap2]; if (((Object)val).name.StartsWith("Player_PREFAB")) { <>2__current = val; <>1__state = 1; return true; } goto IL_0073; } <>7__wrap1 = null; 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(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__1(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly uint CoolPackSteamID = 3146530u; [IteratorStateMachine(typeof(d__1))] public static IEnumerable GetRemotePlayerObjects() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(-2); } public static bool IsPlayerHoldingBox(out int productId) { PlayerNetwork val = SMTInstances.LocalPlayerNetwork(); if (!Object.op_Implicit((Object)(object)val)) { TimeLogger.Logger.LogError("The PlayerNetwork instance couldnt be found.Most probably the base code has changed or this has been called on the main menu.", (LogCategories)2); } productId = val.extraParameter1; return val.equippedItem == 1; } public static bool IsKeypressed(KeyCode key, bool onlyWhileChatClosed = true) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (!onlyWhileChatClosed || (onlyWhileChatClosed && IsChatOpen())) { return Input.GetKeyDown(key); } return false; } public static bool IsChatOpen() { return FsmVariables.GlobalVariables.GetFsmBool("InChat").Value; } public static bool IsMainMenuOpen() { return FsmVariables.GlobalVariables.FindFsmBool("InOptions").Value; } public static bool IsDLCSubscribed() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (SteamManager.Initialized) { return SteamApps.BIsSubscribedApp((AppId_t)CoolPackSteamID); } return false; } } public enum TargetObject { [Description("MasterOBJ/MasterCanvas")] UI_MasterCanvas, [Description("LocalGamePlayer")] LocalGamePlayer, [Description("GameDataManager")] GameDataManager } public enum TransformType { Transform, RectTransformUI } public static class GameObjectManager { private static readonly string superQolityPrefix = "SuperQoL_"; public static GameObject CreateSuperQoLGameObject(string name, TargetObject parentTarget, CreationSettings creationSettings) { if (GetGameObjectFrom(parentTarget, out var gameObject)) { return CreateSuperQoLGameObject(name, gameObject, creationSettings); } return null; } public static GameObject CreateSuperQoLGameObject(string name, GameObject parentObject, CreationSettings creationSettings) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_008d: 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_00fb: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)parentObject == (Object)null) { TimeLogger.Logger.LogError("The parameter parentObject cannot be null.", (LogCategories)int.MinValue); return null; } GameObject val = new GameObject(superQolityPrefix + name); if (creationSettings.TransformType == TransformType.RectTransformUI) { val.AddComponent(); } Transform transform = val.transform; val.SetActive(creationSettings.Active); transform.SetParent(parentObject.transform); if (creationSettings.TransformLocals.LocalPosition.HasValue) { transform.localPosition = creationSettings.TransformLocals.LocalPosition.Value; } if (creationSettings.TransformLocals.LocalRotation.HasValue) { transform.localRotation = creationSettings.TransformLocals.LocalRotation.Value; } if (creationSettings.TransformLocals.LocalScale.HasValue) { transform.localScale = creationSettings.TransformLocals.LocalScale.Value; } return val; } public static T AddComponentTo(TargetObject parentTarget) where T : Component { if (GetGameObjectFrom(parentTarget, out var gameObject)) { return gameObject.AddComponent(); } return default(T); } public static bool GetGameObjectFrom(TargetObject targetObject, out GameObject gameObject) { gameObject = UnityObjectExtensions.GameObject(GetComponentForTargetObject(targetObject)); if (gameObject == null) { gameObject = GameObject.Find(EnumExtension.GetDescription((Enum)targetObject)); } if ((Object)(object)gameObject == (Object)null) { TimeLogger.Logger.LogError("The GameObject for target " + $"\"{targetObject}\" ({EnumExtension.GetDescription((Enum)targetObject)}) could not be retrieved. Maybe you need " + "to do this it at a later point?", (LogCategories)int.MinValue); TimeLogger.Logger.LogError("On the other hand, the GameObject.Find is null? " + $"{(Object)(object)GameObject.Find(EnumExtension.GetDescription((Enum)targetObject)) == (Object)null}", (LogCategories)1); } return (Object)(object)gameObject != (Object)null; } private static Component GetComponentForTargetObject(TargetObject targetObject) { return (Component)(targetObject switch { TargetObject.UI_MasterCanvas => SMTInstances.GameCanvas(), TargetObject.LocalGamePlayer => SMTInstances.FirstPersonController(), TargetObject.GameDataManager => SMTInstances.GameDataManager(), _ => throw new NotImplementedException($"{targetObject} value is not implemented."), }); } } public readonly struct CreationSettings { public static CreationSettings Defaults { get; } = new CreationSettings(null, null, null); public bool Active { get; } public TransformType TransformType { get; } public TransformLocals TransformLocals { get; } public CreationSettings(bool? active, TransformType? transformType, TransformLocals? transformLocals) { Active = active.GetValueOrDefault(true); TransformType = transformType.GetValueOrDefault(); TransformLocals = transformLocals ?? TransformLocals.Inherited; } } public readonly struct TransformLocals { public static TransformLocals Inherited { get; } = new TransformLocals(null, null, null); public static TransformLocals Generic { get; } = new TransformLocals(Vector3.zero, Quaternion.identity, Vector3.one); public Vector3? LocalPosition { get; } public Vector3? LocalScale { get; } public Quaternion? LocalRotation { get; } public TransformLocals(Vector3? localPosition, Quaternion? localRotation, Vector3? localScale) { LocalPosition = localPosition; LocalScale = localScale; LocalRotation = localRotation; } } [StructLayout(LayoutKind.Sequential, Size = 1)] public struct SMTInstances { private static CustomCameraController cameraControllerCache; public static GameCanvas GameCanvas() { return GameCanvas.Instance; } public static FirstPersonController FirstPersonController() { return FirstPersonController.Instance; } public static PlayerNetwork LocalPlayerNetwork() { FirstPersonController obj = UnityObjectExtensions.NullableObject(FirstPersonController()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static BroomShotgunNetwork LocalBroomShotgunNetwork() { FirstPersonController obj = UnityObjectExtensions.NullableObject(FirstPersonController()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static GameData GameDataManager() { return GameData.Instance; } public static Builder_Main BuilderMain() { GameCanvas obj = UnityObjectExtensions.NullableObject(GameCanvas()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static NetworkSpawner NetworkSpawner() { GameData obj = UnityObjectExtensions.NullableObject(GameDataManager()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static GameObject MasterObject() { return FsmVariables.GlobalVariables.FindFsmGameObject("MasterOBJ").Value; } public static PlayerPermissions PlayerPermissions() { FirstPersonController obj = UnityObjectExtensions.NullableObject(FirstPersonController()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static ManagerBlackboard ManagerBlackboard() { GameData obj = UnityObjectExtensions.NullableObject(GameDataManager()); if (obj == null) { return null; } return ((Component)obj).GetComponent(); } public static CustomCameraController GetCustomCameraController() { CustomCameraController val = default(CustomCameraController); if (!Object.op_Implicit((Object)(object)cameraControllerCache) && GameObject.Find("Player_Camera").TryGetComponent(ref val)) { cameraControllerCache = val; } return cameraControllerCache; } } public enum PlayerPermissionsEnum { None, General, Manager, Cashier, Restocker, Security } public static class HostPermissions { private static PlayerPermissions playerPerms; private static PlayerPermissions GetCachedPlayerPermissions() { return UnityObjectExtensions.AssignIfDeadReference(ref playerPerms, SMTInstances.PlayerPermissions()); } public static bool HasPermission(PlayerPermissionsEnum permission) { if (!Object.op_Implicit((Object)(object)GetCachedPlayerPermissions())) { return false; } return permission switch { PlayerPermissionsEnum.General => GetCachedPlayerPermissions().hasGP, PlayerPermissionsEnum.Manager => GetCachedPlayerPermissions().hasMP, PlayerPermissionsEnum.Cashier => GetCachedPlayerPermissions().hasCP, PlayerPermissionsEnum.Restocker => GetCachedPlayerPermissions().hasRP, PlayerPermissionsEnum.Security => GetCachedPlayerPermissions().hasSP, PlayerPermissionsEnum.None => true, _ => throw new NotSupportedException(permission.ToString()), }; } } public enum HotkeyActiveContext { AlwaysActiveLowPrio = 0, WorldLoaded = 1, WorldLoadedNotPaused = 5, WheelHotkeysEnabled = 6, BroomEquipped = 9, CanShoot = 10, WorldLoadedHighPrio = 50, AlwaysActiveHighPrio = 99, RadialWheelOpen = 100 } public sealed class InputManagerSMT : InputBepInEx { private static InputManagerSMT _instance; public static InputManagerSMT Instance => _instance ?? (_instance = new InputManagerSMT()); public InputManagerSMT() : base(typeof(InputManagerSMT), (OnValidationError)0, true, new List()) { } protected override void HotkeyValidationError(string hotkeyName, string message, KeyBind keyBind) { ((InputBepInEx)this).HotkeyValidationError(hotkeyName, message, keyBind); TimeLogger.Logger.SendMessageNotification((LogTier)4, message, true); } private HotkeyContext GetContextFrom(HotkeyActiveContext hotkeyActCtx) { return (HotkeyContext)(hotkeyActCtx switch { HotkeyActiveContext.AlwaysActiveLowPrio => GenerateContext(hotkeyActCtx, null), HotkeyActiveContext.WorldLoaded => GenerateContext(hotkeyActCtx, () => WorldState.IsWorldLoaded), HotkeyActiveContext.WorldLoadedNotPaused => GenerateContext(hotkeyActCtx, () => WorldState.IsWorldLoaded && !AuxUtils.IsMainMenuOpen()), HotkeyActiveContext.WheelHotkeysEnabled => GenerateContext(hotkeyActCtx, () => ModConfig.Instance.EnableRadialQuickToolsKeys.Value), HotkeyActiveContext.BroomEquipped => GenerateContext(hotkeyActCtx, () => WorldState.IsWorldLoaded && WeaponManager.IsBroomEquipped()), HotkeyActiveContext.CanShoot => GenerateContext(hotkeyActCtx, () => WeaponManager.IsPlayerInShotgunmode(BroomShotgunNetwork.LocalInstance) && WeaponManager.CanUseWeapon()), HotkeyActiveContext.WorldLoadedHighPrio => GenerateContext(hotkeyActCtx, null), HotkeyActiveContext.RadialWheelOpen => GenerateContext(hotkeyActCtx, RadialWheelManager.IsRadialShowing), HotkeyActiveContext.AlwaysActiveHighPrio => GenerateContext(hotkeyActCtx, () => WorldState.IsWorldLoaded), _ => throw new NotImplementedException(hotkeyActCtx.ToString()), }); } private HotkeyContext GenerateContext(HotkeyActiveContext hotkeyActCtx, Func activationCondition) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown return new HotkeyContext(hotkeyActCtx.ToString(), activationCondition, (int)hotkeyActCtx); } public void AddHotkeyFromConfig(ConfigEntry hotkeyConfig, InputState inputState, HotkeyActiveContext hotkeyActCtx, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ((InputBepInEx)this).AddHotkeyFromConfig(hotkeyConfig, inputState, GetContextFrom(hotkeyActCtx), action); } public void AddHotkeyFromConfig(ConfigEntry hotkeyConfig, InputState inputState, HotkeyActiveContext hotkeyActCtx, int cooldownMillis, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ((InputBepInEx)this).AddHotkeyFromConfig(hotkeyConfig, inputState, GetContextFrom(hotkeyActCtx), cooldownMillis, action); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, KeyCode[] modifiers, InputState inputState, HotkeyActiveContext hotkeyActCtx, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, modifiers, inputState, GetContextFrom(hotkeyActCtx), action); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, KeyCode[] modifiers, InputState inputState, HotkeyActiveContext hotkeyActCtx, int cooldownMillis, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, modifiers, inputState, GetContextFrom(hotkeyActCtx), cooldownMillis, action); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, InputState inputState, HotkeyActiveContext hotkeyActCtx, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, Array.Empty(), inputState, GetContextFrom(hotkeyActCtx), action); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, InputState inputState, HotkeyActiveContext hotkeyActCtx, int cooldownMillis, Action action) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, Array.Empty(), inputState, GetContextFrom(hotkeyActCtx), cooldownMillis, action); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, KeyCode[] modifiers, InputState inputState, HotkeyActiveContext hotkeyActCtx, Action action, string groupName) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, modifiers, inputState, GetContextFrom(hotkeyActCtx), action, groupName); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, KeyCode[] modifiers, InputState inputState, HotkeyActiveContext hotkeyActCtx, int cooldownMillis, Action action, string groupName) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, modifiers, inputState, GetContextFrom(hotkeyActCtx), cooldownMillis, action, groupName); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, InputState inputState, HotkeyActiveContext hotkeyActCtx, Action action, string groupName) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, Array.Empty(), inputState, GetContextFrom(hotkeyActCtx), action, groupName); } public bool TryAddHotkey(string hotkeyName, KeyCode keyCode, InputState inputState, HotkeyActiveContext hotkeyActCtx, int cooldownMillis, Action action, string groupName) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return ((InputBepInEx)this).TryAddHotkey(hotkeyName, keyCode, Array.Empty(), inputState, GetContextFrom(hotkeyActCtx), cooldownMillis, action, groupName); } } public class MirrorDebugHeartbeat { private static bool IsConnectedAsClient; public static void Init() { WorldState.OnWorldLoaded += delegate { IsConnectedAsClient = WorldState.CurrentOnlineMode == GameOnlineMode.Client; if (IsConnectedAsClient) { StartHeartBeat(); } }; WorldState.OnQuitOrMainMenu += delegate { IsConnectedAsClient = false; }; } private static void StartHeartBeat() { Task.Run(async delegate { while (IsConnectedAsClient) { NetworkClient.Send(new NetworkPongMessage(double.MaxValue, 0.0, 0.0), 0); await Task.Delay(4000); } }); } } public class ModConfig { private static ModConfig instance; private ConfigManagerController configManagerControl; private const string RequiresRestartSymbol = "(**)"; private const string RequiresReloadSymbol = "(*)"; public const string EmployeeJobText = "Employee AI"; public const string CustomerText = "Customer"; public const string EmployeeJobModuleText = "Employee AI Module"; public const string CustomerModuleText = "Customer Module"; public const string PerformanceModuleText = "NPC Performance - Requires Employee AI or Customer module enabled"; public const string ItemTransferSpeedModuleText = "Item Transfer Speed Module"; public const string HighlightModuleText = "Highlight Module"; public const string EquipWheelModuleText = "Equipment Wheel Module"; public const string BuildModuleText = "Build Module"; public const string MiscModuleText = "Misc. Module"; public const string NotificationsModuleText = "Notifications Module"; public const string PerfDisplayFreqMultModuleText = "x AI Workload Capacity Counter x"; public const string PerfCustomSettingsModuleText = "xx NPC AI Custom Settings Module xx"; public const string DebugModuleText = "z DEBUG z"; public const string WorkloadCapacityDescription = "NOTE: A \"unit\" (a value of 1) of workload capacity, is equal to a total of 50 turns to share between all employees, and another 50 for all customers, each second."; public static ModConfig Instance => instance ?? (instance = new ModConfig()); public ConfigEntry EnableEmployeeChanges { get; private set; } public ConfigEntry ClosedStoreEmployeeWalkSpeedMultiplier { get; private set; } public ConfigEntry ClosedStoreEmployeeItemTransferMaxed { get; private set; } public ConfigEntry EmployeeNextActionWait { get; private set; } public ConfigEntry ImprovedSecurityPickUpMode { get; private set; } public ConfigEntry SecurityThiefChaseMode { get; private set; } public ConfigEntry FreeStoragePriority { get; private set; } public ConfigEntry EnableCustomerChanges { get; private set; } public ConfigEntry EnableCustomerStuckDetection { get; private set; } public ConfigEntry EnableShopListOnlyAssignedProducts { get; private set; } public ConfigEntry CustomerCardPayRatio { get; private set; } public ConfigEntry NpcJobFrequencyMode { get; private set; } public ConfigEntry EmployeeIdleWait { get; private set; } public ConfigEntry EnableTransferProducts { get; private set; } public ConfigEntry ItemTransferMode { get; private set; } public ConfigEntry NumTransferProducts { get; private set; } public ConfigEntry EnablePatchHighlight { get; private set; } public ConfigEntry HighlightVisualMode { get; private set; } public ConfigEntry HotkeyCycleHighlightMode { get; private set; } public ConfigEntry HotkeyToggleAimedHighlight { get; private set; } public ConfigEntry ShelfHighlightColorRGBA { get; private set; } public ConfigEntry ShelfLabelHighlightColorRGBA { get; private set; } public ConfigEntry StorageHighlightColorRGBA { get; private set; } public ConfigEntry StorageSlotHighlightColorRGBA { get; private set; } public ConfigEntry EnableRadialWheelPatches { get; private set; } public ConfigEntry RadialEquipmentWheelHotkey { get; private set; } public ConfigEntry EnableRadialQuickToolsKeys { get; private set; } public ConfigEntry RadialQuickToolsModifierKey { get; private set; } public ConfigEntry RadialDisplayControl { get; private set; } public ConfigEntry BroomShotgunModeEnabled { get; private set; } public ConfigEntry BroomShotgunModeHotkey { get; private set; } public ConfigEntry MaxShotgunSmokeParticles { get; private set; } public ConfigEntry EnableBuildPatches { get; private set; } public ConfigEntry CloneBuildHotkey { get; private set; } public ConfigEntry MoveBuildHotkey { get; private set; } public ConfigEntry CloneMoveTargetDistance { get; private set; } public ConfigEntry EnableIncreasedPropLoadLimits { get; private set; } public ConfigEntry EnableMiscPatches { get; private set; } public ConfigEntry EnableCheckoutAutoClicker { get; private set; } public ConfigEntry EnablePriceGunFix { get; private set; } public ConfigEntry EnableExpandedProdOrderClickArea { get; private set; } public ConfigEntry EnableModNotifications { get; private set; } public ConfigEntry EnableWelcomeMessages { get; private set; } public ConfigEntry EnableErrorMessages { get; private set; } public ConfigEntry DisplayAutoModeFrequencyMult { get; private set; } public ConfigEntry CustomEmployeeWaitTarget { get; private set; } public ConfigEntry CustomCustomerWaitTarget { get; private set; } public ConfigEntry CustomMinimumFrequencyMult { get; private set; } public ConfigEntry CustomMaximumFrequencyMult { get; private set; } public ConfigEntry CustomMaximumFrequencyReduction { get; private set; } public ConfigEntry CustomMaximumFrequencyIncrease { get; private set; } public ConfigEntry EnabledDevMode { get; private set; } public ConfigEntry TeleportSoundVolume { get; private set; } private ModConfig() { } public void InitializeConfig(BaseUnityPlugin basePlugin) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown configManagerControl = new ConfigManagerController(basePlugin.Config); } public void StartConfigBinding() { if (configManagerControl == null) { throw new InvalidOperationException("You must call InitializeConfig first."); } InitializeConfigStartNotes(); string moduleGenericEnablerKey = "*Enable ·{0}· (**)"; string moduleGenericEnablerDescription = "This makes it possible for other settings in the [{0}] section to work.\nDisable in case of errors."; InitializeEmployeeAIModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeNpcPerformanceModule(); InitializeCustomerModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeItemTransferSpeedModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeHighlightExtensionModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeBroomShotgunMode(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeRadialWheelModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeBuildModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeMiscModule(moduleGenericEnablerKey, moduleGenericEnablerDescription); InitializeNotificationModule(); InitializeDisplayAutoSettingsModule(); InitializeNpcPerformanceCustomSettingsModule(); InitializeDebugModule(); configManagerControl.RenameOrphanedSettings(); Plugin.HookChangeDebugSetting(); } private void InitializeConfigStartNotes() { configManagerControl.AddGUIHiddenNote("!↓ NOTE ABOUT CONFIG FILE EDITING ↓!", "", "I highly recommend installing \"Bepinex.ConfigurationManager\" so you can change settings in-game.\nYou can grab the latest BepInEx5 version from its GitHub Releases page:\nhttps://github.com/BepInEx/BepInEx.ConfigurationManager/releases\n\n ********* SETTINGS HELP *********\n\nSettings usually have the following format: \n\n\t## Setting description.\n\t# Setting Type: ...\n\t# Default value: ...\n\t# Acceptable value range/Acceptable values: ... (This one might not exist for the setting)\n\tSetting short description = Value.\n\nThere are predefined values for each setting, depending on its \"Setting type\":\n * Boolean - Its value can be either true or false.\n * Int32 - An integer numeric value. Limited by \"# Acceptable value range\"\n * Single - A decimal value, like 13.1, or 0. Limited by \"# Acceptable value range\".\n * EnumFreeStoragePriority/Enum... - These are special types that have a range of values to choose from. Valid values are shown in a comma separated list in \"# Acceptable values\".\n * KeyboardShortcut: - Activation hotkey. For a full list, see the 'Properties' section at https://docs.unity3d.com/2023.1/Documentation/ScriptReference/KeyCode.html . Only keyboard and mouse input is supported. Modifiers can be added with '+': Example: \"LeftControl + Y\"\n\n ***************************************\n\nHost: Player that creates the game in multiplayer.\nClient: Player that joins an already created multiplayer game", (IConfigPatchDependence)null, false); configManagerControl.AddSectionNote("· Settings with a (**) symbol require a restart to apply changes, and hides related settings when disabled.· Settings with a (*) symbol will work after reloading a save.", (string)null, (IConfigPatchDependence)null, false, false); } private void InitializeEmployeeAIModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { EnableEmployeeChanges = configManagerControl.AddConfig("Employee AI Module", string.Format(moduleGenericEnablerKey, "Employee AI Module"), true, string.Format(moduleGenericEnablerDescription, "Employee AI Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); ConfigManagerController obj = configManagerControl; AcceptableValueRange val = new AcceptableValueRange(0.25f, 10f); ClosedStoreEmployeeWalkSpeedMultiplier = obj.AddConfigWithAcceptableValues("Employee AI Module", "Employee walk speed mult. (closed store)", 1f, "Employee movement speed will be multiplied by this value while the store is closed with no customers.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ClosedStoreEmployeeItemTransferMaxed = configManagerControl.AddConfig("Employee AI Module", "Employee fast item placing (closed store)", false, "Restock employees will place all products in a shelf at once, but only while the store is closed with no customers.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, false, false); ConfigManagerController obj2 = configManagerControl; val = new AcceptableValueRange(0.1f, 4f); EmployeeNextActionWait = obj2.AddConfigWithAcceptableValues("Employee AI Module", "Wait time after job step is finished", 1.5f, "Sets the amount of time, in seconds, that an employee will idle before going into the next job step, like picking up a box or placing it in a storage slot. \nDoes not affect employee checkout speed or restocker item placing.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ImprovedSecurityPickUpMode = configManagerControl.AddConfigWithAcceptableValues("Employee AI Module", "Improved security pick-up mode", EnumSecurityPickUp.Disabled, "As security employees level up, they will be able to pick up more products at " + $"once, and reach across a larger area. All benefits stop improving at level {EmployeeJobAIPatch.MaxSecurityPickUpLevel} \n" + $"- {EnumSecurityPickUp.Disabled}: Same as base game. Products are picked up one by one." + $"- {EnumSecurityPickUp.Reduced}: All security level benefits halved compared to \"{EnumSecurityPickUp.Normal}\". " + $"A level 100 security employee with the {EnumSecurityPickUp.Reduced} setting, will have the same " + $"pick-up skills as a level 50 with the {EnumSecurityPickUp.Normal} setting" + $"- {EnumSecurityPickUp.Normal}: Security will pick up an additional product every " + $"{EmployeeJobAIPatch.LevelsForExtraPickUp} levels, and slightly increase its range every level" + $"- {EnumSecurityPickUp.AlwaysMaxed}: All security employees will have the best possible pick-up stats.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, (AcceptableValueRange)null, false, false, false); SecurityThiefChaseMode = configManagerControl.AddConfigWithAcceptableValues("Employee AI Module", "Security Thief Chase", EnumSecurityEmployeeThiefChase.Disabled, "This sets the mode in which security employees will work against thieves:\n" + $"- {EnumSecurityEmployeeThiefChase.Disabled}: Same as base game. All security employees " + "will target the first thief they can find.\n" + $"- {EnumSecurityEmployeeThiefChase.AllChaseButLastOne}: Same as base game, but if all thieves " + "are already being chased, one security employee will keep watch for the next thief.\n" + $"- {EnumSecurityEmployeeThiefChase.OnlyOnePerThief}: Recommended mode. Each thief will be " + "chased by a single security employee and no more. The rest keep watch for the next thief.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, (AcceptableValueRange)null, false, false, false); FreeStoragePriority = configManagerControl.AddConfigWithAcceptableValues("Employee AI Module", "Employee storage shelf priority", EnumFreeStoragePriority.Labeled, "Controls which types of storage shelves employees may use and in what order of priority.\nAny shelf type not specified in the setting, becomes off-limits for employees to place boxes in, though they will still pick up boxes from it. Restocker box merging ignores priority, but will avoid disallowed storage types.\n" + $"{EnumFreeStoragePriority.Labeled} ({EnumExtension.GetDescription((Enum)EnumFreeStoragePriority.Labeled)}) - Vanilla behaviour.\n" + $"{EnumFreeStoragePriority.Unlabeled} ({EnumExtension.GetDescription((Enum)EnumFreeStoragePriority.Unlabeled)}\n)" + $"{EnumFreeStoragePriority.OnlyLabeled} ({EnumExtension.GetDescription((Enum)EnumFreeStoragePriority.OnlyLabeled)})\n" + $"{EnumFreeStoragePriority.OnlyUnlabeled} ({EnumExtension.GetDescription((Enum)EnumFreeStoragePriority.OnlyUnlabeled)})\n", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, (AcceptableValueRange)null, false, false, false); } private void InitializeCustomerModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { EnableCustomerChanges = configManagerControl.AddConfig("Customer Module", string.Format(moduleGenericEnablerKey, "Customer Module"), true, string.Format(moduleGenericEnablerDescription, "Customer Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); EnableCustomerStuckDetection = configManagerControl.AddConfig("Customer Module", "Enable stuck customer fix", false, "Check whether a customer seems to be stuck unable to move, and tries to free it with progressively more aggressive methods.\nThis may have a small performance hit on weaker CPUs.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, false, false); EnableShopListOnlyAssignedProducts = configManagerControl.AddConfig("Customer Module", "Customers dont buy all unlocked products", false, "Prevents customers from trying to buy unlocked products that you did not put up for sale, so you can focus your store on selling only the products you want.\nWhen you open the store, a list is generated of all product types assigned to store shelves, empty or not. Customers will only buy products that are in that list. \nThis internal list cannot be modified, and will refresh next time you reopen the store. Think of it as if the store is sending out the catalog of products for the day, and changing shelf assignments afterwards wont affect what customers expect to find.\nCustomers still complain if they cant find any of the products supposed to be on stock from the list. ", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, false, false); CustomerCardPayRatio = configManagerControl.AddConfigWithAcceptableValues("Customer Module", "Card pay percentage", 50, "Lets you adjust the percentage of customers that pay with card.\n0: All customers pay with cash.\n100: All customers pay with credit card.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, new AcceptableValueRange(0, 100), true, false, false); } private void InitializeNpcPerformanceModule() { NpcJobFrequencyMode = configManagerControl.AddConfigWithAcceptableValues("NPC Performance - Requires Employee AI or Customer module enabled", "Npc performance system", EnumJobFrequencyMultMode.Disabled, "TL;DR: Choose Auto_Performance if your system is slow, otherwise go with Auto_Balanced.\n\nEmployees/Customers have a fixed set of \"actions\" they do each second.\nThis setting allows you to choose an automatic balancing system on how npcs will perform. \nIt wont make npcs faster than normal, but it avoids them reacting slower due to game limits.\n\n- Disabled: Same as unmodded game\n- Auto_Performance: System performance over npc reaction times\n- Auto_Balanced: Recommended option. Switches between using less or more resources than vanilla game, depending on npc needs\n- Auto_Aggressive: Adjusts for max npc responsiveness\n- Auto_Custom: For advanced users. Lets you set all internal values. You can change them below in the ·xx NPC AI Custom Settings Module xx· section.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, (AcceptableValueRange)null, false, false, false); ConfigManagerController obj = configManagerControl; AcceptableValueRange val = new AcceptableValueRange(1f, 10f); EmployeeIdleWait = obj.AddConfigWithAcceptableValues("NPC Performance - Requires Employee AI or Customer module enabled", "Job check frequency while idle", 2f, "Sets the interval (in seconds) for an idle employee to search for new jobs. Higher values may improve performance.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); } private void InitializeItemTransferSpeedModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { EnableTransferProducts = configManagerControl.AddConfig("Item Transfer Speed Module", string.Format(moduleGenericEnablerKey, "Item Transfer Speed Module"), true, string.Format(moduleGenericEnablerDescription, "Item Transfer Speed Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); ItemTransferMode = configManagerControl.AddConfig("Item Transfer Speed Module", "Product shelf item transfer mode", EnumItemTransferMode.Disabled, "Sets when extra item transfer will work.IMPORTANT NOTE: Internally disabled if \"High Latency Mode\" is enabled.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, false, false); ConfigManagerController obj = configManagerControl; int numTransferItemsBase = EmployeeJobAIPatch.NumTransferItemsBase; string text = "The number of items you place or take from a product shelf when you click (or hold click) on it.\nThe setting \"" + ((ConfigEntryBase)ItemTransferMode).Definition.Key + "\" must not be " + EnumExtension.GetDescription((Enum)EnumItemTransferMode.Disabled) + "."; AcceptableValueRange val = new AcceptableValueRange(1, 50); NumTransferProducts = obj.AddConfigWithAcceptableValues("Item Transfer Speed Module", "Product shelf item transfer quantity", numTransferItemsBase, text, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, val, false, false, false); } private void InitializeHighlightExtensionModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) EnablePatchHighlight = configManagerControl.AddConfig("Highlight Module", string.Format(moduleGenericEnablerKey, "Highlight Module"), true, string.Format(moduleGenericEnablerDescription, "Highlight Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); HighlightVisualMode = configManagerControl.AddConfig("Highlight Module", "Highlight visual mode", HighlightMode.Disabled, "The highlight visuals around the object's shape.\nWhile highlighted, all of them have the same small performance hit in most cases, but generally, " + $"{HighlightMode.OutlineOnly} is the fastest, and going lower on the list gets " + $"progressively slower, with {HighlightMode.SeeThrough} being the slowest:\n" + $" - {HighlightMode.Disabled}: No highlighting.\n" + $" - {HighlightMode.OutlineOnly}: A simple outline. The closest to the old highlight visuals.\n" + $" - {HighlightMode.OutlineGlow}: An outline in direct view, and a glow when not in view.\n" + $" - {HighlightMode.OutlineBlurredGlow}: An outline in direct view, and a fuzzy glow when not in view.\n" + $" - {HighlightMode.SeeThrough}: Colors the entire shelf when not in direct view.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); HotkeyCycleHighlightMode = configManagerControl.AddConfig("Highlight Module", "Cycle through highlight modes", KeyboardShortcut.Empty, "Changes the current highlight visual mode with a hotkey.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); HotkeyToggleAimedHighlight = configManagerControl.AddConfig("Highlight Module", "Highlight product on crosshair", KeyboardShortcut.Empty, "Looking at a box or item from a short distance (its info will appear in the top-right panel) and pressing this hotkey will activate its highlight. \nIf no product is being looked at, it removes all current highlights.\nWhen holding a box and not looking at a product, it toggles highlighting for the held item.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); configManagerControl.AddGUIHiddenNote("Highlight Module", "", "Below you can set each highlight color.\nThe format is an Hexadecimal RGB with an optional transparency channel (RRGGBB or RRGGBBAA). There are many \"color to hex\" websites to help you set the color.\nThe alpha channel is used to control the intensity of the color. By default its \"BF\", equivalent to 75% of max intensity, but higher values may be needed in brightly lit stores or the highlight might be hard to see.", (IConfigPatchDependence)null, false); ShelfHighlightColorRGBA = configManagerControl.AddConfig("Highlight Module", "Shelf highlight color", new Color(1f, 0.25f, 0.1f, 0.75f), "Color of product shelves when highlighted. The alpha channel controls effect intensity.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); ShelfLabelHighlightColorRGBA = configManagerControl.AddConfig("Highlight Module", "Shelf label highlight color", new Color(1f, 1f, 0f, 0.75f), "Color of shelf labels when highlighted. The alpha channel controls effect intensity.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); StorageHighlightColorRGBA = configManagerControl.AddConfig("Highlight Module", "Storage highlight color", new Color(0f, 0f, 1f, 0.75f), "Color of storage shelves when highlighted. The alpha channel controls effect intensity.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); StorageSlotHighlightColorRGBA = configManagerControl.AddConfig("Highlight Module", "Storage slot highlight color", new Color(0f, 1f, 1f, 0.75f), "Color of storage slot spaces when highlighted. The alpha channel controls effect intensity.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); } private void InitializeRadialWheelModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) string text = "Wheel display control"; string text2 = "Quick tools modifier"; QuickToolKeyModifiers quickToolKeyModifiers = QuickToolKeyModifiers.LeftControl; EnableRadialWheelPatches = configManagerControl.AddConfig("Equipment Wheel Module", string.Format(moduleGenericEnablerKey, "Equipment Wheel Module"), true, string.Format(moduleGenericEnablerDescription, "Equipment Wheel Module") + "\n\nThis setting also enables other players to use the equipment wheel when you are the host.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); RadialEquipmentWheelHotkey = configManagerControl.AddConfig("Equipment Wheel Module", "Equipment wheel hotkey", KeyboardShortcut.Empty, "Hotkey for showing up the equipment wheel while held. Releasing it with a tool selected equips it. You can also left click to select the tool, or right click to cancel and close the equipment wheel.\nTools are not magically spawned, but instead they are teleported to your hands, which means the tool must already exist in an organizer or on the map for it to work.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, false, false); EnableRadialQuickToolsKeys = configManagerControl.AddConfig("Equipment Wheel Module", "Enable quick tool hotkeys", false, "Enable hotkeys to bring up a tool without using the wheel.\nHotkeys start from key '1' and up, with an optional modifier key (" + EnumExtension.GetDescription((Enum)quickToolKeyModifiers) + " by default) that you can set in the '" + text2 + "' setting below.If you want a different hotkey number for a tool, change their order in the '" + text + "' setting below. \nDance moves will still play when pressing numbers, so you should reassign those.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, false, false); RadialQuickToolsModifierKey = configManagerControl.AddConfig("Equipment Wheel Module", "Quick tools modifier", quickToolKeyModifiers, "Modifier key used in combination with a number to bring up the corresponding tool.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, false, false); RadialDisplayControl = configManagerControl.AddConfig("Equipment Wheel Module", text + " (*)", ToolWheelDefinitions.GetDefaultDisplayControlString(), "Here you can list the tools you want displayed in the equipment wheel, and their position. The first tool in the list shows up at the top of the equipment wheel, with next ones following a clockwise direction.\nThe format is a comma separated list of tools, case insensitive.If the list is empty or its format is not valid, all tools will be shown as if default.\n", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); } private void InitializeBroomShotgunMode(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) string text = "American Module"; BroomShotgunModeEnabled = configManagerControl.AddConfig(text, string.Format(moduleGenericEnablerKey, text), true, string.Format(moduleGenericEnablerDescription, text), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); BroomShotgunModeHotkey = configManagerControl.AddConfig(text, "Toggle broom aiming", new KeyboardShortcut((KeyCode)324, Array.Empty()), "Press this hotkey while holding a broom to enter aim mode, then left click to shoot. The same key will also switch back to holding the broom normally. Have fun.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, false, false); ConfigManagerController obj = configManagerControl; AcceptableValueRange val = new AcceptableValueRange(0, 3000); MaxShotgunSmokeParticles = obj.AddConfigWithAcceptableValues(text, "Max smoke particles", 2000, "Limit the amount of smoke particles from shooting. This should only matter in potato computers, in which case lower it to get more performance.A value of 0 completely disables smoke effects.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)3, false, false, val, false, false, false); } private void InitializeBuildModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) EnableBuildPatches = configManagerControl.AddConfig("Build Module", string.Format(moduleGenericEnablerKey, "Build Module"), true, string.Format(moduleGenericEnablerDescription, "Build Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); CloneBuildHotkey = configManagerControl.AddConfig("Build Module", "Clone target buildable hotkey", KeyboardShortcut.Empty, "Shortcut to open the build menu, with the targeted building preselected and ready to buy and place.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)1, false, false, false, false); MoveBuildHotkey = configManagerControl.AddConfig("Build Module", "Move target buildable hotkey", KeyboardShortcut.Empty, "Shortcut to put the targeted building in 'Placement mode'.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)1, false, false, false, false); CloneMoveTargetDistance = configManagerControl.AddConfigWithAcceptableValues("Build Module", "Clone/Move max target distance", 40, "Limit on how far away a buildable can be for the above hotkeys to clone it or move it.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)1, false, false, new AcceptableValueRange(5, 100), false, false, false); EnableIncreasedPropLoadLimits = configManagerControl.AddConfig("Build Module", "Increased limit of buildables (*)", false, $"This solves the problem of the vanilla game having a limit of {GenericBuildPatches.VanillaPropLoadLimit} " + "buildables, and decoratives, so any items built after that wont show up. This patch is for those madmen, madwomen and madchildren that went the extra mile and got " + $"to hit this limit. Now you get {GenericBuildPatches.NewPropLoadLimit} as the new limit " + "so try to beat that, you freaks.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, false, false); } private void InitializeMiscModule(string moduleGenericEnablerKey, string moduleGenericEnablerDescription) { EnableMiscPatches = configManagerControl.AddConfig("Misc. Module", string.Format(moduleGenericEnablerKey, "Misc. Module"), true, string.Format(moduleGenericEnablerDescription, "Misc. Module"), (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); EnableCheckoutAutoClicker = configManagerControl.AddConfig("Misc. Module", "Hold click to scan checkout products", false, "Instead of having to keep pressing Main Action (Left Click by default) to scan each product on the cash register belt, you can hold it to continuously scan as you mouse over products.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); EnablePriceGunFix = configManagerControl.AddConfig("Misc. Module", "Enable pricing gun double price fix", false, "Fixes customers sometimes complaining when prices are set to 200%.See the 0.8.2.0 changelog for a explanation on why I consider this a bug.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, false, false); EnableExpandedProdOrderClickArea = configManagerControl.AddConfig("Misc. Module", "Increased clickable area in product order", false, "When at the Manager Blackboard, you can click anywhere in the product panel to add it to the shopping list, instead of just the \"+\" button.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, false, false); } private void InitializeNotificationModule() { EnableModNotifications = configManagerControl.AddConfig("Notifications Module", "Enable custom mod notifications (**)", true, "If enabled, you may receive custom notifications from this mod.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, false); EnableWelcomeMessages = configManagerControl.AddConfig("Notifications Module", "Enable random welcome messages (*)", true, "When you load into a supermarket, there is a chance that you get a random welcoming message.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)1, false, false, false, false); EnableErrorMessages = configManagerControl.AddConfig("Notifications Module", "Enable error messages (*)", true, "If a mod patch fails, it will show a message to warn you.\nAdditionally, after that it will show a super helpful tip to, maybe, fix the error!", (IConfigPatchDependence)null, (MultiplayerModInstallSide)1, false, false, false, false); } private void InitializeDisplayAutoSettingsModule() { DisplayAutoModeFrequencyMult = configManagerControl.AddConfig("x AI Workload Capacity Counter x", "Show workload capacity counter", false, "Shows a counter with the workload capacity used in the last cycle (1 second) for Employees (E) and Customers (C) separately.\nLower values means less cpu was used for npc actions. A value of 1 is the same as the base game value.\nThis will only work while the " + ((ConfigEntryBase)NpcJobFrequencyMode).Definition.Key + " setting is in any of the \"Auto\" modes.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)2, false, false, false, false); } private void InitializeNpcPerformanceCustomSettingsModule() { string text = "∨ This setting is only used if \"" + ((ConfigEntryBase)NpcJobFrequencyMode).Definition.Key + "\" value is \"" + EnumExtension.GetDescription((Enum)EnumJobFrequencyMultMode.Auto_Custom) + "\" ∨\n\nDefault values are the same as in the Balanced performance mode.\n"; BalancedMode balancedMode = new BalancedMode(); ConfigManagerController obj = configManagerControl; float avgEmployeeWaitTargetMillis = balancedMode.AvgEmployeeWaitTargetMillis; string text2 = text + "\n\nEmployees have limited \"turns\" to do its job, and end up waiting more or less depending on how much total work there is.This setting sets the wait time, in milliseconds, for the system to automatically balance workload capacity, so the average wait time between all employees/customers is kept as close as possible to this value.\nSmaller values will make the system work harder to give more turns to npcs and reduce wait times."; AcceptableValueRange val = new AcceptableValueRange(AutoModeLimits.AvgNpcWaitTarget.MinLimit, AutoModeLimits.AvgNpcWaitTarget.MaxLimit); CustomEmployeeWaitTarget = obj.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Average employee wait time target", avgEmployeeWaitTargetMillis, text2, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ConfigManagerController obj2 = configManagerControl; float avgCustomerWaitTargetMillis = balancedMode.AvgCustomerWaitTargetMillis; string text3 = text + "\n\nSame as " + ((ConfigEntryBase)CustomEmployeeWaitTarget).Definition.Key + ", but for customers. Since most of the time there are far more customers than employees, it is recommended to keep this value higher to avoid dragging the system too much at peak store times."; val = new AcceptableValueRange(AutoModeLimits.AvgNpcWaitTarget.MinLimit, AutoModeLimits.AvgNpcWaitTarget.MaxLimit); CustomCustomerWaitTarget = obj2.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Average customer wait time target", avgCustomerWaitTargetMillis, text3, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ConfigManagerController obj3 = configManagerControl; float minFreqMult = balancedMode.MinFreqMult; string text4 = text + "\n\nSets the minimum possible workload capacity. When the job scheduler detects that the target wait time is being sufficiently kept, it will start reducing workload capacity up to this value to save performance.NOTE: A \"unit\" (a value of 1) of workload capacity, is equal to a total of 50 turns to share between all employees, and another 50 for all customers, each second."; val = new AcceptableValueRange(AutoModeLimits.MinFreqMult.MinLimit, AutoModeLimits.MinFreqMult.MaxLimit); CustomMinimumFrequencyMult = obj3.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Minimum workload capacity", minFreqMult, text4, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ConfigManagerController obj4 = configManagerControl; float maxFreqMult = balancedMode.MaxFreqMult; string text5 = text + "\n\nSets the maximum possible workload capacity. When the job scheduler detects that the npc wait time is higher than the target, it will start increasing workload capacity up to this value. Be careful, since higher values can have a big impact on cpu usage by the AI.\nNOTE: A \"unit\" (a value of 1) of workload capacity, is equal to a total of 50 turns to share between all employees, and another 50 for all customers, each second."; val = new AcceptableValueRange(AutoModeLimits.MaxFreqMult.MinLimit, AutoModeLimits.MaxFreqMult.MaxLimit); CustomMaximumFrequencyMult = obj4.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Maximum workload capacity", maxFreqMult, text5, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ConfigManagerController obj5 = configManagerControl; float num = Math.Abs(balancedMode.DecreaseStep); string text6 = text + "\n\nSets how quickly the job scheduler can reduce workload capacity. Each cycle (1 second), it will reduce workload capacity up to this quantity. The actual quantity will depend on how far below target is the npc avg wait timer."; val = new AcceptableValueRange(AutoModeLimits.DecreaseStep.MinLimit, AutoModeLimits.DecreaseStep.MaxLimit); CustomMaximumFrequencyReduction = obj5.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Maximum workload reduction per cycle", num, text6, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); ConfigManagerController obj6 = configManagerControl; float increaseStep = balancedMode.IncreaseStep; string text7 = text + "\n\nSets how quickly the job scheduler can increase workload capacity. Each cycle (1 second), it will increase workload capacity up to this quantity. The actual quantity will depend on how far above target is the npc avg wait timer."; val = new AcceptableValueRange(AutoModeLimits.IncreaseStep.MinLimit, AutoModeLimits.IncreaseStep.MaxLimit); CustomMaximumFrequencyIncrease = obj6.AddConfigWithAcceptableValues("xx NPC AI Custom Settings Module xx", "Maximum workload increase per cycle", increaseStep, text7, (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)2, false, false, val, false, false, false); } private void InitializeDebugModule() { bool num = EnabledDevMode?.Value ?? false; EnabledDevMode = BindDebugConfig(); if (num) { EnabledDevMode.Value = true; } ConfigManagerController obj = configManagerControl; AcceptableValueRange val = new AcceptableValueRange(0f, 1f); TeleportSoundVolume = obj.AddConfigWithAcceptableValues("z DEBUG z", "Teleport sound volume", 0.5f, "Volume of the teleport sound effect.", (IConfigPatchDependence)(object)Container.Instance, (MultiplayerModInstallSide)1, false, false, val, false, false, true); } private ConfigEntry BindDebugConfig() { return configManagerControl.AddConfig("z DEBUG z", "Enable DEV mode", false, "Dev stuff you dont want to know about.", (IConfigPatchDependence)null, (MultiplayerModInstallSide)0, false, false, false, true); } public bool IsDebugEnabledConfig() { bool value; if (EnabledDevMode == null) { EnabledDevMode = BindDebugConfig(); value = EnabledDevMode.Value; configManagerControl.Remove(((ConfigEntryBase)EnabledDevMode).Definition); } else { value = EnabledDevMode.Value; } return value; } } public static class ShaderUtils { public static readonly Lazy LegacyParticleShader = new Lazy((Func)(() => Shader.Find("Legacy Shaders/Particles/Additive") ?? Shader.Find("Unlit/Color"))); public static readonly Lazy URP_ParticleShaderUnlit = new Lazy((Func)(() => Shader.Find("Universal Render Pipeline/Particles/Unlit") ?? Shader.Find("Unlit/Color"))); public static readonly Lazy SMT_Shader = new Lazy((Func)GetGameShader); private static Shader GetGameShader() { if ((Object)(object)GameData.Instance == (Object)null) { TimeLogger.Logger.LogWarning("GameData instance null", (LogCategories)268435456); return null; } GameObject obj = UnityObjectExtensions.NullableObject(GameObject.Find("Level_SupermarketProps/UsableProps")); if (obj == null) { return null; } return ((Renderer)((Component)obj.transform.GetChild(0)).GetComponent()).material.shader; } } [Flags] public enum SMT_Layers { None = -1, Default = 0, TransparentFX = 1, IgnoreRaycast = 2, OverlapLayer = 3, Water = 4, UI = 5, Player = 6, Interactable = 7 } public static class SMTLayers { public static readonly int RayCastGenericLayerMask = ConvertLayersToMask(SMT_Layers.Default, SMT_Layers.Water, SMT_Layers.Player); public static int ConvertLayersToMask(params SMT_Layers[] layers) { int num = 0; foreach (SMT_Layers sMT_Layers in layers) { num |= 1 << (int)sMT_Layers; } return num; } } } namespace SuperQoLity.SuperMarket.ModUtils.UI { public class UIPanelHandler { public const string UIPanelName = "SuperQolInfoPanel"; public const string UIPanelPrefabName = "superqol"; private const float MaxBarValue = 1000f; private static AssetBundleElement bundleElement; public static bool IsPanelLoaded; private static float barMaxHeight; private static GameObject superQolUIPanel; public static bool LoadUIPanel() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (IsPanelLoaded) { TimeLogger.Logger.LogWarning("Performance panel was already loaded.", (LogCategories)4); return true; } if (bundleElement == null) { bundleElement = new AssetBundleElement(typeof(Plugin), "Assets\\Debug\\superqol"); } if (bundleElement.TryLoadNewPrefabInstance("SuperQolInfoPanel", ref superQolUIPanel)) { IsPanelLoaded = true; barMaxHeight = GetBarHeight(GetContainerTop(), 0); superQolUIPanel.SetActive(false); return true; } return false; } public static void InitializePerformancePanel(float[] values) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!IsPanelLoaded) { throw new InvalidOperationException("Performance UI Panel is not loaded."); } Transform containerTop = GetContainerTop(); for (int i = 0; i < containerTop.childCount; i++) { SetBarHeight(0f, containerTop, i); SetAvgTimeText("-", containerTop, i); SetFreqMultText("-", containerTop, i); } SetFreqStepValues(values); CanvasMethods.AttachPanelToCanvasWithAnchor(superQolUIPanel, ((Component)GameCanvas.Instance).transform); ((Transform)superQolUIPanel.GetComponent()).localScale = new Vector3(1.2f, 1.2f, 1.2f); } public static void DestroyPerformancePanel() { if (IsPanelLoaded) { HideUIPanel(); Object.Destroy((Object)(object)superQolUIPanel); IsPanelLoaded = false; } } public static void ShowUIPanel() { if (IsPanelLoaded && !superQolUIPanel.activeSelf) { superQolUIPanel.SetActive(true); } } public static void HideUIPanel() { if (IsPanelLoaded && superQolUIPanel.activeSelf) { superQolUIPanel.SetActive(false); } } public static void SetFreqStepValues(float[] values) { if (IsPanelLoaded) { Transform containerBottom = GetContainerBottom(); for (int i = 0; i < containerBottom.childCount; i++) { ((TMP_Text)((Component)containerBottom.GetChild(i).GetChild(2)).GetComponent()).text = values[i].ToString("F2"); } } } private static Transform GetContainerTop() { return superQolUIPanel.transform.GetChild(0).GetChild(0); } private static Transform GetContainerBottom() { return superQolUIPanel.transform.GetChild(0).GetChild(1); } private static Transform GetSubContainerTopElement(Transform containerTop, int index, int subIndex) { return containerTop.GetChild(index).GetChild(subIndex); } private static float GetBarHeight(Transform containerTop, int index) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) Rect rect = ((Component)GetSubContainerTopElement(containerTop, index, 0).GetChild(0)).GetComponent().rect; return ((Rect)(ref rect)).yMax; } private static void SetBarHeight(float height, Transform containerTop, int index) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) RectTransform component = ((Component)GetSubContainerTopElement(containerTop, index, 0).GetChild(0)).GetComponent(); component.sizeDelta = new Vector2(component.sizeDelta.x, height); } private static string GetAvgTimeText(Transform containerTop, int index) { return ((TMP_Text)((Component)GetSubContainerTopElement(containerTop, index, 1)).GetComponent()).text; } private static void SetAvgTimeText(string text, Transform containerTop, int index) { ((TMP_Text)((Component)GetSubContainerTopElement(containerTop, index, 1)).GetComponent()).text = text; } private static string GetFreqMultText(Transform containerTop, int index) { return ((TMP_Text)((Component)GetSubContainerTopElement(containerTop, index, 2)).GetComponent()).text; } private static void SetFreqMultText(string text, Transform containerTop, int index) { ((TMP_Text)((Component)GetSubContainerTopElement(containerTop, index, 2)).GetComponent()).text = text; } public static void AddNewHistoricValue(float avgTime, float freqMultiplier) { if (!IsPanelLoaded) { return; } Transform containerTop = GetContainerTop(); for (int i = 0; i < containerTop.childCount; i++) { float height; string text; string text2; if (i < containerTop.childCount - 1) { height = GetBarHeight(containerTop, i + 1); text = GetAvgTimeText(containerTop, i + 1); text2 = GetFreqMultText(containerTop, i + 1); } else { height = CalculateBarHeight(avgTime); text = FormatAvgTime(avgTime); text2 = FormatFreqMult(freqMultiplier); } SetBarHeight(height, containerTop, i); SetAvgTimeText(text, containerTop, i); SetFreqMultText(text2, containerTop, i); } } private static string FormatAvgTime(float avgTime) { return avgTime.ToString("F0"); } private static string FormatFreqMult(float freqMult) { return freqMult.ToString("F2") + "x"; } private static float CalculateBarHeight(float value) { return value * barMaxHeight / 1000f; } } } namespace SuperQoLity.SuperMarket.ModUtils.Messaging { public class GameNotifications { private enum NotificationType { Discard, Immediate, Queued } private readonly struct NotificationInfo { public string Message { get; } public LogTier LogLevel { get; } public bool IsInitialized { get; } public NotificationInfo(string message, LogTier logLevel) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Message = message; LogLevel = logLevel; IsInitialized = true; } } private static readonly Lazy instance = new Lazy(() => new GameNotifications()); private const byte MinSingleMessageLength = 6; private const byte MaxSingleMessageLength = 60; private readonly string[] separatorPriority = new string[4] { ":", ". ", " ", "." }; public const string NewLineNotifSeparator = "\u00b4^\u00a8"; public static readonly int MAX_MESSAGE_QUEUE = 5; private Queue notificationQueue; private readonly int notificationFrequencyMilli = 4250; private readonly int notifConsumerFrequency = 150; private readonly int minDelay = 900; private readonly int maxDelay = 3250; private bool notificationSystemEnabled; private CancellableSingleTask notificationTask; private object queueLock; public static GameNotifications Instance => instance.Value; public bool NotificationsActive { get; private set; } private GameNotifications() { notificationTask = new CancellableSingleTask(true); notificationSystemEnabled = false; queueLock = new object(); notificationQueue = new Queue(); } public void InitializeGameNotifications() { if (ModConfig.Instance.EnableModNotifications.Value) { AddNotificationSupport(); } WorldState.OnGameWorldChange += delegate(GameWorldEvent ev) { switch (ev) { case GameWorldEvent.WorldLoaded: if (Instance.notificationSystemEnabled) { TryEnableNotificationsInGame(); } break; case GameWorldEvent.QuitOrMenu: DisableShowingNotifications(); break; } }; ModConfig.Instance.EnableModNotifications.SettingChanged += NotificationsSettingsChanged; } public void NotificationsSettingsChanged(object sender, EventArgs e) { if (ModConfig.Instance.EnableModNotifications.Value) { Instance.AddNotificationSupport(); } else { Instance.RemoveNotificationSupport(); } } public bool AddNotificationSupport() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!notificationSystemEnabled) { TimeLogger.AddGameNotificationSupport(new NotificationAction(SendInGameNotification), "SuperQoLity"); } return notificationSystemEnabled = true; } public bool RemoveNotificationSupport() { if (notificationSystemEnabled) { TimeLogger.RemoveGameNotificationSupport(); } return notificationSystemEnabled = false; } public void TryEnableNotificationsInGame() { bool flag = false; try { if (TestNotificationObjects()) { flag = EnableShowingNotifications(); } } catch (Exception ex) { TimeLogger.Logger.LogExceptionWithMessage("Error while enabling game notifications.", ex, (LogCategories)1048576); } finally { if (!flag) { TimeLogger.RemoveGameNotificationSupport(); } } } public bool EnableShowingNotifications() { if (notificationSystemEnabled) { TaskExtensionMethods.FireAndForget(notificationTask.StartTaskAsync((Func)(() => NotificationConsumer()), "GameNotification Consumer", false), (LogCategories)1048576); NotificationsActive = true; return true; } TimeLogger.Logger.LogWarning("EnableShowingNotifications() was called but the notification system is not enabled. Notifications wont show.", (LogCategories)1048576); return false; } public void DisableShowingNotifications() { TaskExtensionMethods.FireAndForgetCancels(notificationTask.StopTaskAndWaitAsync(10000), (LogCategories)1048576, false); NotificationsActive = false; } public bool TestNotificationObjects() { bool flag = false; bool flag2 = false; try { if ((Object)(object)GameCanvas.Instance.importantNotificationPrefab != (Object)null && (Object)(object)GameCanvas.Instance.importantNotificationParentTransform != (Object)null) { flag = true; } else if ((Object)(object)GameCanvas.Instance.notificationPrefab != (Object)null && (Object)(object)GameCanvas.Instance.notificationParentTransform != (Object)null) { flag2 = true; } } catch (Exception ex) { TimeLogger.Logger.LogExceptionWithMessage("Exception while accessing the game notification objects.", ex, (LogCategories)1048576); } if (!flag && !flag2) { TimeLogger.Logger.LogError("The prefab and transform objects required for notifications cant be used. The mod notification system will be disabled.", (LogCategories)1048576); return notificationSystemEnabled = false; } return true; } private async Task NotificationConsumer() { while (!notificationTask.IsCancellationRequested) { NotificationInfo notifInfo = default(NotificationInfo); int num = notifConsumerFrequency; lock (queueLock) { Queue queue = notificationQueue; if (queue != null && queue.Count > 0) { notifInfo = notificationQueue.Dequeue(); } } if (!string.IsNullOrEmpty(notifInfo.Message)) { await ShowNotification(notifInfo); num = notificationFrequencyMilli; } await UniTask.Delay(num, false, (PlayerLoopTiming)8, notificationTask.CancellationToken, false); } } public void SendInGameNotification(string message, LogTier logLevel, bool skipQueue) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (message == null) { TimeLogger.Logger.LogError("The message string cannot be null.", (LogCategories)1048576); return; } switch (ProcessTypeNotification(skipQueue)) { case NotificationType.Queued: notificationQueue.Enqueue(new NotificationInfo(message, logLevel)); break; case NotificationType.Immediate: TaskExtensionMethods.FireAndForget(ShowNotification(new NotificationInfo(message, logLevel)), (LogCategories)1048576); break; } } private NotificationType ProcessTypeNotification(bool skipQueue) { bool flag = notificationQueue.Count >= MAX_MESSAGE_QUEUE; NotificationType notificationType; if (skipQueue || flag) { if (flag) { TimeLogger.Logger.LogInfo("GameNotification queue already has the max limit of " + $"{notificationQueue.Count} messages waiting. Showing without queuing.", (LogCategories)1048576); } notificationType = NotificationType.Immediate; } else { notificationType = NotificationType.Queued; } if (notificationType == NotificationType.Immediate && !WorldState.IsWorldLoaded) { TimeLogger.Logger.LogInfo("Notification was to be shown immediately, but world is not loaded. Discarded.", (LogCategories)1048576); notificationType = NotificationType.Discard; } return notificationType; } private async Task ShowNotification(NotificationInfo notifInfo) { if (IsMultipartMessage(notifInfo.Message)) { await ShowNotificationMultipartMessage(notifInfo); } else { ShowNotificationMessage(notifInfo); } } private bool IsMultipartMessage(string message) { if (message.Length <= 60 && !message.Contains("\n")) { return message.Contains("\u00b4^\u00a8"); } return true; } private async Task ShowNotificationMultipartMessage(NotificationInfo notifInfo) { List msgPartsList = SplitMessageParts(notifInfo.Message); for (int i = 0; i < msgPartsList.Count; i++) { string text = msgPartsList[i]; ShowNotificationMessage(msgPartsList[i], notifInfo.LogLevel); if (i == msgPartsList.Count - 1) { await UniTask.Delay(500, false, (PlayerLoopTiming)8, default(CancellationToken), false); break; } await UniTask.Delay((int)Mathf.Lerp((float)minDelay, (float)maxDelay, (float)text.Length / 60f), false, (PlayerLoopTiming)8, default(CancellationToken), false); } } private List SplitMessageParts(string message) { List msgPartsNewLineFull = new List(); List msgPartsComplete = new List(); List list = message.Split(new string[1] { "\u00b4^\u00a8" }, StringSplitOptions.None).ToList(); list.ForEach(delegate(string msgPart) { msgPartsNewLineFull.AddRange(msgPart.Split(new char[1] { '\n' })); }); list.ForEach(delegate(string msgPart) { msgPartsComplete.AddRange(GetExceededCharsMultipartMessage(msgPart.Trim())); }); return msgPartsComplete; } private List GetExceededCharsMultipartMessage(string message) { if (message.Length <= 60) { return new List(1) { message }; } List list = new List(); int num = 0; int num2 = message.Length; int indexSearchCount = 54; while (num2 > 60) { int lastIndexSearchBegin = num + 60; int num3 = FindSeparatorSplitPoint(message, lastIndexSearchBegin, indexSearchCount); int num4 = ((num3 == -1) ? 60 : (num3 - num)); list.Add(message.Substring(num, num4).Trim()); num += num4; num2 = message.Length - num - 1; } list.Add(message.Substring(num, num2 + 1).Trim()); return list; } private int FindSeparatorSplitPoint(string message, int lastIndexSearchBegin, int indexSearchCount) { int num = -1; string[] array = separatorPriority; foreach (string text in array) { num = message.LastIndexOf(text, lastIndexSearchBegin, indexSearchCount); if (num != -1) { num += text.Length; break; } } return num; } private void ShowNotificationMessage(NotificationInfo notifInfo) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) ShowNotificationMessage(notifInfo.Message, notifInfo.LogLevel); } private void ShowNotificationMessage(string message, LogTier logLevel) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GameObject obj = CreateNotificationObjetFromLogLevel(logLevel); ((TMP_Text)obj.GetComponent()).text = message; obj.SetActive(true); } private GameObject CreateNotificationObjetFromLogLevel(LogTier logLevel) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (IsImportantNotification(logLevel)) { return Object.Instantiate(GameCanvas.Instance.importantNotificationPrefab, GameCanvas.Instance.importantNotificationParentTransform); } return Object.Instantiate(GameCanvas.Instance.notificationPrefab, GameCanvas.Instance.notificationParentTransform); } private bool IsImportantNotification(LogTier logLevel) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)logLevel != 4 && (int)logLevel != 2 && (int)logLevel != 1) { return (int)logLevel == -1; } return true; } public static string RemoveSpecialNotifNewLinesForLog(string text, LogTier logLevel, LogCategories category, bool showInGameNotification, PreprocessType preprocType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)preprocType == 0 && showInGameNotification && text.Contains("\u00b4^\u00a8")) { text = text.Replace("\u00b4^\u00a8", ""); } return text; } } public class StartingMessage { public enum MessageType { Welcome, Help } private static float welcomeMessageChance; private static Random rndMsg; private static bool pendingPatchError; private static string[] superWelcomingMessages; private static string[] superUsefulHelpMessages; static StartingMessage() { welcomeMessageChance = 0.05f; superWelcomingMessages = new string[25] { "I dont think you are supposed to see this one.", "Here we are once again to make the customers pay.", "The ka-ching must go on.", "Dont forget to put your best customer service smile! \n:( \nNo, not like that.", "\"Please, remember to tie up your pets,\nand kids, outside the store. Thank you.\"", "^_^ $$$$$\n :-| $$$\n :-( $ \n T_T", "Customers cant hurt you.\nBut they want to.", "We cant process your request at this time. Queue time is:\n 1281 minutes.", "|~ #·?=@@)·\u00b4ç%... \n Fatal error while generating daily welcome quote. Please wait for a repair technician to fix it.", "Just... one more welcome message... only one more... \n this will be the last one... for sure...", "⚠\ud83d\udea8 AI DETECTED \ud83d\udea8⚠. Please solve this Captcha to continue: █████ [”REDACTED”] ██████████████████ \n █▚▌ ⬤ ▄█▀ ⬤ █▄ ▐▄█ ▀█▀ █ ⬤ █▚▌,\n █▚▌ ⬤ █▬█ ⬤ ▐◣ █☰ █████ ", "There is something wrong in this game. I cant put my finger on it, but sometimes \n I feel like the employees are watchi... \n Oh, hey! Hello player! Welcome to Supermarket Together!", "I need every single shelf space filled with potatoes. Right now. Come on, make it happen!", "No welcome message, is a a good welcome message. Too late.", "Im going to need another Ibuprofen. \"This is not an Ibuprophen endorsement. I am not affiliated with any companies that sell Ibuprophen. Please read the instruction manual carefully, \n and ask your doctor if Ibuprophen is right for you\"", "Straighten that shrimp-shaped back.", "A long time ago \n in a supermarket far, far away \n\n STORE\nWARS", "This is not the greatest welcome message. \nThis is just a tribute", "Look ma, look!\n I made a mod!", "I would be doing this for a living, \nbut living costs money", "\"This supermarket would look better with some more \nbrooms near the entrances\" - Said nobody ever", "The secret to earning more money is simple:", "Sorry, Im feeling lazy, so you get this message", "These thiefs dont know whats coming to them *cocks broom*", "If you wanted to see every welcome message,\nyou would need to load into the game an average of...\nuh, let me get the calculator one sec...\nyeah ok so basically\n\na lot" }; superUsefulHelpMessages = new string[18] { "Try burning some incense to ward off \n from evil spirits cursing the game.", "Maybe you should think about the life choices \n that brought you to this moment.", "From the dev => Must be someone else s fault. \n\n Not mine though.", "Entropy comes for us all.", "Dont despair. There are better mods out there than this.", "From the dev => If I knew this was going to happen, \n I would have done nothing to prevent it anyway.", "Keep restarting the game. Maybe on the 100th try it ll work.", "If you stare at this message for long enough, \n the problem will solve itself.", "From greener_capes => \"This developer sucks, \n why is he not fixing this already??!\"", "This might be a good moment to do your homework, \n or finish that task you have been ignoring for weeks.", "From anonymous1872 => \n \"This is ridiculous, these Pro Tips aint helpful at all!\"", "From the dev => Instead of adding features to the mod, \n I spent time doing these messages you might never see. \n\n Dont be like me.", "When boiling pasta, add a dash of salt \n and a bit of olive oil to the water.", "This is the golden Pro Tip that appears once every 10 years \n Share this Pro Tip to get 1000 years of terrible luck.", "Out of all the Pro Tips, this is the most useful.", "Please, contact your administrator to access this Pro Tip.", "From the dev => I could fix this... for a price. Unfortunately, even then I am too lazy.", "Every time you blame this mod, another Pro Tip gets added." }; rndMsg = new Random(); } public static void InitStartingMessages(bool allPatchsOK) { pendingPatchError = !allPatchsOK; WorldState.OnWorldLoaded += SendWelcomeOnWorldLoaded; } private static void SendWelcomeOnWorldLoaded() { MessageType messageType = MessageType.Welcome; if (pendingPatchError) { pendingPatchError = false; messageType = MessageType.Help; } SendWelcomeMessage(messageType); } private static void SendWelcomeMessage(MessageType messageType) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((messageType != 0 || !ModConfig.Instance.EnableWelcomeMessages.Value) && (messageType != MessageType.Help || !ModConfig.Instance.EnableErrorMessages.Value)) { return; } LogTier val = (LogTier)1; if (messageType == MessageType.Welcome) { val = (LogTier)8; if (welcomeMessageChance <= Random.Range(0f, 1f)) { return; } } string text = GetRandomMessage(messageType).Replace("\n", "\u00b4^\u00a8"); TimeLogger.Logger.Log(val, text, (LogCategories)8, true); } private static string GetRandomMessage(MessageType messageType) { return messageType switch { MessageType.Welcome => FormatMessageByType(superWelcomingMessages[rndMsg.Next(0, superWelcomingMessages.Length)], MessageType.Welcome), MessageType.Help => FormatMessageByType(superUsefulHelpMessages[rndMsg.Next(0, superUsefulHelpMessages.Length)], MessageType.Help), _ => throw new NotImplementedException($"The switch case {messageType} is not implemented."), }; } private static string FormatMessageByType(string message, MessageType messageType) { return messageType switch { MessageType.Welcome => "Supermarket tip of the day: \n\n" + message, MessageType.Help => "An error ocurred in 1 or more SuperQolity patches.\n You can contact me (Damntry) on Discord at the \n(unofficial) Supermarket Together server. \n\n\nRandom Error Pro Tip: \n\n" + message, _ => throw new NotImplementedException($"The switch case {messageType} is not implemented."), }; } } } namespace SuperQoLity.SuperMarket.ModUtils.ExternalMods { public class ModInfoBetterSMT : ModInfoData { public const string GUID = "BetterSMT"; public const string Name = "BetterSMT"; public const string PatchesNamespace = "BetterSMT.Patches"; public const string HarmonyId = "BetterSMT"; public ModInfoBetterSMT(ModInfoData modInfo) : base(modInfo) { } } public class BetterSMT_Helper : ExternalModHelper { private static BetterSMT_Helper instance; public static BetterSMT_Helper Instance { get { if (instance == null) { instance = new BetterSMT_Helper("BetterSMT", "BetterSMT", new Version("2.5.0")); } return instance; } } public ModInfoBetterSMT ModInfo { get; private set; } private BetterSMT_Helper(string GUID, string modName, Version supportedVersion) : base(GUID, modName, supportedVersion) { ModInfo = new ModInfoBetterSMT(((ExternalModHelper)this).ModInfo); } public void LogCurrentBetterSMTStatus(bool allPatchsOk) { //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) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected I4, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) ModLoadStatus modStatus = ((ExternalModHelper)this).ModStatus; switch ((int)modStatus) { case 1: if (!allPatchsOk) { TimeLogger.Logger.LogWarning(GetDifferentVersionLogMessage(), (LogCategories)8); } break; case 0: TimeLogger.Logger.LogDebug("Mod BetterSMT seems to be missing. Skipping its patches.", (LogCategories)8); break; case 2: TimeLogger.Logger.LogInfo("Mod BetterSMT exists. SuperQoLity patches will be applied to remove BetterSMT highlighting.", (LogCategories)8); break; default: throw new NotImplementedException($"This switch case {((ExternalModHelper)this).ModStatus} is not implemented."); } } private string GetDifferentVersionLogMessage() { string arg = ((((ModInfoData)ModInfo).LoadedVersion > ((ModInfoData)ModInfo).SupportedVersion) ? "higher" : "lower"); string text = string.Format("Mod {0} exists but its version ({1}) is ", "BetterSMT", ((ModInfoData)ModInfo).LoadedVersion) + $"{arg} than the supported version ({((ModInfoData)ModInfo).SupportedVersion}).\n"; if (((ModInfoData)ModInfo).LoadedVersion < ((ModInfoData)ModInfo).SupportedVersion) { text += "It is recommended to upgrade BetterSMT, at least to the supported version. Otherwise, this "; } else if (((ModInfoData)ModInfo).LoadedVersion > ((ModInfoData)ModInfo).SupportedVersion) { text += "This "; } return text + "could cause problems and bugs in-game. If you encounter any errors, you can disable these patches in the \"SuperQoLity\" -> \"" + ((ConfigEntryBase)ModConfig.Instance.EnablePatchHighlight).Definition.Section + "\" section of the config."; } public bool IsVersionWithHighlighting() { return ((ModInfoData)ModInfo).LoadedVersion < new Version("2.5.0"); } public bool IsFasterItemStockingEnabled() { bool flag = default(bool); return ((ExternalModHelper)this).GetConfigValue("Enables quick stocking", ref flag) && flag; } public bool IsFasterItemRemovingEnabled() { bool flag = default(bool); return ((ExternalModHelper)this).GetConfigValue("Enables quick removing", ref flag) && flag; } } public class ModInfoSMTAntiCheat : ModInfoData { public const string GUID = "ika.smtanticheat"; public const string Name = "Ika SMT Anti Cheat"; public ModInfoSMTAntiCheat(ModInfoData modInfo) : base(modInfo) { } } public class SMTAntiCheat_Helper : ExternalModHelper { private static SMTAntiCheat_Helper instance; public bool methodCallFailed; public static SMTAntiCheat_Helper Instance { get { if (instance == null) { instance = new SMTAntiCheat_Helper("ika.smtanticheat", "Ika SMT Anti Cheat", new Version("0.0.1")); } return instance; } } public ModInfoSMTAntiCheat ModInfo { get; private set; } private SMTAntiCheat_Helper(string GUID, string modName, Version supportedVersion) : base(GUID, modName, supportedVersion) { ModInfo = new ModInfoSMTAntiCheat(((ExternalModHelper)this).ModInfo); } public void CmdAlterFunds(float funds) { if (((ExternalModHelper)this).IsModLoadedAndEnabled && !methodCallFailed) { try { ReflectionHelper.CallMethod((object)GameData.Instance, "UserCode_CmdAlterFunds__Single", new object[1] { funds }); return; } catch (Exception ex) { methodCallFailed = true; TimeLogger.Logger.LogExceptionWithMessage("Error calling UserCode_CmdAlterFunds__Single directly. Reverting to networked version of the method.", ex, (LogCategories)8388608); } } GameData.Instance.CmdAlterFunds(funds); } } } namespace SuperQoLity.SuperMarket.Debug { public class SRPBatcherProfilerSQoL : MonoBehaviour { internal class RecorderEntry { public string name; public string oldName; public int callCount; public float accTime; public Recorder recorder; } private enum SRPBMarkers { kStdRenderDraw, kStdShadowDraw, kSRPBRenderDraw, kSRPBShadowDraw, kRenderThreadIdle, kStdRenderApplyShader, kStdShadowApplyShader, kSRPBRenderApplyShader, kSRPBShadowApplyShader, kPrepareBatchRendererGroupNodes } private enum OptimizationRenderMethod { None, SRPBatcher, GPUInstanced } public bool m_Enable = true; private const float kAverageStatDuration = 1f; private int m_frameCount; private float m_AccDeltaTime; private string m_statsLabel; private GUIStyle m_style; private RecorderEntry[] recordersList = new RecorderEntry[10] { new RecorderEntry { name = "RenderLoop.Draw" }, new RecorderEntry { name = "Shadows.Draw" }, new RecorderEntry { name = "SRPBatcher.Draw", oldName = "RenderLoopNewBatcher.Draw" }, new RecorderEntry { name = "SRPBatcherShadow.Draw", oldName = "ShadowLoopNewBatcher.Draw" }, new RecorderEntry { name = "RenderLoopDevice.Idle" }, new RecorderEntry { name = "StdRender.ApplyShader" }, new RecorderEntry { name = "StdShadow.ApplyShader" }, new RecorderEntry { name = "SRPBRender.ApplyShader" }, new RecorderEntry { name = "SRPBShadow.ApplyShader" }, new RecorderEntry { name = "PrepareBatchRendererGroupNodes" } }; private int optiRenderCount = Enum.GetValues(typeof(OptimizationRenderMethod)).Length; private bool firstPass = true; private OptimizationRenderMethod previousOptiRender; private OptimizationRenderMethod currentOptiRender; private void Awake() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < recordersList.Length; i++) { Sampler val = Sampler.Get(recordersList[i].name); if (val.isValid) { recordersList[i].recorder = val.GetRecorder(); } else if (recordersList[i].oldName != null) { val = Sampler.Get(recordersList[i].oldName); if (val.isValid) { recordersList[i].recorder = val.GetRecorder(); } } } m_style = new GUIStyle(); m_style.fontSize = 15; m_style.normal.textColor = Color.white; ResetStats(); } private void RazCounters() { m_AccDeltaTime = 0f; m_frameCount = 0; for (int i = 0; i < recordersList.Length; i++) { recordersList[i].accTime = 0f; recordersList[i].callCount = 0; } } private void ResetStats() { m_statsLabel = "Gathering data..."; RazCounters(); } private void ToggleStats() { m_Enable = !m_Enable; ResetStats(); } private void Update() { if (Input.GetKeyDown((KeyCode)290)) { previousOptiRender = currentOptiRender; currentOptiRender = (OptimizationRenderMethod)((int)(currentOptiRender + 1) % optiRenderCount); } if (currentOptiRender != previousOptiRender || firstPass) { GraphicsSettings.useScriptableRenderPipelineBatching = false; Object.FindAnyObjectByType().enableInstancing = false; switch (currentOptiRender) { case OptimizationRenderMethod.SRPBatcher: GraphicsSettings.useScriptableRenderPipelineBatching = true; break; case OptimizationRenderMethod.GPUInstanced: Object.FindAnyObjectByType().enableInstancing = true; break; } ResetStats(); previousOptiRender = currentOptiRender; firstPass = false; } if (Input.GetKeyDown((KeyCode)289)) { ToggleStats(); } if (!m_Enable) { return; } bool useScriptableRenderPipelineBatching = GraphicsSettings.useScriptableRenderPipelineBatching; m_AccDeltaTime += Time.unscaledDeltaTime; m_frameCount++; for (int i = 0; i < recordersList.Length; i++) { if (recordersList[i].recorder != null) { recordersList[i].accTime += (float)recordersList[i].recorder.elapsedNanoseconds / 1000000f; recordersList[i].callCount += recordersList[i].recorder.sampleBlockCount; } } if (m_AccDeltaTime >= 1f) { float num = 1f / (float)m_frameCount; float num2 = recordersList[0].accTime * num; float num3 = recordersList[1].accTime * num; float num4 = recordersList[2].accTime * num; float num5 = recordersList[3].accTime * num; float num6 = recordersList[4].accTime * num; float num7 = recordersList[9].accTime * num; m_statsLabel = $"Accumulated time for RenderLoop.Draw and ShadowLoop.Draw (all threads)\n{num2 + num3 + num4 + num5 + num7:F2}ms CPU Rendering time ( incl {num6:F2}ms RT idle )\n"; if (useScriptableRenderPipelineBatching) { m_statsLabel += $" {num4 + num5:F2}ms SRP Batcher code path\n"; m_statsLabel += $" {num4:F2}ms All objects ( {recordersList[7].callCount / m_frameCount} ApplyShader calls )\n"; m_statsLabel += $" {num5:F2}ms Shadows ( {recordersList[8].callCount / m_frameCount} ApplyShader calls )\n"; } m_statsLabel += $" {num2 + num3:F2}ms Standard code path\n"; m_statsLabel += $" {num2:F2}ms All objects ( {recordersList[5].callCount / m_frameCount} ApplyShader calls )\n"; m_statsLabel += $" {num3:F2}ms Shadows ( {recordersList[6].callCount / m_frameCount} ApplyShader calls )\n"; m_statsLabel += $" {num7:F2}ms PIR Prepare Group Nodes ( {recordersList[9].callCount / m_frameCount} calls )\n"; m_statsLabel += $"Global Main Loop: {m_AccDeltaTime * 1000f * num:F2}ms ({(int)((float)m_frameCount / m_AccDeltaTime)} FPS)\n"; RazCounters(); } } private void OnGUI() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) float num = 50f; if (m_Enable) { _ = GraphicsSettings.useScriptableRenderPipelineBatching; GUI.color = new Color(1f, 1f, 1f, 1f); float num2 = 700f; float num3 = 256f; num += num3 + 50f; GUILayout.BeginArea(new Rect(32f, 50f, num2, num3), $"{currentOptiRender} (F9)", GUI.skin.window); GUILayout.Label(m_statsLabel, m_style, Array.Empty()); GUILayout.EndArea(); } } } public static class TruckRoomFakeReveal { private static CancellableSingleTask coolTask; private static Vector3 originalTruckDoorPosition; public static int Delay; public static float DoorOpenDistance; public static float DoorCloseDistance; public static float MinDoorYPosition; public static int AfterResetWait; public static int LightsBeginWait; public static int CloseDoorWait; public static float TruckDoorForwardMove; static TruckRoomFakeReveal() { coolTask = new CancellableSingleTask(true); Delay = 15; DoorOpenDistance = 0.00225f; DoorCloseDistance = 0.05f; MinDoorYPosition = 0.01f; AfterResetWait = 500; LightsBeginWait = 1500; CloseDoorWait = 5500; TruckDoorForwardMove = -0.06f; InputManagerSMT.Instance.TryAddHotkey("StartTruckCrap", (KeyCode)103, (InputState)0, HotkeyActiveContext.WorldLoaded, async delegate { if (coolTask.IsTaskRunning) { await coolTask.StopTaskAndWaitAsync(100); } await coolTask.StartTaskAsync((Func)Start, "Stupidity", false); }); } public static async Task Start() { GameObject val = GameObject.Find("TESTORINO"); if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); GameObject.Find("Office_01a_2m_Wall_LOD0 (2)").transform.position = originalTruckDoorPosition; return; } Transform truckDoor = GameObject.Find("Office_01a_2m_Wall_LOD0 (2)").transform; originalTruckDoorPosition = truckDoor.position; Transform obj = Object.Instantiate(truckDoor); ((Object)((Component)obj).gameObject).name = "TESTORINO"; Material material = ((Renderer)((Component)obj).gameObject.GetComponent()).material; material.color = Color.black; material.mainTextureScale = Vector2.zero; truckDoor.position = new Vector3(truckDoor.position.x + TruckDoorForwardMove, truckDoor.position.y, truckDoor.position.z); IEnumerable enumerable = from g in GameObject.FindGameObjectsWithTag(Tags.Decoration) where ((Object)g).name == "212_OrientalLanternH(Clone)" || ((Object)g).name == "35_HangingLampG(Clone)" select g; CollectionExtensions.Do(enumerable, (Action)delegate(GameObject g) { ((Component)g.transform.Find("Mesh")).gameObject.SetActive(false); }); CollectionExtensions.Do(enumerable.Select((GameObject g) => g.transform.Find("Lights")), (Action)delegate(Transform t) { ((Component)t).gameObject.SetActive(false); }); await Task.Delay(AfterResetWait); Stopwatch sw = Stopwatch.StartNew(); while (!coolTask.IsCancellationRequested) { _ = sw.Elapsed.TotalMilliseconds; _ = (double)LightsBeginWait; if (sw.Elapsed.TotalMilliseconds < (double)CloseDoorWait) { truckDoor.position = new Vector3(truckDoor.position.x, truckDoor.position.y + DoorOpenDistance, truckDoor.position.z); } else { float num = Math.Max(truckDoor.position.y - DoorCloseDistance, MinDoorYPosition); truckDoor.position = new Vector3(truckDoor.position.x, num, truckDoor.position.z); if (truckDoor.position.y <= MinDoorYPosition) { break; } } await Task.Delay(Delay); } } } } namespace SuperQoLity.Properties { [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [DebuggerNonUserCode] [CompilerGenerated] internal class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] internal static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("SuperQoLity.Properties.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] internal static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } internal Resources() { } } [CompilerGenerated] [GeneratedCode("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")] internal sealed class Settings : ApplicationSettingsBase { private static Settings defaultInstance = (Settings)(object)SettingsBase.Synchronized((SettingsBase)(object)new Settings()); public static Settings Default => defaultInstance; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }