From 21a88d6ef84c2c0b3c3fa5c562b24119d308e23f Mon Sep 17 00:00:00 2001 From: Syklass Date: Sat, 11 Jul 2026 15:16:05 +0300 Subject: [PATCH 1/2] Fix name scan after BSG magnifier change and language switch race Load the search marker from Data/icon_search.png with scale calibrated to the new template width. Preload offline item cache on startup and resolve items via TryGetItemById to avoid crashes when the cache is still loading after a language change. Unregister hotkeys while saving settings and skip scans gracefully when an item is not cached yet. Track icon_search.png in repo: required for Name Scan after BSG magnifier UI change. Bump version to 3.9.4. --- .gitignore | 5 ++- .vscode/launch.json | 16 ++++++++ .vscode/tasks.json | 40 +++++++++++++++++++ RatScanner/Data/icon_search.png | Bin 0 -> 773 bytes RatScanner/RatConfig.cs | 1 + RatScanner/RatScanner.csproj | 2 +- RatScanner/RatScannerMain.cs | 41 ++++++++++++++------ RatScanner/Scan/ItemIconScan.cs | 8 +++- RatScanner/Scan/ItemNameScan.cs | 8 +++- RatScanner/TarkovDevAPI.cs | 27 +++++++++++++ RatScanner/ViewModel/SettingsVM.cs | 60 +++++++++++++++-------------- 11 files changed, 162 insertions(+), 46 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 RatScanner/Data/icon_search.png diff --git a/.gitignore b/.gitignore index 816d30c8..d57cb2d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ ## Custom ignores -# Static icon data +# Static icon data (downloaded from RatScannerData releases for local dev) RatScanner/[Dd]ata/* +# Shipped with the app: updated magnifier template for BSG's post-patch inspect UI. +# RatEye 4.x no longer embeds this asset; Name Scan loads it from Data/icon_search.png. +!RatScanner/[Dd]ata/icon_search.png # publish folder publish/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..eff9e592 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "RatScanner (Debug)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/RatScanner/bin/Debug/net10.0-windows10.0.22621.0/RatScanner.exe", + "args": [], + "cwd": "${workspaceFolder}/RatScanner/bin/Debug/net10.0-windows10.0.22621.0", + "console": "integratedTerminal", + "stopAtEntry": false + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..7c30dfe8 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,40 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/RatScanner/RatScanner.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/RatScanner/RatScanner.csproj", + "-c", + "Release", + "-o", + "${workspaceFolder}/publish", + "--runtime", + "win-x64", + "-p:PublishSingleFile=true", + "--self-contained", + "true" + ], + "problemMatcher": "$msCompile" + } + ] +} diff --git a/RatScanner/Data/icon_search.png b/RatScanner/Data/icon_search.png new file mode 100644 index 0000000000000000000000000000000000000000..c55d52deb8f615ba6e1f1dee4cf62c715d6aa1a5 GIT binary patch literal 773 zcmV+g1N!`lP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0-8xgK~y+Tt(5Ca zlW`Qszq>e{w3}us8zy)cO4Bk;e3P0IDEP(~3L*H9^mq6s-}F{62$Z3zGn;9X#6l%h zaN2Y?=PsJNb!r1dXzw>;4=XcKcJc?qoIf?(Ij9@yw9%hRLdV>K%Pc(aVnI zWhm&rxwTaqlNP2YkW!_RY<>iN69W$q4iJq-VW5(*(!v6P03wkHt``&_CnqQM^t&_~ z4Q><`3X~hbN(!QugO|1ZG>TG3A4Q|!dN!IU{mVVz&USw|-78OZ$ ze4m}24Fegssv^t$mirPOo2(?-*E{~HjJ#II`WC2S_3A9=* zTrL-$kB$nEH@g61(7l!xJnrd{Ot_N?3bdHb(34qt0wOd{E-L<;`FWWDt{dwo*fj#( zZ*E3=SC@czT&xold}cYWDL)@df^l{{n|`0~^4Vk%AMIgB2ePQZb2Brr(eKFbm%vOU z-Q-SjvD-U4rAD^dSTrue Resources\RatLogoSmall.ico RatScanner.App - 3.9.3 + 3.9.4 disable true RatScanner diff --git a/RatScanner/RatScannerMain.cs b/RatScanner/RatScannerMain.cs index aafeee67..2d9ad1dc 100644 --- a/RatScanner/RatScannerMain.cs +++ b/RatScanner/RatScannerMain.cs @@ -205,10 +205,20 @@ private RatEye.Config GetRatEyeConfig(bool highlighted = true) { InventoryConfig = new Config.Processing.Inventory() { OptimizeHighlighted = highlighted, }, + InspectionConfig = CreateInspectionConfig(), }, }; } + private static Config.Processing.Inspection CreateInspectionConfig() { + var marker = new Bitmap(RatConfig.Paths.SearchIcon); + // MarkerItemScale is calibrated to template width: in-game icon is ~16px at 1080p + return new Config.Processing.Inspection() { + Marker = marker, + MarkerItemScale = 16f / marker.Width, + }; + } + private Database RatStashDatabaseFromTarkovDev() { List rsItems = new(); if (!TarkovDevAPI.TryGetCachedItems(out TarkovDev.GraphQL.Item[] items) || items.Length == 0) { @@ -298,17 +308,25 @@ internal void NameScan(Vector2 position) { toolTipPosition += new Vector2(-(int)(marker.Width * scale), (int)(marker.Height * scale)); toolTipPosition += position; - ItemNameScan tempNameScan = new( - inspection, - toolTipPosition, - RatConfig.ToolTip.Duration); - - ItemScans.Enqueue(tempNameScan); + if (!TryEnqueueNameScan(inspection, toolTipPosition)) return; RefreshOverlay(); } } + private bool TryEnqueueNameScan(RatEye.Processing.Inspection inspection, Vector2 toolTipPosition) { + if (!TarkovDevAPI.TryGetItemById(inspection.Item!.Id, out _)) { + Logger.LogWarning($"Skipping name scan: item {inspection.Item.Id} is not in cache yet."); + return false; + } + + ItemScans.Enqueue(new ItemNameScan( + inspection, + toolTipPosition, + RatConfig.ToolTip.Duration)); + return true; + } + /// /// Perform a name scan over the entire active screen /// @@ -333,12 +351,7 @@ internal void NameScanScreen(object? _ = null) { Bitmap marker = RatEyeEngine.Config.ProcessingConfig.InspectionConfig.Marker; toolTipPosition += new Vector2(0, (int)(marker.Height * scale)); - ItemNameScan tempNameScan = new( - inspection, - toolTipPosition, - RatConfig.ToolTip.Duration); - - ItemScans.Enqueue(tempNameScan); + TryEnqueueNameScan(inspection, toolTipPosition); } RefreshOverlay(); } @@ -364,6 +377,10 @@ internal void IconScan(Vector2 position) { RatEye.Processing.Icon? icon = inventory.LocateIcon(); if (icon?.DetectionConfidence <= 0 || icon?.Item == null) return; + if (!TarkovDevAPI.TryGetItemById(icon.Item.Id, out _)) { + Logger.LogWarning($"Skipping icon scan: item {icon.Item.Id} is not in cache yet."); + return; + } Vector2 toolTipPosition = position; toolTipPosition += icon.Position + icon.ItemPosition; diff --git a/RatScanner/Scan/ItemIconScan.cs b/RatScanner/Scan/ItemIconScan.cs index 2b3c1dd6..c73521b4 100644 --- a/RatScanner/Scan/ItemIconScan.cs +++ b/RatScanner/Scan/ItemIconScan.cs @@ -1,8 +1,8 @@ using RatEye; using RatStash; using System; -using System.Linq; using Icon = RatEye.Processing.Icon; +using TarkovItem = RatScanner.TarkovDev.GraphQL.Item; namespace RatScanner.Scan; @@ -16,7 +16,11 @@ public class ItemIconScan : ItemScan { public ItemIconScan(Icon icon, Vector2 toolTipPosition, int duration) { Icon = icon; RatStash.Item iconItem = icon.Item; - Item = TarkovDevAPI.GetItems().FirstOrDefault(item => item.Id == iconItem.Id) ?? throw new Exception($"Unknown item: {icon.Item.Id}"); + if (!TarkovDevAPI.TryGetItemById(iconItem.Id, out TarkovItem? tarkovItem) || tarkovItem is null) { + throw new Exception($"Unknown item: {iconItem.Id}"); + } + + Item = tarkovItem; ItemExtraInfo = icon.ItemExtraInfo; Confidence = icon.DetectionConfidence; Rotated = icon.Rotated; diff --git a/RatScanner/Scan/ItemNameScan.cs b/RatScanner/Scan/ItemNameScan.cs index 94640b58..60556504 100644 --- a/RatScanner/Scan/ItemNameScan.cs +++ b/RatScanner/Scan/ItemNameScan.cs @@ -1,7 +1,7 @@ using RatEye; using RatEye.Processing; using System; -using System.Linq; +using TarkovItem = RatScanner.TarkovDev.GraphQL.Item; namespace RatScanner.Scan; @@ -10,7 +10,11 @@ public class ItemNameScan : ItemScan { public ItemNameScan(Inspection inspection, Vector2 toolTipPosition, int duration) { RatStash.Item inspectionItem = inspection.Item; - Item = TarkovDevAPI.GetItems().FirstOrDefault(item => item.Id == inspectionItem.Id) ?? throw new Exception($"Unknown item: {inspection.Item.Id}"); + if (!TarkovDevAPI.TryGetItemById(inspectionItem.Id, out TarkovItem? tarkovItem) || tarkovItem is null) { + throw new Exception($"Unknown item: {inspectionItem.Id}"); + } + + Item = tarkovItem; Confidence = inspection.MarkerConfidence; IconPath = inspection.IconPath; _toolTipPosition = toolTipPosition; diff --git a/RatScanner/TarkovDevAPI.cs b/RatScanner/TarkovDevAPI.cs index 90d934ff..dfd64199 100644 --- a/RatScanner/TarkovDevAPI.cs +++ b/RatScanner/TarkovDevAPI.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Json; @@ -306,6 +307,12 @@ private static bool IsCacheExpired(string baseQueryKey, long time) { /// Full cache initialization - waits for all requests to complete /// public static async Task InitializeCache() { + // Preload offline cache for the current language so scans do not fail during fetch + TryLoadFromOfflineCache(ItemsQueryKey(), RatConfig.MediumTTL); + TryLoadFromOfflineCache(TasksQueryKey(), RatConfig.LongTTL); + TryLoadFromOfflineCache(HideoutStationsQueryKey(), RatConfig.LongTTL); + TryLoadFromOfflineCache(MapsQueryKey(), RatConfig.LongTTL); + await Task.WhenAll( QueueRequest(ItemsQueryKey(), ItemsQuery, RatConfig.MediumTTL), QueueRequest(TasksQueryKey(), TasksQuery, RatConfig.LongTTL), @@ -316,6 +323,26 @@ await Task.WhenAll( public static Item[] GetItems(LanguageCode language, GameMode gameMode) => GetCached(ItemsQueryKey(language, gameMode), () => ItemsQuery(language, gameMode), RatConfig.MediumTTL); public static Item[] GetItems() => GetCached(ItemsQueryKey(), ItemsQuery, RatConfig.MediumTTL); + + /// + /// Looks up an item by id in the current language cache and, if needed, in other loaded item caches. + /// + public static bool TryGetItemById(string id, out Item? item) { + item = GetItems().FirstOrDefault(i => i.Id == id); + if (item != null) return true; + + foreach (KeyValuePair entry in Cache) { + if (!entry.Key.StartsWith("items_", StringComparison.Ordinal)) continue; + if (entry.Value.response is not Item[] items) continue; + + item = items.FirstOrDefault(i => i.Id == id); + if (item != null) return true; + } + + item = null; + return false; + } + public static bool TryGetCachedItems(out Item[] items) { if (Cache.TryGetValue(ItemsQueryKey(), out (long expire, object response) cached)) { items = (Item[])cached.response; diff --git a/RatScanner/ViewModel/SettingsVM.cs b/RatScanner/ViewModel/SettingsVM.cs index 13f499ca..29e76b76 100644 --- a/RatScanner/ViewModel/SettingsVM.cs +++ b/RatScanner/ViewModel/SettingsVM.cs @@ -1,4 +1,4 @@ -using RatStash; +using RatStash; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; @@ -15,9 +15,9 @@ internal class SettingsVM : INotifyPropertyChanged { public bool UseCachedIcons { get; set; } public Hotkey IconScanHotkey { get; set; } - public string ToolTipDuration { get; set; } - public int ToolTipMilli { get; set; } - public UiLanguage UiLanguage { get; set; } + public string ToolTipDuration { get; set; } + public int ToolTipMilli { get; set; } + public UiLanguage UiLanguage { get; set; } public bool ShowName { get; set; } public bool ShowAvgDayPrice { get; set; } @@ -51,15 +51,15 @@ internal class SettingsVM : INotifyPropertyChanged { // Interactable Overlay public bool EnableIneractableOverlay { get; set; } - public bool BlurBehindSearch { get; set; } - public Hotkey InteractableOverlayHotkey { get; set; } - - private readonly LocalizationService _localizationService; - - internal SettingsVM(LocalizationService localizationService) { - _localizationService = localizationService; - LoadSettings(); - } + public bool BlurBehindSearch { get; set; } + public Hotkey InteractableOverlayHotkey { get; set; } + + private readonly LocalizationService _localizationService; + + internal SettingsVM(LocalizationService localizationService) { + _localizationService = localizationService; + LoadSettings(); + } public void LoadSettings() { EnableNameScan = RatConfig.NameScan.Enable; @@ -71,9 +71,9 @@ public void LoadSettings() { UseCachedIcons = RatConfig.IconScan.UseCachedIcons; IconScanHotkey = RatConfig.IconScan.Hotkey; - ToolTipDuration = RatConfig.ToolTip.Duration.ToString(); - ToolTipMilli = RatConfig.ToolTip.Duration; - UiLanguage = RatConfig.UserInterface.Language; + ToolTipDuration = RatConfig.ToolTip.Duration.ToString(); + ToolTipMilli = RatConfig.ToolTip.Duration; + UiLanguage = RatConfig.UserInterface.Language; ShowName = RatConfig.MinimalUi.ShowName; ShowAvgDayPrice = RatConfig.MinimalUi.ShowAvgDayPrice; @@ -110,11 +110,13 @@ public void LoadSettings() { public async Task SaveSettings() { bool updateMarketDB = NameScanLanguage != (int)RatConfig.NameScan.Language; bool updateTarkovTrackerToken = TarkovTrackerToken != RatConfig.Tracking.TarkovTracker.Token; - bool updateTarkovTrackerBackend = TarkovTrackerBackend != RatConfig.Tracking.TarkovTracker.Backend; - bool updateResolution = ScreenWidth != RatConfig.ScreenWidth || ScreenHeight != RatConfig.ScreenHeight; - bool updateLanguage = RatConfig.NameScan.Language != (Language)NameScanLanguage; - bool updateUiLanguage = RatConfig.UserInterface.Language != UiLanguage; + bool updateTarkovTrackerBackend = TarkovTrackerBackend != RatConfig.Tracking.TarkovTracker.Backend; + bool updateResolution = ScreenWidth != RatConfig.ScreenWidth || ScreenHeight != RatConfig.ScreenHeight; + bool updateLanguage = RatConfig.NameScan.Language != (Language)NameScanLanguage; + bool updateUiLanguage = RatConfig.UserInterface.Language != UiLanguage; + RatScannerMain.Instance.HotkeyManager.UnregisterHotkeys(); + try { // Save config RatConfig.NameScan.Enable = EnableNameScan; RatConfig.NameScan.EnableAuto = EnableAutoNameScan; @@ -123,11 +125,11 @@ public async Task SaveSettings() { RatConfig.IconScan.Enable = EnableIconScan; RatConfig.IconScan.ScanRotatedIcons = ScanRotatedIcons; RatConfig.IconScan.UseCachedIcons = UseCachedIcons; - RatConfig.IconScan.Hotkey = IconScanHotkey; - - RatConfig.ToolTip.Duration = int.TryParse(ToolTipDuration, out int i) ? i : 0; - RatConfig.ToolTip.Duration = ToolTipMilli; - RatConfig.UserInterface.Language = UiLanguage; + RatConfig.IconScan.Hotkey = IconScanHotkey; + + RatConfig.ToolTip.Duration = int.TryParse(ToolTipDuration, out int i) ? i : 0; + RatConfig.ToolTip.Duration = ToolTipMilli; + RatConfig.UserInterface.Language = UiLanguage; RatConfig.MinimalUi.ShowName = ShowName; RatConfig.MinimalUi.ShowAvgDayPrice = ShowAvgDayPrice; @@ -163,11 +165,13 @@ public async Task SaveSettings() { PageSwitcher.Instance.ResetWindowSize(); await TarkovDevAPI.InitializeCache(); if (updateTarkovTrackerToken || updateTarkovTrackerBackend) UpdateTarkovTrackerToken(); - if (updateUiLanguage) _localizationService.SetLanguage(UiLanguage); - if (updateResolution || updateLanguage) RatScannerMain.Instance.SetupRatEye(); + if (updateUiLanguage) _localizationService.SetLanguage(UiLanguage); + if (updateResolution || updateLanguage) RatScannerMain.Instance.SetupRatEye(); RatEye.Config.LogDebug = RatConfig.LogDebug; - RatScannerMain.Instance.HotkeyManager.RegisterHotkeys(); + } finally { + RatScannerMain.Instance.HotkeyManager.RegisterHotkeys(); + } // Save config to file Logger.LogInfo("Saving config..."); From 44518ea0c8e7d748937bd372e612b2c3b7ff0241 Mon Sep 17 00:00:00 2001 From: DysektAI Date: Sat, 11 Jul 2026 13:54:19 -0400 Subject: [PATCH 2/2] Harden name-scan cache lookup and marker loading Guard missing icon_search.png with a clear Logger.LogError path, reuse one Bitmap across RatEye reconfigs, make TryGetItemById cache-only and game-mode-scoped so scans never queue fetches or leak cross-mode data, and drop the dead ToolTipDuration parse on settings save. --- RatScanner/RatScannerMain.cs | 21 ++++-- RatScanner/TarkovDevAPI.cs | 15 ++++- RatScanner/ViewModel/SettingsVM.cs | 103 ++++++++++++++--------------- 3 files changed, 80 insertions(+), 59 deletions(-) diff --git a/RatScanner/RatScannerMain.cs b/RatScanner/RatScannerMain.cs index 2d9ad1dc..2aa5660e 100644 --- a/RatScanner/RatScannerMain.cs +++ b/RatScanner/RatScannerMain.cs @@ -51,6 +51,8 @@ public class RatScannerMain : INotifyPropertyChanged { internal RatEyeEngine RatEyeEngine; + private Bitmap? _searchMarker; + public event PropertyChangedEventHandler? PropertyChanged; internal ItemQueue ItemScans = new(); @@ -210,12 +212,23 @@ private RatEye.Config GetRatEyeConfig(bool highlighted = true) { }; } - private static Config.Processing.Inspection CreateInspectionConfig() { - var marker = new Bitmap(RatConfig.Paths.SearchIcon); + private Config.Processing.Inspection CreateInspectionConfig() { + if (_searchMarker == null) { + string path = RatConfig.Paths.SearchIcon; + if (!File.Exists(path)) { + Logger.LogError( + $"Search icon not found at: {path}\n\n" + + "Name scan requires Data/icon_search.png. Reinstall or update RatScanner so the full package is present."); + } + + _searchMarker = new Bitmap(path); + Logger.LogInfo($"Loaded name-scan marker {_searchMarker.Width}x{_searchMarker.Height} from {path}"); + } + // MarkerItemScale is calibrated to template width: in-game icon is ~16px at 1080p return new Config.Processing.Inspection() { - Marker = marker, - MarkerItemScale = 16f / marker.Width, + Marker = _searchMarker, + MarkerItemScale = 16f / _searchMarker.Width, }; } diff --git a/RatScanner/TarkovDevAPI.cs b/RatScanner/TarkovDevAPI.cs index dfd64199..01a6c188 100644 --- a/RatScanner/TarkovDevAPI.cs +++ b/RatScanner/TarkovDevAPI.cs @@ -325,14 +325,23 @@ await Task.WhenAll( public static Item[] GetItems() => GetCached(ItemsQueryKey(), ItemsQuery, RatConfig.MediumTTL); /// - /// Looks up an item by id in the current language cache and, if needed, in other loaded item caches. + /// Looks up an item by id in loaded caches for the current game mode (no network). + /// Prefers the active language, then other languages of the same mode. /// public static bool TryGetItemById(string id, out Item? item) { - item = GetItems().FirstOrDefault(i => i.Id == id); - if (item != null) return true; + item = null; + if (string.IsNullOrEmpty(id)) return false; + + if (Cache.TryGetValue(ItemsQueryKey(), out (long expire, object response) current) + && current.response is Item[] currentItems) { + item = currentItems.FirstOrDefault(i => i.Id == id); + if (item != null) return true; + } + string modeSuffix = $"_{RatConfig.GameMode}"; foreach (KeyValuePair entry in Cache) { if (!entry.Key.StartsWith("items_", StringComparison.Ordinal)) continue; + if (!entry.Key.EndsWith(modeSuffix, StringComparison.Ordinal)) continue; if (entry.Value.response is not Item[] items) continue; item = items.FirstOrDefault(i => i.Id == id); diff --git a/RatScanner/ViewModel/SettingsVM.cs b/RatScanner/ViewModel/SettingsVM.cs index 29e76b76..833d0e84 100644 --- a/RatScanner/ViewModel/SettingsVM.cs +++ b/RatScanner/ViewModel/SettingsVM.cs @@ -117,58 +117,57 @@ public async Task SaveSettings() { RatScannerMain.Instance.HotkeyManager.UnregisterHotkeys(); try { - // Save config - RatConfig.NameScan.Enable = EnableNameScan; - RatConfig.NameScan.EnableAuto = EnableAutoNameScan; - RatConfig.NameScan.Language = (Language)NameScanLanguage; - - RatConfig.IconScan.Enable = EnableIconScan; - RatConfig.IconScan.ScanRotatedIcons = ScanRotatedIcons; - RatConfig.IconScan.UseCachedIcons = UseCachedIcons; - RatConfig.IconScan.Hotkey = IconScanHotkey; - - RatConfig.ToolTip.Duration = int.TryParse(ToolTipDuration, out int i) ? i : 0; - RatConfig.ToolTip.Duration = ToolTipMilli; - RatConfig.UserInterface.Language = UiLanguage; - - RatConfig.MinimalUi.ShowName = ShowName; - RatConfig.MinimalUi.ShowAvgDayPrice = ShowAvgDayPrice; - RatConfig.MinimalUi.ShowPricePerSlot = ShowPricePerSlot; - RatConfig.MinimalUi.ShowTraderPrice = ShowTraderPrice; - RatConfig.MinimalUi.ShowKappa = ShowKappa; - RatConfig.MinimalUi.ShowQuestHideoutTracker = ShowQuestHideoutTracker; - RatConfig.MinimalUi.ShowQuestHideoutTeamTracker = ShowQuestHideoutTeamTracker; - RatConfig.MinimalUi.ShowUpdated = ShowUpdated; - RatConfig.MinimalUi.Opacity = Opacity; - - RatConfig.Tracking.ShowNonFIRNeeds = ShowNonFIRNeeds; - RatConfig.Tracking.ShowKappaNeeds = ShowKappaNeeds; - - RatConfig.Tracking.TarkovTracker.Token = TarkovTrackerToken.Trim(); - RatConfig.Tracking.TarkovTracker.ShowTeam = ShowTarkovTrackerTeam; - RatConfig.Tracking.TarkovTracker.Backend = TarkovTrackerBackend; - - RatConfig.Overlay.Search.Enable = EnableIneractableOverlay; - RatConfig.Overlay.Search.BlurBehind = BlurBehindSearch; - RatConfig.Overlay.Search.Hotkey = InteractableOverlayHotkey; - - RatConfig.ScreenWidth = ScreenWidth; - RatConfig.ScreenHeight = ScreenHeight; - RatConfig.ScreenScale = ScreenScale; - RatConfig.GameMode = GameMode; - RatConfig.MinimizeToTray = MinimizeToTray; - RatConfig.AlwaysOnTop = AlwaysOnTop; - RatConfig.LogDebug = LogDebug; - - // Apply config - PageSwitcher.Instance.Topmost = RatConfig.AlwaysOnTop; - PageSwitcher.Instance.ResetWindowSize(); - await TarkovDevAPI.InitializeCache(); - if (updateTarkovTrackerToken || updateTarkovTrackerBackend) UpdateTarkovTrackerToken(); - if (updateUiLanguage) _localizationService.SetLanguage(UiLanguage); - if (updateResolution || updateLanguage) RatScannerMain.Instance.SetupRatEye(); - - RatEye.Config.LogDebug = RatConfig.LogDebug; + // Save config + RatConfig.NameScan.Enable = EnableNameScan; + RatConfig.NameScan.EnableAuto = EnableAutoNameScan; + RatConfig.NameScan.Language = (Language)NameScanLanguage; + + RatConfig.IconScan.Enable = EnableIconScan; + RatConfig.IconScan.ScanRotatedIcons = ScanRotatedIcons; + RatConfig.IconScan.UseCachedIcons = UseCachedIcons; + RatConfig.IconScan.Hotkey = IconScanHotkey; + + RatConfig.ToolTip.Duration = ToolTipMilli; + RatConfig.UserInterface.Language = UiLanguage; + + RatConfig.MinimalUi.ShowName = ShowName; + RatConfig.MinimalUi.ShowAvgDayPrice = ShowAvgDayPrice; + RatConfig.MinimalUi.ShowPricePerSlot = ShowPricePerSlot; + RatConfig.MinimalUi.ShowTraderPrice = ShowTraderPrice; + RatConfig.MinimalUi.ShowKappa = ShowKappa; + RatConfig.MinimalUi.ShowQuestHideoutTracker = ShowQuestHideoutTracker; + RatConfig.MinimalUi.ShowQuestHideoutTeamTracker = ShowQuestHideoutTeamTracker; + RatConfig.MinimalUi.ShowUpdated = ShowUpdated; + RatConfig.MinimalUi.Opacity = Opacity; + + RatConfig.Tracking.ShowNonFIRNeeds = ShowNonFIRNeeds; + RatConfig.Tracking.ShowKappaNeeds = ShowKappaNeeds; + + RatConfig.Tracking.TarkovTracker.Token = TarkovTrackerToken.Trim(); + RatConfig.Tracking.TarkovTracker.ShowTeam = ShowTarkovTrackerTeam; + RatConfig.Tracking.TarkovTracker.Backend = TarkovTrackerBackend; + + RatConfig.Overlay.Search.Enable = EnableIneractableOverlay; + RatConfig.Overlay.Search.BlurBehind = BlurBehindSearch; + RatConfig.Overlay.Search.Hotkey = InteractableOverlayHotkey; + + RatConfig.ScreenWidth = ScreenWidth; + RatConfig.ScreenHeight = ScreenHeight; + RatConfig.ScreenScale = ScreenScale; + RatConfig.GameMode = GameMode; + RatConfig.MinimizeToTray = MinimizeToTray; + RatConfig.AlwaysOnTop = AlwaysOnTop; + RatConfig.LogDebug = LogDebug; + + // Apply config + PageSwitcher.Instance.Topmost = RatConfig.AlwaysOnTop; + PageSwitcher.Instance.ResetWindowSize(); + await TarkovDevAPI.InitializeCache(); + if (updateTarkovTrackerToken || updateTarkovTrackerBackend) UpdateTarkovTrackerToken(); + if (updateUiLanguage) _localizationService.SetLanguage(UiLanguage); + if (updateResolution || updateLanguage) RatScannerMain.Instance.SetupRatEye(); + + RatEye.Config.LogDebug = RatConfig.LogDebug; } finally { RatScannerMain.Instance.HotkeyManager.RegisterHotkeys(); }