Decompiled source of OrderAndOrganize v0.5.0
plugins\OrderAndOrganize\OrderAndOrganize.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mirror; using OrderAndOrganize.Configuration; using OrderAndOrganize.Diagnostics; using OrderAndOrganize.Game; using OrderAndOrganize.Models; using OrderAndOrganize.Patches; using OrderAndOrganize.Services; using OrderAndOrganize.UI; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("OrderAndOrganize")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a0eb83a8da5c37e61bc0621f5b234821dacba945")] [assembly: AssemblyProduct("OrderAndOrganize")] [assembly: AssemblyTitle("OrderAndOrganize")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OrderAndOrganize { [BepInPlugin("com.ddqminik.supermarkettogether.orderandorganize", "Order & Organize", "0.5.0")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.ddqminik.supermarkettogether.orderandorganize"; public const string PluginName = "Order & Organize"; public const string PluginVersion = "0.5.0"; internal static ManualLogSource Log; internal static Plugin Instance; private ModConfiguration _config; private Harmony _harmony; private GameInventoryAdapter _inventoryAdapter; private GameProductCatalogAdapter _catalogAdapter; private GameShoppingListAdapter _shoppingListAdapter; private GamePurchaseAdapter _purchaseAdapter; private GameMoneyAdapter _moneyAdapter; private GameNotificationAdapter _notificationAdapter; private GameAuthorityAdapter _authorityAdapter; private GameUiAdapter _uiAdapter; private PendingOrderTracker _pendingTracker; private AutomationController _automationController; private OrderButtonController _buttonController; private GameApiDiagnostics _diagnostics; private ConfigWindow _configWindow; private CategoryMapper _categoryMapper; private CategoryShelfManager _categoryShelfManager; private CategoryPickerUI _categoryPickerUI; private bool _hasLoggedApiOnce; private float _storeLoadedTime; private const float DiagnosticsDelaySeconds = 5f; private bool _categoryMapperRebuilt; private float _lastStalePurgeTime; private float _sceneLoadedTime; private const float PurgeGracePeriodSeconds = 120f; private void Awake() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Order & Organize v0.5.0 loading..."); MigrateFromOldVersion(); _config = new ModConfiguration(); _config.Bind(((BaseUnityPlugin)this).Config); if (!_config.Enabled.Value) { Log.LogInfo((object)"Plugin is disabled via configuration."); return; } InitializeAdapters(); InitializeServices(); InitializeCategoryShelves(); CoroutineRunner.Initialize(); _harmony = new Harmony("com.ddqminik.supermarkettogether.orderandorganize"); _harmony.PatchAll(); SceneManager.sceneUnloaded += OnSceneUnloaded; Log.LogInfo((object)"Order & Organize v0.5.0 loaded successfully."); } private void InitializeAdapters() { _inventoryAdapter = new GameInventoryAdapter(Log); _catalogAdapter = new GameProductCatalogAdapter(Log); _shoppingListAdapter = new GameShoppingListAdapter(Log); _moneyAdapter = new GameMoneyAdapter(Log); _notificationAdapter = new GameNotificationAdapter(Log); _authorityAdapter = new GameAuthorityAdapter(Log); _uiAdapter = new GameUiAdapter(Log); _purchaseAdapter = new GamePurchaseAdapter(Log, _shoppingListAdapter, _moneyAdapter); } private void InitializeServices() { _pendingTracker = new PendingOrderTracker(Log); _automationController = new AutomationController(Log, _config, _authorityAdapter, _moneyAdapter, _purchaseAdapter, _catalogAdapter, _inventoryAdapter, _shoppingListAdapter, _notificationAdapter, _pendingTracker); _buttonController = new OrderButtonController(Log, _config, _catalogAdapter, _inventoryAdapter, _shoppingListAdapter, _notificationAdapter, _pendingTracker, () => _automationController.IsEnabled); _diagnostics = new GameApiDiagnostics(Log, _inventoryAdapter, _catalogAdapter, _shoppingListAdapter); _configWindow = new ConfigWindow(_config, () => _automationController.IsEnabled, delegate { _automationController.Toggle((MonoBehaviour)(object)this); _buttonController.UpdateAutoLabel(); }); } private void InitializeCategoryShelves() { _categoryMapper = new CategoryMapper(Log); string savePath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath), "OrderAndOrganize_CategoryShelves.json"); _categoryShelfManager = new CategoryShelfManager(Log, _categoryMapper, savePath); _categoryPickerUI = new CategoryPickerUI(Log, _categoryShelfManager, _categoryMapper); _categoryPickerUI.LabelsVisible = _config.CategoryLabelsVisible.Value; CategoryStoragePatches.ShelfManager = _categoryShelfManager; CategoryStoragePatches.CategoryMapper = _categoryMapper; CategoryStoragePatches.Enabled = _config.CategoryShelvesEnabled.Value; _config.CategoryShelvesEnabled.SettingChanged += delegate { CategoryStoragePatches.Enabled = _config.CategoryShelvesEnabled.Value; Log.LogInfo((object)("Category shelves " + (_config.CategoryShelvesEnabled.Value ? "enabled" : "disabled") + ".")); }; _config.CategoryLabelsVisible.SettingChanged += delegate { _categoryPickerUI.LabelsVisible = _config.CategoryLabelsVisible.Value; }; Log.LogInfo((object)"Category storage shelves initialized."); } private void Update() { //IL_003f: 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_00a7: 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) if (!_config.Enabled.Value) { return; } if (_categoryPickerUI != null && _categoryPickerUI.IsPickerVisible) { _categoryPickerUI.UpdateInput(); return; } if (Input.GetKeyDown(_config.ToggleHotkey.Value)) { _automationController.Toggle((MonoBehaviour)(object)this); _buttonController.UpdateAutoLabel(); } if (Input.GetKeyDown(_config.ConfigWindowHotkey.Value)) { _configWindow?.Toggle(); } if (_config.CategoryShelvesEnabled.Value && Input.GetKeyDown(_config.CategoryHotkey.Value)) { _categoryPickerUI?.OnHotkeyPressed(); } if (_config.CategoryShelvesEnabled.Value && Input.GetKeyDown(_config.CategoryLabelsToggleHotkey.Value) && _categoryPickerUI != null) { _categoryPickerUI.ToggleLabels(); _config.CategoryLabelsVisible.Value = _categoryPickerUI.LabelsVisible; } if (!_categoryMapperRebuilt && (Object)(object)ProductListing.Instance != (Object)null && ProductListing.Instance.tiers != null && ProductListing.Instance.tiers.Length != 0) { _categoryMapperRebuilt = true; _categoryMapper.Rebuild(); } if (_categoryShelfManager != null && _categoryShelfManager.AssignmentCount > 0 && (Object)(object)GameData.Instance != (Object)null && _sceneLoadedTime > 0f && Time.time - _sceneLoadedTime > 120f && Time.time - _lastStalePurgeTime > 60f) { _lastStalePurgeTime = Time.time; try { _categoryShelfManager.PurgeStaleAssignments(); } catch (Exception ex) { Log.LogWarning((object)("Stale purge failed: " + ex.Message)); } } HandleDiagnostics(); } private void HandleDiagnostics() { if (_hasLoggedApiOnce || !_authorityAdapter.IsStoreLoaded()) { return; } if (_storeLoadedTime <= 0f) { _storeLoadedTime = Time.time; _sceneLoadedTime = Time.time; } else if (!(Time.time - _storeLoadedTime < 5f)) { _hasLoggedApiOnce = true; try { _diagnostics.LogResolvedApi(); } catch (Exception ex) { Log.LogWarning((object)("API diagnostics failed: " + ex.Message)); } } } private void OnGUI() { _configWindow?.Draw(); if (_config.CategoryShelvesEnabled.Value) { _categoryPickerUI?.Draw(); } } private void OnSceneUnloaded(Scene scene) { Log.LogInfo((object)("Scene unloaded: " + ((Scene)(ref scene)).name)); _automationController.OnSceneUnload(); _hasLoggedApiOnce = false; _storeLoadedTime = 0f; _sceneLoadedTime = 0f; _lastStalePurgeTime = 0f; _categoryMapperRebuilt = false; } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } SceneManager.sceneUnloaded -= OnSceneUnloaded; _pendingTracker?.ClearAll(); Log.LogInfo((object)"Order & Organize unloaded."); } private void MigrateFromOldVersion() { try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath); if (!string.IsNullOrEmpty(directoryName)) { string text = Path.Combine(directoryName, "com.dominik.supermarkettogether.smartrestock.cfg"); string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; if (File.Exists(text) && !File.Exists(configFilePath)) { File.Copy(text, configFilePath); Log.LogInfo((object)("Migrated config from " + Path.GetFileName(text))); } string text2 = Path.Combine(directoryName, "SmartRestock_CategoryShelves.json"); string text3 = Path.Combine(directoryName, "OrderAndOrganize_CategoryShelves.json"); if (File.Exists(text2) && !File.Exists(text3)) { File.Copy(text2, text3); Log.LogInfo((object)("Migrated category data from " + Path.GetFileName(text2))); } string text4 = text2 + ".backup"; string text5 = text3 + ".backup"; if (File.Exists(text4) && !File.Exists(text5)) { File.Copy(text4, text5); } } } catch (Exception ex) { Log.LogWarning((object)("Migration from old version failed: " + ex.Message)); } } internal void OnOrderingUIInitialized() { _buttonController?.TryCreateButton(); } internal void OnAutoStartup() { if (_config.AutoOrderAtStartup.Value) { _automationController.SetEnabled(enabled: true, (MonoBehaviour)(object)this); Log.LogInfo((object)"Automation auto-started per configuration."); } } } [HarmonyPatch] internal static class GamePatches { [HarmonyPatch(typeof(ProductListing), "OnStartClient")] [HarmonyPostfix] private static void OnProductListingStartClient() { try { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)"ProductListing.OnStartClient fired - initializing Order & Organize UI."); } Plugin.Instance?.OnOrderingUIInitialized(); Plugin.Instance?.OnAutoStartup(); } catch (Exception arg) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)$"Error in OnStartClient patch: {arg}"); } } } [HarmonyPatch(typeof(ManagerBlackboard), "UpdateUnlockedFranchises")] [HarmonyPostfix] private static void OnUpdateUnlockedFranchises() { try { Plugin.Instance?.OnOrderingUIInitialized(); } catch (Exception arg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)$"Error in UpdateUnlockedFranchises patch: {arg}"); } } } [HarmonyPatch(typeof(LocalizationManager), "GetLocalizationString")] [HarmonyPrefix] private static bool OnGetLocalizationString(ref string key, ref string __result) { if (key != null && key.Length > 0 && key[0] == '`') { __result = key.Substring(1); return false; } return true; } } } namespace OrderAndOrganize.UI { public class CategoryPickerUI { private readonly ManualLogSource _log; private readonly CategoryShelfManager _shelfManager; private readonly CategoryMapper _categoryMapper; private bool _pickerVisible; private Data_Container _targetContainer; private List<KeyValuePair<int, string>> _sortedGroups; private int _selectedIndex; private CursorLockMode _savedLockState; private bool _savedCursorVisible; private MonoBehaviour _frozenController; private static Type _fpcType; private static bool _fpcTypeResolved; private static MonoBehaviour _cachedFpc; private bool _labelsVisible = true; private bool _skipNextFrame; private GUIStyle _panelBgStyle; private GUIStyle _titleStyle; private GUIStyle _itemStyle; private GUIStyle _selectedItemStyle; private GUIStyle _footerStyle; private bool _stylesInitialized; private const float PanelWidth = 320f; private const float PanelHeight = 360f; private const float ItemHeight = 30f; private const int VisibleItemCount = 7; private const float LabelMaxDistance = 20f; private static Dictionary<Color, Texture2D> _texCache = new Dictionary<Color, Texture2D>(); public bool IsPickerVisible => _pickerVisible; public bool LabelsVisible { get { return _labelsVisible; } set { _labelsVisible = value; } } public CategoryPickerUI(ManualLogSource log, CategoryShelfManager shelfManager, CategoryMapper categoryMapper) { _log = log; _shelfManager = shelfManager; _categoryMapper = categoryMapper; } public void UpdateInput() { if (!_pickerVisible) { return; } if (_skipNextFrame) { _skipNextFrame = false; Input.ResetInputAxes(); return; } if (Input.GetKeyDown((KeyCode)103)) { ClosePicker(apply: false); Input.ResetInputAxes(); return; } if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271)) { ClosePicker(apply: true); Input.ResetInputAxes(); return; } if (Input.GetKeyDown((KeyCode)8) || Input.GetKeyDown((KeyCode)127)) { ClearAndClose(); Input.ResetInputAxes(); return; } if (_sortedGroups != null) { float axis = Input.GetAxis("Mouse ScrollWheel"); if (axis > 0.01f) { _selectedIndex = (_selectedIndex - 1 + _sortedGroups.Count) % _sortedGroups.Count; } else if (axis < -0.01f) { _selectedIndex = (_selectedIndex + 1) % _sortedGroups.Count; } if (Input.GetKeyDown((KeyCode)273)) { _selectedIndex = (_selectedIndex - 1 + _sortedGroups.Count) % _sortedGroups.Count; } if (Input.GetKeyDown((KeyCode)274)) { _selectedIndex = (_selectedIndex + 1) % _sortedGroups.Count; } } Input.ResetInputAxes(); } public void OnHotkeyPressed() { if (_pickerVisible) { ClosePicker(apply: false); return; } Data_Container val = RaycastForStorageShelf(); if ((Object)(object)val == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)"CategoryPicker: No storage shelf found in crosshair."); } } else { OpenPicker(val); } } public void ToggleLabels() { _labelsVisible = !_labelsVisible; try { string text = (_labelsVisible ? "ON" : "OFF"); GameCanvas instance = GameCanvas.Instance; if (instance != null) { instance.CreateCanvasNotification("`Category labels: " + text); } } catch { } } private void OpenPicker(Data_Container container) { //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_010f: Unknown result type (might be due to invalid IL or missing references) _targetContainer = container; _sortedGroups = new List<KeyValuePair<int, string>>(_categoryMapper.GetAllGroups()); _sortedGroups.Sort((KeyValuePair<int, string> a, KeyValuePair<int, string> b) => a.Key.CompareTo(b.Key)); if (_sortedGroups.Count == 0) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"CategoryPicker: No category groups available."); } return; } int? category = _shelfManager.GetCategory(container); _selectedIndex = 0; if (category.HasValue) { for (int num = 0; num < _sortedGroups.Count; num++) { if (_sortedGroups[num].Key == category.Value) { _selectedIndex = num; break; } } } _pickerVisible = true; _skipNextFrame = true; _savedLockState = Cursor.lockState; _savedCursorVisible = Cursor.visible; Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; FreezePlayerController(); ManualLogSource log2 = _log; if (log2 != null) { log2.LogDebug((object)$"CategoryPicker: Opened for shelf at {((Component)container).transform.position}"); } } private void ClosePicker(bool apply) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (apply && (Object)(object)_targetContainer != (Object)null && _sortedGroups != null && _selectedIndex >= 0 && _selectedIndex < _sortedGroups.Count) { KeyValuePair<int, string> keyValuePair = _sortedGroups[_selectedIndex]; _shelfManager.SetCategory(_targetContainer, keyValuePair.Key); try { GameCanvas instance = GameCanvas.Instance; if (instance != null) { instance.CreateCanvasNotification("`Shelf tagged: " + keyValuePair.Value); } } catch { } } _pickerVisible = false; _targetContainer = null; _sortedGroups = null; UnfreezePlayerController(); Cursor.lockState = _savedLockState; Cursor.visible = _savedCursorVisible; } private void ClearAndClose() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_targetContainer != (Object)null) { _shelfManager.ClearCategory(_targetContainer); try { GameCanvas instance = GameCanvas.Instance; if (instance != null) { instance.CreateCanvasNotification("`Shelf category cleared"); } } catch { } } _pickerVisible = false; _targetContainer = null; _sortedGroups = null; UnfreezePlayerController(); Cursor.lockState = _savedLockState; Cursor.visible = _savedCursorVisible; } public void Draw() { InitStyles(); if (_labelsVisible) { DrawFloatingLabels(); } if (_pickerVisible && _sortedGroups != null && _sortedGroups.Count != 0) { DrawPickerOverlay(); } } private void DrawPickerOverlay() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_00d1: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0209: Unknown result type (might be due to invalid IL or missing references) float num = ((float)Screen.width - 320f) / 2f; float num2 = ((float)Screen.height - 360f) / 2f; GUI.Box(new Rect(num, num2, 320f, 360f), "", _panelBgStyle); GUILayout.BeginArea(new Rect(num + 12f, num2 + 10f, 296f, 340f)); GUILayout.Label("Assign Category", _titleStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); int? category = _shelfManager.GetCategory(_targetContainer); string text = (category.HasValue ? _categoryMapper.GetGroupName(category.Value) : "None"); GUIStyle val = new GUIStyle(_footerStyle) { alignment = (TextAnchor)4 }; val.normal.textColor = (Color)(category.HasValue ? _categoryMapper.GetGroupColor(category.Value) : new Color(0.6f, 0.6f, 0.6f)); GUILayout.Label("Current: " + text, val, Array.Empty<GUILayoutOption>()); GUILayout.Space(6f); DrawSeparator(296f); GUILayout.Space(6f); int num3 = 3; int num4 = _selectedIndex - num3; for (int i = 0; i < 7; i++) { int num5 = num4 + i; num5 = (num5 % _sortedGroups.Count + _sortedGroups.Count) % _sortedGroups.Count; KeyValuePair<int, string> keyValuePair = _sortedGroups[num5]; bool num6 = num5 == _selectedIndex; Color val2 = EnsureReadable(_categoryMapper.GetGroupColor(keyValuePair.Key)); if (num6) { Rect rect = GUILayoutUtility.GetRect(296f, 30f); Color col = val2 * 0.4f; col.a = 0.9f; GUI.DrawTexture(rect, (Texture)(object)MakeTex(1, 1, col)); GUIStyle val3 = new GUIStyle(_selectedItemStyle); val3.normal.textColor = Color.white; GUI.Label(rect, " > " + keyValuePair.Value, val3); } else { Rect rect2 = GUILayoutUtility.GetRect(296f, 30f); float num7 = Mathf.Abs(i - num3); float a = Mathf.Lerp(1f, 0.45f, num7 / ((float)num3 + 1f)); GUIStyle val4 = new GUIStyle(_itemStyle); Color textColor = val2; textColor.a = a; val4.normal.textColor = textColor; GUI.Label(rect2, " " + keyValuePair.Value, val4); } } GUILayout.Space(6f); DrawSeparator(296f); GUILayout.Space(8f); GUILayout.Label("[Scroll/Arrows] Browse [Enter] Apply", _footerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label("[G] Cancel [Backspace] Clear", _footerStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndArea(); } private void DrawFloatingLabels() { //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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_0069: 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_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) //IL_007f: 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_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_008b: 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_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_010b: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } IReadOnlyDictionary<string, int> allAssignments = _shelfManager.GetAllAssignments(); if (allAssignments.Count == 0) { return; } Vector3 position = ((Component)main).transform.position; foreach (KeyValuePair<string, int> item in allAssignments) { Vector3 val = CategoryShelfManager.ParsePositionKey(item.Key); float num = Vector3.Distance(position, val); if (!(num > 20f)) { Vector3 val2 = val + Vector3.up * 2.2f; Vector3 val3 = main.WorldToScreenPoint(val2); if (!(val3.z <= 0f)) { float num2 = (float)Screen.height - val3.y; string groupName = _categoryMapper.GetGroupName(item.Value); Color groupColor = _categoryMapper.GetGroupColor(item.Value); float num3 = Mathf.Clamp01(1f - num / 20f); int fontSize = Mathf.RoundToInt(Mathf.Lerp(10f, 16f, num3)); GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = fontSize, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; groupColor.a = 0.7f + 0.3f * num3; val4.normal.textColor = groupColor; Vector2 val5 = val4.CalcSize(new GUIContent(groupName)); Rect val6 = new Rect(val3.x - val5.x / 2f, num2 - val5.y / 2f, val5.x + 8f, val5.y + 2f); GUI.DrawTexture(val6, (Texture)(object)MakeTex(1, 1, new Color(0f, 0f, 0f, 0.4f * num3))); GUI.Label(val6, groupName, val4); } } } } private Data_Container RaycastForStorageShelf() { //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) Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return null; } RaycastHit val = default(RaycastHit); if (!Physics.Raycast(main.ScreenPointToRay(new Vector3((float)Screen.width / 2f, (float)Screen.height / 2f, 0f)), ref val, 8f)) { return null; } Transform val2 = ((RaycastHit)(ref val)).transform; int num = 6; while ((Object)(object)val2 != (Object)null && num-- > 0) { Data_Container component = ((Component)val2).GetComponent<Data_Container>(); if ((Object)(object)component != (Object)null) { if (component.containerClass == 69) { return component; } ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"CategoryPicker: Found Data_Container but containerClass={component.containerClass} (not storage)"); } return null; } InteractableContainer component2 = ((Component)val2).GetComponent<InteractableContainer>(); if ((Object)(object)component2 != (Object)null && component2.isStorageShelf) { Transform parent = val2.parent; object obj; if (parent == null) { obj = null; } else { Transform parent2 = parent.parent; obj = ((parent2 != null) ? ((Component)parent2).GetComponent<Data_Container>() : null); } Data_Container val3 = (Data_Container)obj; if ((Object)(object)val3 != (Object)null && val3.containerClass == 69) { return val3; } } val2 = val2.parent; } return null; } private void FreezePlayerController() { try { MonoBehaviour val = FindFirstPersonController(); if ((Object)(object)val != (Object)null && ((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; _frozenController = val; ManualLogSource log = _log; if (log != null) { log.LogDebug((object)"CategoryPicker: Disabled FirstPersonController."); } } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("CategoryPicker: Failed to freeze player controller: " + ex.Message)); } } } private void UnfreezePlayerController() { try { if ((Object)(object)_frozenController != (Object)null) { ((Behaviour)_frozenController).enabled = true; _frozenController = null; ManualLogSource log = _log; if (log != null) { log.LogDebug((object)"CategoryPicker: Re-enabled FirstPersonController."); } } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("CategoryPicker: Failed to unfreeze player controller: " + ex.Message)); } } } internal static MonoBehaviour FindFirstPersonController() { if ((Object)(object)_cachedFpc != (Object)null) { return _cachedFpc; } if (!_fpcTypeResolved) { _fpcTypeResolved = true; _fpcType = AccessTools.TypeByName("StarterAssets.FirstPersonController") ?? AccessTools.TypeByName("FirstPersonController"); } if (_fpcType == null) { return null; } Object obj = Object.FindFirstObjectByType(_fpcType); _cachedFpc = (MonoBehaviour)(object)((obj is MonoBehaviour) ? obj : null); return _cachedFpc; } private void InitStyles() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0046: 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_0065: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_009a: 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_00b4: 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_00c8: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_00f3: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) if (!_stylesInitialized) { _stylesInitialized = true; _panelBgStyle = new GUIStyle(GUI.skin.box); _panelBgStyle.normal.background = MakeTex(2, 2, new Color(0.08f, 0.08f, 0.12f, 0.95f)); _titleStyle = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; _titleStyle.normal.textColor = new Color(0.92f, 0.92f, 0.92f); _itemStyle = new GUIStyle(GUI.skin.label) { fontSize = 14, alignment = (TextAnchor)3 }; _selectedItemStyle = new GUIStyle(GUI.skin.label) { fontSize = 15, fontStyle = (FontStyle)1, alignment = (TextAnchor)3 }; _footerStyle = new GUIStyle(GUI.skin.label) { fontSize = 11, alignment = (TextAnchor)4 }; _footerStyle.normal.textColor = new Color(0.55f, 0.55f, 0.55f); } } private void DrawSeparator(float width) { //IL_0006: 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) GUI.DrawTexture(GUILayoutUtility.GetRect(width, 1f), (Texture)(object)MakeTex(1, 1, new Color(0.4f, 0.4f, 0.4f, 0.6f))); } private static Color EnsureReadable(Color c) { //IL_0005: 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_001e: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) float num = 0.299f * c.r + 0.587f * c.g + 0.114f * c.b; if (num < 0.35f) { float num2 = 0.35f / Mathf.Max(num, 0.01f); c.r = Mathf.Clamp01(c.r * num2); c.g = Mathf.Clamp01(c.g * num2); c.b = Mathf.Clamp01(c.b * num2); } return c; } private static Texture2D MakeTex(int width, int height, Color col) { //IL_0005: 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_002a: 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_0041: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) if (_texCache.TryGetValue(col, out var value) && (Object)(object)value != (Object)null) { return value; } Color[] array = (Color[])(object)new Color[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = col; } Texture2D val = new Texture2D(width, height); val.SetPixels(array); val.Apply(); _texCache[col] = val; return val; } } public class ConfigWindow { private readonly ModConfiguration _config; private readonly Func<bool> _getAutoEnabled; private readonly Action _toggleAuto; private bool _visible; private Rect _windowRect = new Rect(20f, 20f, 420f, 620f); private int _windowId; private int _thresholdInput; private float _cashReserveInput; private int _scanIntervalInput; private int _pendingTimeoutInput; private string _buttonTextInput; private Vector2 _scrollPos; private GUIStyle _headerStyle; private GUIStyle _sectionStyle; private GUIStyle _labelStyle; private GUIStyle _valueStyle; private GUIStyle _toggleStyle; private GUIStyle _windowStyle; private bool _stylesInitialized; private static Texture2D _lineTex; public bool IsVisible => _visible; public ConfigWindow(ModConfiguration config, Func<bool> getAutoEnabled, Action toggleAuto) { //IL_0015: 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) _config = config; _getAutoEnabled = getAutoEnabled; _toggleAuto = toggleAuto; _windowId = "OAOConfig".GetHashCode(); SyncFromConfig(); } public void Toggle() { _visible = !_visible; if (_visible) { SyncFromConfig(); } } private void SyncFromConfig() { _thresholdInput = _config.ThresholdUnits.Value; _cashReserveInput = _config.CashReserve.Value; _scanIntervalInput = _config.ScanIntervalSeconds.Value; _pendingTimeoutInput = _config.PendingOrderTimeoutSeconds.Value; _buttonTextInput = _config.ButtonText.Value; } public void Draw() { //IL_0017: 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_0038: Expected O, but got Unknown //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) if (_visible) { InitStyles(); _windowRect = GUI.Window(_windowId, _windowRect, new WindowFunction(DrawWindowContents), "", _windowStyle); } } private void InitStyles() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0046: 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: Expected O, but got Unknown //IL_0096: 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_00a3: 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_00b6: Expected O, but got Unknown //IL_00d0: 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_00ea: 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_00fe: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_012d: 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_013f: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) if (!_stylesInitialized) { _stylesInitialized = true; _windowStyle = new GUIStyle(GUI.skin.window); _windowStyle.normal.background = MakeTex(2, 2, new Color(0.1f, 0.1f, 0.12f, 0.95f)); _windowStyle.onNormal.background = _windowStyle.normal.background; _windowStyle.padding = new RectOffset(12, 12, 8, 8); _headerStyle = new GUIStyle(GUI.skin.label) { fontSize = 18, fontStyle = (FontStyle)1, alignment = (TextAnchor)4 }; _headerStyle.normal.textColor = new Color(0.9f, 0.9f, 0.9f); _sectionStyle = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1 }; _sectionStyle.normal.textColor = new Color(0.7f, 0.85f, 1f); _labelStyle = new GUIStyle(GUI.skin.label) { fontSize = 13 }; _labelStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f); _valueStyle = new GUIStyle(GUI.skin.label) { fontSize = 13, fontStyle = (FontStyle)1, alignment = (TextAnchor)5 }; _valueStyle.normal.textColor = Color.white; _toggleStyle = new GUIStyle(GUI.skin.toggle) { fontSize = 13 }; _toggleStyle.normal.textColor = new Color(0.85f, 0.85f, 0.85f); _toggleStyle.onNormal.textColor = Color.white; } } private void DrawWindowContents(int id) { //IL_003d: 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_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_0687: Expected O, but got Unknown //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: Unknown result type (might be due to invalid IL or missing references) //IL_07e0: Unknown result type (might be due to invalid IL or missing references) //IL_07e5: Unknown result type (might be due to invalid IL or missing references) //IL_08a2: Unknown result type (might be due to invalid IL or missing references) //IL_08a7: Unknown result type (might be due to invalid IL or missing references) GUILayout.Space(4f); GUILayout.Label("Order & Organize Settings", _headerStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); float num = ((Rect)(ref _windowRect)).height - 70f; _scrollPos = GUILayout.BeginScrollView(_scrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num) }); DrawLine(); GUILayout.Space(4f); GUILayout.Label("General", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); bool flag = GUILayout.Toggle(_config.Enabled.Value, " Mod Enabled", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag != _config.Enabled.Value) { _config.Enabled.Value = flag; } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Threshold:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label(_thresholdInput.ToString(), _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUILayout.EndHorizontal(); float num2 = GUILayout.HorizontalSlider((float)_thresholdInput, 0f, 500f, Array.Empty<GUILayoutOption>()); _thresholdInput = Mathf.RoundToInt(num2); if (_thresholdInput != _config.ThresholdUnits.Value) { _config.ThresholdUnits.Value = _thresholdInput; } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Button Text:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); _buttonTextInput = GUILayout.TextField(_buttonTextInput, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) }); GUILayout.EndHorizontal(); if (_buttonTextInput != _config.ButtonText.Value) { _config.ButtonText.Value = _buttonTextInput; } GUILayout.Space(2f); bool flag2 = GUILayout.Toggle(_config.ShowNotifications.Value, " Show Notifications", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag2 != _config.ShowNotifications.Value) { _config.ShowNotifications.Value = flag2; } bool flag3 = GUILayout.Toggle(_config.VerboseLogging.Value, " Verbose Logging", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag3 != _config.VerboseLogging.Value) { _config.VerboseLogging.Value = flag3; } GUILayout.Space(8f); DrawLine(); GUILayout.Space(4f); GUILayout.Label("Automation", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); bool flag4 = GUILayout.Toggle(_config.AutoOrderAtStartup.Value, " Auto Order at Startup", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag4 != _config.AutoOrderAtStartup.Value) { _config.AutoOrderAtStartup.Value = flag4; } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Toggle Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label(((object)_config.ToggleHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Scan Interval:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label($"{_scanIntervalInput}s", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUILayout.EndHorizontal(); float num3 = GUILayout.HorizontalSlider((float)_scanIntervalInput, 2f, 300f, Array.Empty<GUILayoutOption>()); _scanIntervalInput = Mathf.RoundToInt(num3); if (_scanIntervalInput != _config.ScanIntervalSeconds.Value) { _config.ScanIntervalSeconds.Value = _scanIntervalInput; } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Cash Reserve:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label($"${_cashReserveInput:F0}", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }); GUILayout.EndHorizontal(); float num4 = GUILayout.HorizontalSlider(_cashReserveInput, 0f, 100000f, Array.Empty<GUILayoutOption>()); _cashReserveInput = Mathf.Round(num4 / 100f) * 100f; if (Mathf.Abs(_cashReserveInput - _config.CashReserve.Value) > 1f) { _config.CashReserve.Value = _cashReserveInput; } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Pending Timeout:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label($"{_pendingTimeoutInput}s", _valueStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }); GUILayout.EndHorizontal(); float num5 = GUILayout.HorizontalSlider((float)_pendingTimeoutInput, 10f, 600f, Array.Empty<GUILayoutOption>()); _pendingTimeoutInput = Mathf.RoundToInt(num5); if (_pendingTimeoutInput != _config.PendingOrderTimeoutSeconds.Value) { _config.PendingOrderTimeoutSeconds.Value = _pendingTimeoutInput; } GUILayout.Space(8f); DrawLine(); GUILayout.Space(4f); bool flag5 = _getAutoEnabled?.Invoke() ?? false; GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Auto Order:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUIStyle val = new GUIStyle(_valueStyle); val.normal.textColor = (Color)(flag5 ? Color.green : new Color(1f, 0.4f, 0.4f)); GUILayout.Label(flag5 ? "ACTIVE" : "OFF", val, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.Space(4f); if (GUILayout.Button(flag5 ? "Disable Auto Order" : "Enable Auto Order", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { _toggleAuto?.Invoke(); } GUILayout.Space(8f); DrawLine(); GUILayout.Space(4f); GUILayout.Label("Category Shelves", _sectionStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); bool flag6 = GUILayout.Toggle(_config.CategoryShelvesEnabled.Value, " Category Shelves Enabled", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag6 != _config.CategoryShelvesEnabled.Value) { _config.CategoryShelvesEnabled.Value = flag6; } GUILayout.Space(2f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Category Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label(((object)_config.CategoryHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.Space(2f); bool flag7 = GUILayout.Toggle(_config.CategoryLabelsVisible.Value, " Show Floating Labels", _toggleStyle, Array.Empty<GUILayoutOption>()); if (flag7 != _config.CategoryLabelsVisible.Value) { _config.CategoryLabelsVisible.Value = flag7; } GUILayout.Space(2f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Labels Hotkey:", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }); GUILayout.Label(((object)_config.CategoryLabelsToggleHotkey.Value/*cast due to .constrained prefix*/).ToString(), _valueStyle, Array.Empty<GUILayoutOption>()); GUILayout.EndHorizontal(); GUILayout.Space(4f); GUILayout.EndScrollView(); GUILayout.Space(4f); if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(25f) })) { _visible = false; } GUI.DragWindow(); } private void DrawLine() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(GUILayoutUtility.GetRect(1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }), (Texture)(object)MakeLineTex(), (ScaleMode)0); } private static Texture2D MakeLineTex() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_lineTex == (Object)null) { _lineTex = MakeTex(1, 1, new Color(0.4f, 0.4f, 0.4f, 0.8f)); } return _lineTex; } private static Texture2D MakeTex(int width, int height, Color col) { //IL_000f: 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_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) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown Color[] array = (Color[])(object)new Color[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = col; } Texture2D val = new Texture2D(width, height); val.SetPixels(array); val.Apply(); return val; } } public class OrderButtonController { private const string ButtonObjectName = "OAO_AddLowStockButton"; private const string AutoLabelObjectName = "OAO_AutoLabel"; private readonly ManualLogSource _log; private readonly ModConfiguration _config; private readonly GameProductCatalogAdapter _catalog; private readonly GameInventoryAdapter _inventory; private readonly GameShoppingListAdapter _shoppingList; private readonly GameNotificationAdapter _notification; private readonly PendingOrderTracker _pendingTracker; private readonly Func<bool> _isAutoEnabled; private GameObject _buttonObj; private GameObject _autoLabelObj; private bool _isRunning; private bool _hasLoggedHierarchy; public OrderButtonController(ManualLogSource log, ModConfiguration config, GameProductCatalogAdapter catalog, GameInventoryAdapter inventory, GameShoppingListAdapter shoppingList, GameNotificationAdapter notification, PendingOrderTracker pendingTracker, Func<bool> isAutoEnabled) { _log = log; _config = config; _catalog = catalog; _inventory = inventory; _shoppingList = shoppingList; _notification = notification; _pendingTracker = pendingTracker; _isAutoEnabled = isAutoEnabled; } public void TryCreateButton() { try { ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard(); if ((Object)(object)managerBlackboard == (Object)null) { return; } if (!_hasLoggedHierarchy) { _hasLoggedHierarchy = true; LogUiHierarchy(managerBlackboard); } Transform val = FindButtonParent(managerBlackboard); if ((Object)(object)val == (Object)null) { _log.LogWarning((object)"Could not find a suitable parent for button placement."); return; } if ((Object)(object)val.Find("OAO_AddLowStockButton") != (Object)null) { _log.LogDebug((object)"Button already exists; skipping creation."); UpdateAutoLabel(); return; } CreateButtonByCloning(managerBlackboard, val); if ((Object)(object)_buttonObj == (Object)null) { CreateButtonFallback(val); } CreateAutoLabel(val); _log.LogInfo((object)("Order & Organize button created. Parent: " + ((Object)val).name)); } catch (Exception arg) { _log.LogError((object)$"Failed to create button: {arg}"); } } private Transform FindButtonParent(ManagerBlackboard blackboard) { if ((Object)(object)blackboard.shoppingListParent != (Object)null) { Transform parent = blackboard.shoppingListParent.transform.parent; if ((Object)(object)parent != (Object)null) { _log.LogDebug((object)("Using shopping list grandparent: " + ((Object)parent).name)); return parent; } } if ((Object)(object)blackboard.tabsOBJ != (Object)null) { return blackboard.tabsOBJ.transform.parent ?? blackboard.tabsOBJ.transform; } return ((Component)blackboard).transform; } private void CreateButtonByCloning(ManagerBlackboard blackboard, Transform parent) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindReferenceButton(((Component)blackboard).transform); if ((Object)(object)val == (Object)null) { _log.LogDebug((object)"No reference button found to clone; will use fallback."); return; } _log.LogDebug((object)("Cloning reference button: " + ((Object)val).name)); _buttonObj = Object.Instantiate<GameObject>(val, parent); ((Object)_buttonObj).name = "OAO_AddLowStockButton"; PlayMakerFSM[] components = _buttonObj.GetComponents<PlayMakerFSM>(); for (int i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } components = _buttonObj.GetComponentsInChildren<PlayMakerFSM>(); for (int i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } Button val2 = _buttonObj.GetComponent<Button>(); if ((Object)(object)val2 == (Object)null) { val2 = _buttonObj.AddComponent<Button>(); } ((UnityEventBase)val2.onClick).RemoveAllListeners(); ((UnityEvent)val2.onClick).AddListener(new UnityAction(OnButtonClicked)); SetButtonText(_buttonObj, _config.ButtonText.Value); RectTransform component = _buttonObj.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { component.anchorMin = new Vector2(1f, 0f); component.anchorMax = new Vector2(1f, 0f); component.pivot = new Vector2(1f, 0f); component.anchoredPosition = new Vector2(-10f, 10f); component.sizeDelta = new Vector2(180f, 40f); } _log.LogInfo((object)"Button created by cloning native button."); } private GameObject FindReferenceButton(Transform root) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown foreach (Transform item in root) { Transform val = item; string text = ((Object)val).name.ToLower(); if ((Object)(object)((Component)val).GetComponent<Button>() != (Object)null && (text.Contains("buy") || text.Contains("button") || text.Contains("btn"))) { return ((Component)val).gameObject; } foreach (Transform item2 in val) { Transform val2 = item2; string text2 = ((Object)val2).name.ToLower(); if ((Object)(object)((Component)val2).GetComponent<Button>() != (Object)null && (text2.Contains("buy") || text2.Contains("button") || text2.Contains("btn"))) { return ((Component)val2).gameObject; } } } return null; } private void CreateButtonFallback(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) //IL_008b: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: 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) //IL_0158: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) _buttonObj = new GameObject("OAO_AddLowStockButton"); _buttonObj.transform.SetParent(parent, false); RectTransform obj = _buttonObj.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(1f, 0f); obj.anchorMax = new Vector2(1f, 0f); obj.pivot = new Vector2(1f, 0f); obj.anchoredPosition = new Vector2(-10f, 10f); obj.sizeDelta = new Vector2(180f, 40f); ((Graphic)_buttonObj.AddComponent<Image>()).color = new Color(0.2f, 0.6f, 0.2f, 1f); Button obj2 = _buttonObj.AddComponent<Button>(); ((UnityEvent)obj2.onClick).AddListener(new UnityAction(OnButtonClicked)); ColorBlock colors = ((Selectable)obj2).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0.2f, 0.6f, 0.2f, 1f); ((ColorBlock)(ref colors)).highlightedColor = new Color(0.3f, 0.7f, 0.3f, 1f); ((ColorBlock)(ref colors)).pressedColor = new Color(0.1f, 0.4f, 0.1f, 1f); ((Selectable)obj2).colors = colors; GameObject val = new GameObject("ButtonText"); val.transform.SetParent(_buttonObj.transform, false); RectTransform obj3 = val.AddComponent<RectTransform>(); obj3.anchorMin = Vector2.zero; obj3.anchorMax = Vector2.one; obj3.offsetMin = Vector2.zero; obj3.offsetMax = Vector2.zero; try { TextMeshProUGUI obj4 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj4).text = _config.ButtonText.Value; ((TMP_Text)obj4).alignment = (TextAlignmentOptions)514; ((Graphic)obj4).color = Color.white; ((TMP_Text)obj4).fontSize = 16f; ((TMP_Text)obj4).fontStyle = (FontStyles)1; } catch { Text obj6 = val.AddComponent<Text>(); obj6.text = _config.ButtonText.Value; obj6.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); obj6.alignment = (TextAnchor)4; ((Graphic)obj6).color = Color.white; obj6.fontStyle = (FontStyle)1; obj6.fontSize = 16; } _log.LogInfo((object)"Button created using fallback method."); } private void CreateAutoLabel(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) //IL_008b: Unknown result type (might be due to invalid IL or missing references) _autoLabelObj = new GameObject("OAO_AutoLabel"); _autoLabelObj.transform.SetParent(parent, false); RectTransform obj = _autoLabelObj.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(1f, 0f); obj.anchorMax = new Vector2(1f, 0f); obj.pivot = new Vector2(1f, 0f); obj.anchoredPosition = new Vector2(-10f, 52f); obj.sizeDelta = new Vector2(180f, 20f); try { TextMeshProUGUI obj2 = _autoLabelObj.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj2).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj2).fontSize = 12f; } catch { Text obj4 = _autoLabelObj.AddComponent<Text>(); obj4.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); obj4.alignment = (TextAnchor)4; obj4.fontSize = 12; } UpdateAutoLabel(); } public void UpdateAutoLabel() { //IL_003a: 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_003f: 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_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_autoLabelObj == (Object)null) { return; } Func<bool> isAutoEnabled = _isAutoEnabled; int num; object obj; if (isAutoEnabled == null) { num = 0; } else { num = (isAutoEnabled() ? 1 : 0); if (num != 0) { obj = "Auto Order: ON"; goto IL_0030; } } obj = "Auto Order: OFF"; goto IL_0030; IL_0030: string text = (string)obj; Color color = ((num != 0) ? Color.green : Color.gray); TextMeshProUGUI component = _autoLabelObj.GetComponent<TextMeshProUGUI>(); if ((Object)(object)component != (Object)null) { ((TMP_Text)component).text = text; ((Graphic)component).color = color; return; } Text component2 = _autoLabelObj.GetComponent<Text>(); if ((Object)(object)component2 != (Object)null) { component2.text = text; ((Graphic)component2).color = color; } } private void SetButtonText(GameObject buttonObj, string newText) { TextMeshProUGUI componentInChildren = buttonObj.GetComponentInChildren<TextMeshProUGUI>(); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)componentInChildren).text = newText; return; } Text componentInChildren2 = buttonObj.GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.text = newText; } } private void OnButtonClicked() { if (_isRunning) { return; } _isRunning = true; try { SetButtonInteractable(interactable: false); ExecuteManualRestock(); } finally { SetButtonInteractable(interactable: true); _isRunning = false; } } private void ExecuteManualRestock() { int value = _config.ThresholdUnits.Value; bool value2 = _config.VerboseLogging.Value; List<ProductStockSnapshot> snapshots = new InventoryScanner(_log, _inventory, _catalog, _shoppingList, _pendingTracker, value2).ScanAll(); List<ProductOrderCandidate> candidates = new RestockPlanner().PlanManualRestock(snapshots, value); var (num, num2) = new ShoppingListService(_log, _shoppingList, _catalog).AddCandidatesToShoppingList(candidates); _log.LogInfo((object)$"Manual restock: {num} added, {num2} skipped, threshold={value}"); new NotificationService(_notification, _config.ShowNotifications.Value).NotifyManualResult(num, num2, value); } private void SetButtonInteractable(bool interactable) { if (!((Object)(object)_buttonObj == (Object)null)) { Button component = _buttonObj.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ((Selectable)component).interactable = interactable; } } } private void LogUiHierarchy(ManagerBlackboard blackboard) { //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) _log.LogInfo((object)"=== UI Hierarchy Dump (ManagerBlackboard) ==="); ManualLogSource log = _log; GameObject tabsOBJ = blackboard.tabsOBJ; log.LogInfo((object)("tabsOBJ: " + (((tabsOBJ != null) ? ((Object)tabsOBJ).name : null) ?? "NULL"))); ManualLogSource log2 = _log; GameObject tabsOBJ2 = blackboard.tabsOBJ; object obj; if (tabsOBJ2 == null) { obj = null; } else { Transform transform = tabsOBJ2.transform; if (transform == null) { obj = null; } else { Transform parent = transform.parent; obj = ((parent != null) ? ((Object)parent).name : null); } } if (obj == null) { obj = "NULL"; } log2.LogInfo((object)("tabsOBJ.parent: " + (string?)obj)); ManualLogSource log3 = _log; GameObject shopItemsParent = blackboard.shopItemsParent; log3.LogInfo((object)("shopItemsParent: " + (((shopItemsParent != null) ? ((Object)shopItemsParent).name : null) ?? "NULL"))); ManualLogSource log4 = _log; GameObject shopItemsParent2 = blackboard.shopItemsParent; object obj2; if (shopItemsParent2 == null) { obj2 = null; } else { Transform transform2 = shopItemsParent2.transform; if (transform2 == null) { obj2 = null; } else { Transform parent2 = transform2.parent; obj2 = ((parent2 != null) ? ((Object)parent2).name : null); } } if (obj2 == null) { obj2 = "NULL"; } log4.LogInfo((object)("shopItemsParent.parent: " + (string?)obj2)); ManualLogSource log5 = _log; GameObject shoppingListParent = blackboard.shoppingListParent; log5.LogInfo((object)("shoppingListParent: " + (((shoppingListParent != null) ? ((Object)shoppingListParent).name : null) ?? "NULL"))); ManualLogSource log6 = _log; GameObject shoppingListParent2 = blackboard.shoppingListParent; object obj3; if (shoppingListParent2 == null) { obj3 = null; } else { Transform transform3 = shoppingListParent2.transform; if (transform3 == null) { obj3 = null; } else { Transform parent3 = transform3.parent; obj3 = ((parent3 != null) ? ((Object)parent3).name : null); } } if (obj3 == null) { obj3 = "NULL"; } log6.LogInfo((object)("shoppingListParent.parent: " + (string?)obj3)); ManualLogSource log7 = _log; TextMeshProUGUI totalChargeOBJ = blackboard.totalChargeOBJ; log7.LogInfo((object)("totalChargeOBJ: " + (((totalChargeOBJ != null) ? ((Object)totalChargeOBJ).name : null) ?? "NULL"))); ManualLogSource log8 = _log; TextMeshProUGUI totalChargeOBJ2 = blackboard.totalChargeOBJ; object obj4; if (totalChargeOBJ2 == null) { obj4 = null; } else { Transform transform4 = ((TMP_Text)totalChargeOBJ2).transform; if (transform4 == null) { obj4 = null; } else { Transform parent4 = transform4.parent; obj4 = ((parent4 != null) ? ((Object)parent4).name : null); } } if (obj4 == null) { obj4 = "NULL"; } log8.LogInfo((object)("totalChargeOBJ.parent: " + (string?)obj4)); Transform transform5 = ((Component)blackboard).transform; _log.LogInfo((object)$"ManagerBlackboard root: {((Object)transform5).name} (children={transform5.childCount})"); LogChildren(transform5, 1, 3); if ((Object)(object)blackboard.shoppingListParent != (Object)null) { _log.LogInfo((object)"--- Shopping list parent chain ---"); Transform val = blackboard.shoppingListParent.transform; int num = 0; while ((Object)(object)val != (Object)null && num < 8) { RectTransform component = ((Component)val).GetComponent<RectTransform>(); string arg = (((Object)(object)component != (Object)null) ? $"pos={component.anchoredPosition}, size={component.sizeDelta}, anchors=({component.anchorMin},{component.anchorMax})" : "no RectTransform"); _log.LogInfo((object)$" [depth {num}] {((Object)val).name} ({arg})"); val = val.parent; num++; } } _log.LogInfo((object)"=== End UI Hierarchy Dump ==="); } private void LogChildren(Transform parent, int currentDepth, int maxDepth) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (currentDepth > maxDepth) { return; } string text = new string(' ', currentDepth * 2); foreach (Transform item in parent) { Transform val = item; RectTransform component = ((Component)val).GetComponent<RectTransform>(); bool num = (Object)(object)((Component)val).GetComponent<Button>() != (Object)null; bool flag = (Object)(object)((Component)val).GetComponent<TextMeshProUGUI>() != (Object)null; string text2 = ""; if (num) { text2 += " [Button]"; } if (flag) { string text3 = text2; TextMeshProUGUI component2 = ((Component)val).GetComponent<TextMeshProUGUI>(); text2 = text3 + " [TMP: " + ((component2 != null) ? ((TMP_Text)component2).text : null) + "]"; } string text4 = (((Object)(object)component != (Object)null) ? $" pos={component.anchoredPosition}" : ""); _log.LogDebug((object)$"{text}{((Object)val).name} (children={val.childCount}){text4}{text2}"); LogChildren(val, currentDepth + 1, maxDepth); } } } } namespace OrderAndOrganize.Services { public class AutomationController { private readonly ManualLogSource _log; private readonly ModConfiguration _config; private readonly GameAuthorityAdapter _authority; private readonly GameMoneyAdapter _money; private readonly GamePurchaseAdapter _purchase; private readonly GameProductCatalogAdapter _catalog; private readonly GameInventoryAdapter _inventory; private readonly GameShoppingListAdapter _shoppingList; private readonly GameNotificationAdapter _notification; private readonly PendingOrderTracker _pendingTracker; private bool _enabled; private bool _isRunningCycle; private Coroutine _automationCoroutine; private bool _notifiedNotAuthority; public bool IsEnabled => _enabled; public AutomationController(ManualLogSource log, ModConfiguration config, GameAuthorityAdapter authority, GameMoneyAdapter money, GamePurchaseAdapter purchase, GameProductCatalogAdapter catalog, GameInventoryAdapter inventory, GameShoppingListAdapter shoppingList, GameNotificationAdapter notification, PendingOrderTracker pendingTracker) { _log = log; _config = config; _authority = authority; _money = money; _purchase = purchase; _catalog = catalog; _inventory = inventory; _shoppingList = shoppingList; _notification = notification; _pendingTracker = pendingTracker; } public void Toggle(MonoBehaviour host) { _enabled = !_enabled; _log.LogInfo((object)("Automation toggled: " + (_enabled ? "ENABLED" : "DISABLED"))); NotificationService notificationService = new NotificationService(_notification, _config.ShowNotifications.Value); if (_enabled) { notificationService.NotifyAutomationEnabled(); StartAutomation(host); } else { notificationService.NotifyAutomationDisabled(); StopAutomation(host); } } public void SetEnabled(bool enabled, MonoBehaviour host) { if (_enabled != enabled) { _enabled = enabled; _log.LogInfo((object)("Automation set: " + (_enabled ? "ENABLED" : "DISABLED"))); if (_enabled) { StartAutomation(host); } else { StopAutomation(host); } } } private void StartAutomation(MonoBehaviour host) { if (_automationCoroutine == null) { _automationCoroutine = host.StartCoroutine(AutomationLoop()); _log.LogInfo((object)"Automation coroutine started."); } } public void StopAutomation(MonoBehaviour host) { if (_automationCoroutine != null) { host.StopCoroutine(_automationCoroutine); _automationCoroutine = null; _log.LogInfo((object)"Automation coroutine stopped."); } _isRunningCycle = false; } public void OnSceneUnload() { _pendingTracker.ClearAll(); _isRunningCycle = false; _notifiedNotAuthority = false; _log.LogInfo((object)"Scene unloaded: cleared automation state."); } private IEnumerator AutomationLoop() { while (_enabled) { yield return (object)new WaitForSeconds((float)_config.ScanIntervalSeconds.Value); if (!_enabled) { break; } if (!_authority.IsStoreLoaded()) { _log.LogDebug((object)"Automation: no store loaded, skipping cycle."); } else if (!_authority.IsLocalAuthority()) { if (!_notifiedNotAuthority) { _log.LogInfo((object)"Automation: not the host/server. Automatic purchases disabled."); new NotificationService(_notification, _config.ShowNotifications.Value).NotifyNotAuthority(); _notifiedNotAuthority = true; } } else if (_isRunningCycle) { _log.LogDebug((object)"Automation: previous cycle still running, skipping."); } else { yield return RunCycle(); } } _automationCoroutine = null; } private IEnumerator RunCycle() { _isRunningCycle = true; ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard(); if ((Object)(object)managerBlackboard == (Object)null) { _log.LogDebug((object)"Automation: ManagerBlackboard not available."); _isRunningCycle = false; yield break; } if (!_purchase.IsShoppingListEmpty(managerBlackboard)) { new NotificationService(_notification, _config.ShowNotifications.Value).NotifyManualListBlocking(); _isRunningCycle = false; yield break; } int value = _config.ThresholdUnits.Value; bool value2 = _config.VerboseLogging.Value; List<ProductStockSnapshot> list; List<ProductOrderCandidate> list2; AutomationCycleResult result; try { list = new InventoryScanner(_log, _inventory, _catalog, _shoppingList, _pendingTracker, value2).ScanAll(); _pendingTracker.Reconcile(list, _config.PendingOrderTimeoutSeconds.Value); list2 = new RestockPlanner().PlanAutoRestock(list, value, _pendingTracker); result = new AutomationCycleResult { ProductsScanned = list.Count, ProductsBelowThreshold = list2.Count }; } catch (Exception arg) { _log.LogError((object)$"Automation scan/plan error: {arg}"); _isRunningCycle = false; yield break; } if (list2 == null || list2.Count == 0) { _log.LogDebug((object)$"Automation: no products below threshold ({value})."); _isRunningCycle = false; yield break; } float value3 = _config.CashReserve.Value; PurchaseService purchaseService = new PurchaseService(_log, _purchase, _money, _pendingTracker, value2); yield return CoroutineRunner.Instance.StartTrackedCoroutine(purchaseService.ExecutePurchases(managerBlackboard, list2, list, value3, result)); _log.LogInfo((object)($"Automation cycle complete: scanned={result.ProductsScanned}, " + $"below threshold={result.ProductsBelowThreshold}, purchased={result.ProductsPurchased}, " + $"skipped(funds)={result.ProductsSkippedInsufficientFunds}, " + $"skipped(pending)={result.ProductsSkippedPending}, " + $"spent=${result.TotalSpent:F2}, " + $"money={result.MoneyBefore:F2}->{result.MoneyAfter:F2}")); new NotificationService(_notification, _config.ShowNotifications.Value).NotifyAutomationResult(result); _isRunningCycle = false; } } public class CategoryMapper { private readonly ManualLogSource _log; private Dictionary<int, int> _productToGroup; private Dictionary<int, string> _groupNames; private Dictionary<int, Color> _groupColors; private bool _initialized; public CategoryMapper(ManualLogSource log) { _log = log; } public int GetGroupForProduct(int productId) { EnsureInitialized(); if (!_productToGroup.TryGetValue(productId, out var value)) { return -1; } return value; } public string GetGroupName(int groupIndex) { EnsureInitialized(); if (_groupNames.TryGetValue(groupIndex, out var value)) { return value; } return $"Group {groupIndex}"; } public Color GetGroupColor(int groupIndex) { //IL_001c: 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) EnsureInitialized(); if (!_groupColors.TryGetValue(groupIndex, out var value)) { return Color.white; } return value; } public Dictionary<int, string> GetAllGroups() { EnsureInitialized(); return new Dictionary<int, string>(_groupNames); } public void Rebuild() { _initialized = false; EnsureInitialized(); } private void EnsureInitialized() { //IL_01a6: 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) if (_initialized) { return; } _productToGroup = new Dictionary<int, int>(); _groupNames = new Dictionary<int, string>(); _groupColors = new Dictionary<int, Color>(); ProductListing instance = ProductListing.Instance; if ((Object)(object)instance == (Object)null || instance.tiers == null || instance.productGroups == null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"CategoryMapper: ProductListing not available yet."); } return; } _initialized = true; for (int i = 0; i < instance.tiers.Length; i++) { string text = instance.tiers[i]; if (string.IsNullOrEmpty(text)) { continue; } string[] array = text.Split(new char[1] { '-' }); if (array.Length != 2 || !int.TryParse(array[0], out var result) || !int.TryParse(array[1], out var result2)) { continue; } int num = ((i < instance.productGroups.Length) ? instance.productGroups[i] : (-1)); if (num < 0) { continue; } for (int j = result; j <= result2; j++) { _productToGroup[j] = num; } if (_groupNames.ContainsKey(num)) { continue; } string text2 = "productGroup" + num; string text3 = null; try { if ((Object)(object)LocalizationManager.instance != (Object)null) { text3 = LocalizationManager.instance.GetLocalizationString(text2); } } catch { } _groupNames[num] = ((!string.IsNullOrEmpty(text3)) ? text3 : $"Group {num}"); if (instance.groupsColors != null && num < instance.groupsColors.Length) { _groupColors[num] = instance.groupsColors[num]; } else { _groupColors[num] = Color.white; } } ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"CategoryMapper: Mapped {_productToGroup.Count} products across {_groupNames.Count} groups."); } foreach (KeyValuePair<int, string> groupName in _groupNames) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogDebug((object)$" Group {groupName.Key}: {groupName.Value}"); } } } } public class CategoryShelfManager { private readonly ManualLogSource _log; private readonly CategoryMapper _categoryMapper; private readonly string _savePath; private Dictionary<string, int> _assignments = new Dictionary<string, int>(); public int AssignmentCount => _assignments.Count; private string BackupPath => _savePath + ".backup"; public CategoryShelfManager(ManualLogSource log, CategoryMapper categoryMapper, string savePath) { _log = log; _categoryMapper = categoryMapper; _savePath = savePath; Load(); } public void SetCategory(Data_Container container, int groupIndex) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) string text = PositionKey(((Component)container).transform.position); _assignments[text] = groupIndex; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"Category set: shelf at {text} -> group {groupIndex} ({_categoryMapper.GetGroupName(groupIndex)})"); } Save(); } public void ClearCategory(Data_Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) string text = PositionKey(((Component)container).transform.position); if (_assignments.Remove(text)) { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Category cleared: shelf at " + text)); } Save(); } } public void ClearCategoryByPosition(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string text = PositionKey(position); if (_assignments.Remove(text)) { ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Category auto-cleared: shelf destroyed at " + text)); } Save(); } } public void PurgeStaleAssignments() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) if (_assignments.Count == 0) { return; } List<string> list = new List<string>(); foreach (string key in _assignments.Keys) { Vector3 val = ParsePositionKey(key); bool flag = false; Collider[] array = Physics.OverlapSphere(val, 0.5f); foreach (Collider val2 in array) { Data_Container val3 = ((Component)val2).GetComponent<Data_Container>(); if ((Object)(object)val3 == (Object)null) { val3 = ((Component)val2).GetComponentInParent<Data_Container>(); } if ((Object)(object)val3 != (Object)null && val3.containerClass == 69) { flag = true; break; } } if (!flag) { list.Add(key); } } if (list.Count == 0) { return; } int count = _assignments.Count; float num = (float)list.Count / (float)count; if (num > 0.5f) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)($"CategoryShelfManager: Purge ABORTED — {list.Count}/{count} entries " + $"({num:P0}) would be removed. This likely means shelves haven't loaded yet.")); } return; } CreateBackup(); foreach (string item in list) { _assignments.Remove(item); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)("CategoryShelfManager: Purged stale assignment at " + item + " (shelf no longer exists)")); } } Save(); } public int? GetCategory(Data_Container container) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) string key = PositionKey(((Component)container).transform.position); if (!_assignments.TryGetValue(key, out var value)) { return null; } return value; } public bool IsProductAllowed(Data_Container container, int productId) { int? category = GetCategory(container); if (!category.HasValue) { return true; } return _categoryMapper.GetGroupForProduct(productId) == category.Value; } public IReadOnlyDictionary<string, int> GetAllAssignments() { return _assignments; } public bool IsProductAllowedAtPosition(Vector3 position, int productId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string key = PositionKey(position); if (!_assignments.TryGetValue(key, out var value)) { return true; } return _categoryMapper.GetGroupForProduct(productId) == value; } public int? GetCategoryAtPosition(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) string key = PositionKey(position); if (!_assignments.TryGetValue(key, out var value)) { return null; } return value; } public static string PositionKey(Vector3 pos) { //IL_0000: 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_0024: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(pos.x * 10f); int num2 = Mathf.RoundToInt(pos.y * 10f); int num3 = Mathf.RoundToInt(pos.z * 10f); return $"{num},{num2},{num3}"; } public static Vector3 ParsePositionKey(string key) { //IL_0018: 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_003c: 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_004e: Unknown result type (might be due to invalid IL or missing references) string[] array = key.Split(new char[1] { ',' }); if (array.Length != 3) { return Vector3.zero; } if (!int.TryParse(array[0], out var result)) { return Vector3.zero; } if (!int.TryParse(array[1], out var result2)) { return Vector3.zero; } if (!int.TryParse(array[2], out var result3)) { return Vector3.zero; } return new Vector3((float)result / 10f, (float)result2 / 10f, (float)result3 / 10f); } private void CreateBackup() { try { if (File.Exists(_savePath)) { File.Copy(_savePath, BackupPath, overwrite: true); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("CategoryShelfManager: Backup created at " + BackupPath)); } } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("CategoryShelfManager: Failed to create backup: " + ex.Message)); } } } private bool TryRestoreFromBackup() { if (!File.Exists(BackupPath)) { return false; } try { string json = File.ReadAllText(BackupPath); Dictionary<string, int> assignments = new Dictionary<string, int>(); Dictionary<string, int> assignments2 = _assignments; _assignments = assignments; ParseJson(json); int count = _assignments.Count; _assignments = assignments2; if (count == 0) { return false; } _assignments = assignments; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"CategoryShelfManager: Restored {count} assignments from backup."); } Save(); return true; } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogWarning((object)("CategoryShelfManager: Failed to restore from backup: " + ex.Message)); } return false; } } private void Save() { try { string directoryName = Path.GetDirectoryName(_savePath); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.AppendLine(" \"version\": 1,"); stringBuilder.AppendLine(" \"assignments\": {"); int num = 0; foreach (KeyValuePair<string, int> assignment in _assignments) { num++; string arg = ((num < _assignments.Count) ? "," : ""); stringBuilder.AppendLine($" \"{EscapeJson(assignment.Key)}\": {assignment.Value}{arg}"); } stringBuilder.AppendLine(" }"); stringBuilder.AppendLine("}"); File.WriteAllText(_savePath, stringBuilder.ToString()); ManualLogSource log = _log; if (log != null) { log.LogDebug((object)$"CategoryShelfManager: Saved {_assignments.Count} assignments to {_savePath}"); } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("CategoryShelfManager: Failed to save: " + ex.Message)); } } } private void Load() { _assignments.Clear(); if (!File.Exists(_savePath)) { ManualLogSource log = _log; if (log != null) { log.LogDebug((object)"CategoryShelfManager: No save file found, starting fresh."); } return; } try { string json = File.ReadAllText(_savePath); ParseJson(json); PurgeCorruptKeys(); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"CategoryShelfManager: Loaded {_assignments.Count} assignments from {_savePath}"); } } catch (Exception ex) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogError((object)("CategoryShelfManager: Failed to load: " + ex.Message)); } } if (_assignments.Count == 0 && File.Exists(BackupPath)) { ManualLogSource log4 = _log; if (log4 != null) { log4.LogWarning((object)"CategoryShelfManager: Main file has 0 assignments but backup exists — attempting restore."); } TryRestoreFromBackup(); } } private void ParseJson(string json) { int num = json.IndexOf("\"assignments\"", StringComparison.Ordinal); if (num < 0) { return; } int num2 = json.IndexOf('{', num + 13); if (num2 < 0) { return; } int num3 = json.IndexOf('}', num2); if (num3 < 0) { return; } string[] array = json.Substring(num2 + 1, num3 - num2 - 1).Split(new char[1] { '\n' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim().TrimEnd(new char[1] { ',' }); if (string.IsNullOrEmpty(text)) { continue; } int num4 = text.IndexOf('"'); if (num4 < 0) { continue; } int num5 = text.LastIndexOf('"'); if (num5 > num4) { string text2 = text.Substring(num4 + 1, num5 - num4 - 1); string s = text.Substring(text.LastIndexOf(':') + 1).Trim(); if (!string.IsNullOrEmpty(text2) && int.TryParse(s, out var result)) { _assignments[text2] = result; } } } } private void PurgeCorruptKeys() { List<string> list = new List<string>(); foreach (string key in _assignments.Keys) { string[] array = key.Split(new char[1] { ',' }); if (array.Length != 3 || !int.TryParse(array[0], out var result) || !int.TryParse(array[1], out result) || !int.TryParse(array[2], out result)) { list.Add(key); } } if (list.Count <= 0) { return; } foreach (string item in list) { _assignments.Remove(item); ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("CategoryShelfManager: Removed corrupt key: '" + item + "'")); } } Save(); } private static string EscapeJson(string s) { return s.Replace("\\", "\\\\").Replace("\"", "\\\""); } } public class CoroutineRunner : MonoBehaviour { public static CoroutineRunner Instance { get; private set; } public static void Initialize() { //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_001e: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("OAO_CoroutineRunner"); Object.DontDestroyOnLoad((Object)val); Instance = val.AddComponent<CoroutineRunner>(); } } public Coroutine StartTrackedCoroutine(IEnumerator routine) { return ((MonoBehaviour)this).StartCoroutine(routine); } } public class InventoryScanner { private readonly ManualLogSource _log; private readonly GameInventoryAdapter _inventory; private readonly GameProductCatalogAdapter _catalog; private readonly GameShoppingListAdapter _shoppingList; private readonly PendingOrderTracker _pendingTracker; private readonly bool _verbose; public InventoryScanner(ManualLogSource log, GameInventoryAdapter inventory, GameProductCatalogAdapter catalog, GameShoppingListAdapter shoppingList, PendingOrderTracker pendingTracker, bool verbose) { _log = log; _inventory = inventory; _catalog = catalog; _shoppingList = shoppingList; _pendingTracker = pendingTracker; _verbose = verbose; } public List<ProductStockSnapshot> ScanAll() { List<ProductStockSnapshot> list = new List<ProductStockSnapshot>(); ProductListing productListing = _catalog.GetProductListing(); ManagerBlackboard managerBlackboard = _catalog.GetManagerBlackboard(); if ((Object)(object)productListing == (Object)null || (Object)(object)managerBlackboard == (Object)null) { _log.LogWarning((object)"Cannot scan: ProductListing or ManagerBlackboard not available."); return list; } if (!_inventory.Resolve()) { _log.LogError((object)"Cannot scan: GetProductsExistences method not resolved."); return list; } List<int> availableProducts = _catalog.GetAvailableProducts(productListing); if (availableProducts == null || availableProducts.Count == 0) { _log.LogDebug((object)"No available products to scan."); return list; } foreach (int item in availableProducts) { try { ProductStockSnapshot productStockSnapshot = ScanProduct(managerBlackboard, productListing, item); if (productStockSnapshot != null) { list.Add(productStockSnapshot); } } catch (Exception ex) { _log.LogWarning((object)$"Error scanning product {item}: {ex.Message}"); } } _log.LogDebug((object)$"Scan complete: {list.Count} products scanned."); return list; } private ProductStockSnapshot ScanProduct(ManagerBlackboard blackboard, ProductListing listing, int productId) { if (listing.productsData == null || productId < 0 || productId >= listing.productsData.Length) { return null; } bool flag = _catalog.IsProductUnlocked(listing, productId); int[] productExistences = _inventory.GetProductExistences(blackboard, productId); if (productExistences == null || productExistences.Length < 3) { return null; } int num = productExistences[0]; int num2 = productExistences[1]; int num3 = productExistences[2]; int num4 = 0; PendingAutomatedOrder pendingAutomatedOrder = _pendingTracker?.GetPendingOrder(productId); if (pendingAutomatedOrder != null) { int num5 = Math.Max(0, num3 - pendingAutomatedOrder.InMovementBeforePurchase); num4 = Math.Max(0, pendingAutomatedOrder.OrderedUnits - num5); } string productName = _catalog.GetProductName(productId); int maxItemsPerBox = _catalog.GetMaxItemsPerBox(listing, productId); float boxPrice = _catalog.GetBoxPrice(listing, productId); bool flag2 = _shoppingList.IsProductOnShoppingList(blackboard, productId); ProductStockSnapshot productStockSnapshot = new ProductStockSnapshot { ProductId = productId, ProductName = productName, OnShelves = num, InStorage = num2, InMovement = num3, PendingUnreflectedUnits = num4, UnitsPerBox = maxItemsPerBox, BoxPrice = boxPrice, IsUnlocked = flag, IsOrderable = (flag && maxItemsPerBox > 0), IsOnShoppingList = flag2 }; if (_verbose) { _log.LogDebug((object)($"Product={productName} ProductId={productId} " + $"OnShelves={num} InStorage={num2} InMovement={num3} " + $"PendingUnreflected={num4} CombinedStock={productStockSnapshot.CombinedStock} " + $"EffectiveCombinedStock={productStockSnapshot.EffectiveCombinedStock} " + $"UnitsPerBox={maxItemsPerBox} BoxPrice={boxPrice:F2} " + $"AlreadyOnShoppingList={flag2}")); } return productStockSnapshot; } } public class NotificationService { private readonly GameNotificationAdapter _adapter; private readonly bool _enabled; public NotificationService(GameNotificationAdapter adapter, bool enabled) { _adapter = adapter; _enabled = enabled; } public void NotifyAutomationEnabled() { if (_enabled) { _adapter.ShowNotification("Order & Organize automation enabled."); } } public void NotifyAutomationDisabled() { if (_enabled) { _adapter.ShowNotification("Order & Organize automation disabled."); } } public void NotifyManualResult(int added, int skipped, int threshold) { if (!_enabled) { return; } if (added == 0 && skipped == 0) { _adapter.ShowNotification($"Order & Organize: nothing is below {threshold} units."); return; } string message = $"Order & Organize: added {added} products to the shopping list."; if (skipped > 0) { message = $"Order & Organize: added {added} products, skipped {skipped} already listed."; } _adapter.ShowNotification(message); } public void NotifyAutomationResult(AutomationCycleResult result) { if (_enabled && (result.HasPurchases || result.HasSkips)) { if (result.ProductsPurchased > 0 && result.ProductsSkippedInsufficientFunds > 0) { _adapter.ShowImportantNotification($"Auto-Order: {result.ProductsPurchased} boxes purchased for ${result.TotalSpent:F2} " + $"({result.ProductsSkippedInsufficientFunds} skipped - low funds)"); } else if (result.ProductsPurchased > 0) { _adapter.ShowImportantNotification($"Auto-Order: {result.ProductsPurchased} boxes purchased for ${result.TotalSpent:F2}"); } } } public void NotifyManualListBlocking() { if (_enabled) { _adapter.ShowRateLimitedNotification("manual_list_block", "Order & Organize paused: manual shopping list is not empty."); } } public void NotifyNotAuthority() { if (_enabled) { _adapter.ShowRateLimitedNotification("not_authority", "Order & Organize: automation disabled (not host)."); } } public void NotifyCompatibilityError(string detail) { _adapter.ShowNotification("Order & Organize could not access the current ordering system. Check BepInEx logs."); } } public class PendingOrderTracker { private readonly ManualLogSource _log; private readonly Dictionary<int, PendingAutomatedOrder> _pendingOrders = new Dictionary<int, PendingAutomatedOrder>(); public int Count => _pendingOrders.Count; public PendingOrderTracker(ManualLogSource log) { _log = log; } public void RecordOrder(ProductStockSnapshot snapshot, float boxPrice) { PendingAutomatedOrder pendingAutomatedOrder = new PendingAutomatedOrder { ProductId = snapshot.ProductId, ProductName = snapshot.ProductName, OrderedUnits = snapshot.UnitsPerBox, UnitsPerBox = snapshot.UnitsPerBox, PurchaseTimestamp = DateTime.UtcNow, CombinedStockBeforePurchase = snapshot.CombinedStock, InMovementBeforePurchase = snapshot.InMovement, ExpectedCombinedStock = snapshot.CombinedStock + snapshot.UnitsPerBox, BoxPrice = boxPrice }; _pendingOrders[snapshot.Product