From 4416690860ef576fdf86f4c978aad2b62919fea2 Mon Sep 17 00:00:00 2001 From: abstract6217 <265506766+abstract6217@users.noreply.github.com> Date: Thu, 18 Jun 2026 19:33:30 -0500 Subject: [PATCH] Add adaptive PvP settings profile --- Core/Optimizer.cs | 105 ++++++++++++++++++++++++++++++- Core/RustConfig.cs | 39 +++++++++++- Core/RustKeyConfig.cs | 61 ++++++++++++++++++ Core/UserConfigs.cs | 19 +++++- Helpers/HardwareDetector.cs | 79 +++++++++++++++++++++++ Helpers/TrayHandler.cs | 2 + MainFrm.Designer.cs | 14 ++++- MainFrm.cs | 122 +++++++++++++++++++++++++----------- README.md | 2 + 9 files changed, 399 insertions(+), 44 deletions(-) create mode 100644 Core/RustKeyConfig.cs diff --git a/Core/Optimizer.cs b/Core/Optimizer.cs index a23a10c..c93b71a 100644 --- a/Core/Optimizer.cs +++ b/Core/Optimizer.cs @@ -12,6 +12,8 @@ namespace RustOptimizer.Core { public static class Optimizer { + public const string PvpGuideProfileName = "PvP (Steam Guide 2026)"; + [DllImport("advapi32.dll", SetLastError = true)] private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle); @@ -49,6 +51,12 @@ public static Dictionary GetOptimalSettings(string profile) { var settings = new Dictionary(); + if (profile == PvpGuideProfileName) + { + ApplyPvpGuideSettings(settings); + return settings; + } + // Universal Settings for all profiles settings.Add("graphics.vsync", "False"); settings.Add("client.headbob", "False"); @@ -154,6 +162,101 @@ public static Dictionary GetOptimalSettings(string profile) } return settings; } + + private static void ApplyPvpGuideSettings(Dictionary settings) + { + var displayMode = HardwareDetector.GetPrimaryDisplayMode(); + + // Rust-only values shown in the guide. GPU control-panel and Windows tweaks + // are intentionally excluded from this profile. + settings["graphics.fov"] = "90"; + settings["client.headbob"] = "False"; + settings["client.crosshair"] = "True"; + settings["client.hitcross"] = "True"; + settings["gametip.showgametips"] = "False"; + settings["client.hurtpunch"] = "False"; + settings["effects.maxgibs"] = "1"; + settings["rgbeffects.enabled"] = "False"; + settings["rgbeffects.brightness"] = "0"; + + settings["fps.limit"] = displayMode.RefreshRate.ToString(); + settings["graphics.vsync"] = "False"; + settings["fps.limitinmenu"] = "True"; + settings["fps.limitinbackground"] = "True"; + + settings["graphics.renderscale"] = "1"; + settings["graphics.shaderlod"] = "200"; + settings["graphics.drawdistance"] = "1000"; + settings["water.reflections"] = "2"; + settings["water.quality"] = "0"; + settings["graphics.grassshadows"] = "False"; + settings["grass.displacement"] = "True"; + settings["graphics.af"] = "1"; + settings["graphics.parallax"] = "0"; + + settings["graphics.shadowquality"] = "0"; + settings["graphics.shadowmode"] = "1"; + settings["graphics.shadowcascades"] = "0"; + settings["graphics.shadowdistance"] = "0"; + settings["graphics.shadowlights"] = "0"; + + settings["decor.quality"] = "0"; + settings["grass.quality"] = "0"; + settings["terrain.quality"] = "0"; + settings["tree.meshes"] = "10"; + settings["tree.quality"] = "100"; + settings["mesh.quality"] = "100"; + settings["graphics.lodbias"] = "1"; + settings["particle.quality"] = "0"; + + if (HardwareDetector.IsNvidiaGpu()) + { + settings["graphics.dlss"] = "2"; + settings["effects.antialiasing"] = "0"; + } + else + { + settings["graphics.dlss"] = "-1"; + settings["effects.antialiasing"] = "3"; + } + settings["effects.bloom"] = "False"; + settings["effects.ao"] = "False"; + settings["effects.sharpen"] = "True"; + settings["effects.vignet"] = "False"; + settings["graphics.dof"] = "False"; + settings["effects.lensdirt"] = "False"; + settings["effects.motionblur"] = "False"; + settings["effects.shafts"] = "False"; + settings["global.showblood"] = "False"; + + settings["culling.env"] = "False"; + settings["graphics.contactshadows"] = "False"; + settings["gc.buffer"] = "4085"; + } + + public static Dictionary GetPvpGuideShortcuts() + { + return new Dictionary + { + ["graphics.vm_fov_scale"] = "False", + ["graphics.vm_horizontal_flip"] = "True", + ["client.clampscreenshake"] = "True", + ["hitnotify.notification_level"] = "2", + ["legs.enablelegs"] = "0", + ["effects.showoutlines"] = "True" + }; + } + + public static Dictionary GetPvpGuideBindings() + { + return new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["c"] = "+graphics.fov 90;graphics.fov 70", + ["f1"] = "client.consoletoggle;combatlog;client.ping", + ["l"] = "~meta.exec \"client.lookatradius 0\" \"chat.add 0 0 MIN\";meta.exec \"client.lookatradius 0.2\" \"chat.add 0 0 DEFAULT\";meta.exec \"client.lookatradius 10\" \"chat.add 0 0 MAX\"", + ["y"] = "forward;sprint" + }; + } /// /// Plays a Toilet Flush sound /// @@ -351,4 +454,4 @@ public static void SetPriority(bool high) } } } -} \ No newline at end of file +} diff --git a/Core/RustConfig.cs b/Core/RustConfig.cs index 9c8b555..3cd7105 100644 --- a/Core/RustConfig.cs +++ b/Core/RustConfig.cs @@ -19,6 +19,8 @@ public class RustConfig /// public void LoadSettings(string filePath) { + settings.Clear(); + if (File.Exists(filePath)) { foreach (string line in File.ReadAllLines(filePath)) @@ -28,11 +30,27 @@ public void LoadSettings(string filePath) continue; } - string[] parts = line.Split(new char[] { ' ' }, 2); + string[] parts = line.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 2) { string key = parts[0].Trim(); - string value = parts[1].Trim().Trim('"'); + string value = parts[1].Trim(); + + // Bind entries have a second key component (for example, "input.bind c"). + // Keeping it in the dictionary key prevents different binds overwriting each other. + if (key.Equals("input.bind", StringComparison.OrdinalIgnoreCase)) + { + string[] bindParts = value.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); + if (bindParts.Length != 2) + { + continue; + } + + key = $"{key} {bindParts[0]}"; + value = bindParts[1]; + } + + value = Unquote(value); settings[key] = value; } } @@ -53,10 +71,25 @@ public void SaveSettings(string filePath) { foreach (var kvp in settings) { - writer.WriteLine($"{kvp.Key} \"{kvp.Value}\""); + writer.WriteLine($"{kvp.Key} \"{EscapeValue(kvp.Value)}\""); } } } + + private static string Unquote(string value) + { + if (value.Length >= 2 && value[0] == '"' && value[^1] == '"') + { + value = value.Substring(1, value.Length - 2); + } + + return value.Replace("\\\"", "\""); + } + + private static string EscapeValue(string value) + { + return value.Replace("\"", "\\\""); + } /// /// Tries to get a specific setting from the loaded settings. /// diff --git a/Core/RustKeyConfig.cs b/Core/RustKeyConfig.cs new file mode 100644 index 0000000..bdc67e7 --- /dev/null +++ b/Core/RustKeyConfig.cs @@ -0,0 +1,61 @@ +namespace RustOptimizer.Core +{ + public static class RustKeyConfig + { + public static void ApplyBindings(string filePath, IReadOnlyDictionary bindings) + { + string? directory = Path.GetDirectoryName(filePath); + if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory)) + { + throw new DirectoryNotFoundException($"Rust config directory was not found: {directory}"); + } + + List lines = File.Exists(filePath) + ? File.ReadAllLines(filePath).ToList() + : new List(); + + Dictionary bindingLines = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < lines.Count; i++) + { + if (TryGetBindingKey(lines[i], out string key)) + { + bindingLines[key] = i; + } + } + + foreach (var binding in bindings) + { + string line = $"bind {binding.Key.ToLowerInvariant()} {binding.Value}"; + if (bindingLines.TryGetValue(binding.Key, out int lineIndex)) + { + lines[lineIndex] = line; + } + else + { + bindingLines[binding.Key] = lines.Count; + lines.Add(line); + } + } + + if (File.Exists(filePath)) + { + File.Copy(filePath, filePath + ".bak", true); + } + + File.WriteAllLines(filePath, lines); + } + + private static bool TryGetBindingKey(string line, out string key) + { + key = string.Empty; + string[] parts = line.Trim().Split(new char[] { ' ' }, 3, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 3 || !parts[0].Equals("bind", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + key = parts[1]; + return true; + } + } +} diff --git a/Core/UserConfigs.cs b/Core/UserConfigs.cs index 4a3b59e..c9720af 100644 --- a/Core/UserConfigs.cs +++ b/Core/UserConfigs.cs @@ -7,14 +7,26 @@ public static class UserConfigs { public static string ConfigPath { get; private set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Rust Optimizer", "User", "UserCFG.ini"); public static string BackupsPath { get; set; } = Path.Combine(Application.StartupPath, "backups"); - public static string GamePath { get; set; } = MainFrm.Instance.gamePathString.Text; + public static string GamePath { get; set; } = string.Empty; public static string ?SavedProfile { get; set; } = null; public static bool AutoFlushEnabled { get; set; } = false; public static bool AutoFlushSfx { get; set; } = false; public static int AutoFlushInterval { get; set; } = 15; public static string AutoFlushUnit { get; set; } = "Minutes"; public static bool CPUHighPriority { get; set; } = false; - public static string GameConfigPath { get; set; } = Path.Combine(MainFrm.Instance.gamePathString.Text, "cfg", "client.cfg"); + public static bool PvpGuideShortcuts { get; set; } = false; + public static string GameConfigPath => GetGameConfigPath(GamePath); + public static string KeysConfigPath => GetKeysConfigPath(GamePath); + + public static string GetGameConfigPath(string gamePath) + { + return Path.Combine(gamePath ?? string.Empty, "cfg", "client.cfg"); + } + + public static string GetKeysConfigPath(string gamePath) + { + return Path.Combine(gamePath ?? string.Empty, "cfg", "keys.cfg"); + } /// /// Loads, and refreshes Global Settings. @@ -32,7 +44,8 @@ public static void Refresh() AutoFlushInterval = ini.GetInteger("AppSettings", "FlushInterval", 15); AutoFlushUnit = ini.ReadValue("AppSettings", "FlushUnit", "Minutes"); CPUHighPriority = ini.GetBoolean("AppSettings", "CPUHighPriority", false); + PvpGuideShortcuts = ini.GetBoolean("AppSettings", "PvpGuideShortcuts", false); } } -} \ No newline at end of file +} diff --git a/Helpers/HardwareDetector.cs b/Helpers/HardwareDetector.cs index c0215dd..1b5e1b8 100644 --- a/Helpers/HardwareDetector.cs +++ b/Helpers/HardwareDetector.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Management; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -12,6 +13,84 @@ namespace RustOptimizer.Helpers { public static class HardwareDetector { + private const int EnumCurrentSettings = -1; + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + private static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DevMode devMode); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct DevMode + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string DeviceName; + public ushort SpecVersion; + public ushort DriverVersion; + public ushort Size; + public ushort DriverExtra; + public uint Fields; + public int PositionX; + public int PositionY; + public uint DisplayOrientation; + public uint DisplayFixedOutput; + public short Color; + public short Duplex; + public short YResolution; + public short TTOption; + public short Collate; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string FormName; + public ushort LogPixels; + public uint BitsPerPixel; + public uint PelsWidth; + public uint PelsHeight; + public uint DisplayFlags; + public uint DisplayFrequency; + public uint ICMMethod; + public uint ICMIntent; + public uint MediaType; + public uint DitherType; + public uint Reserved1; + public uint Reserved2; + public uint PanningWidth; + public uint PanningHeight; + } + + public static (int Width, int Height, int RefreshRate) GetPrimaryDisplayMode() + { + Screen? primaryScreen = Screen.PrimaryScreen; + int width = primaryScreen?.Bounds.Width ?? 1920; + int height = primaryScreen?.Bounds.Height ?? 1080; + int refreshRate = 60; + + if (primaryScreen == null) + { + return (width, height, refreshRate); + } + + DevMode mode = new DevMode + { + DeviceName = string.Empty, + FormName = string.Empty, + Size = (ushort)Marshal.SizeOf() + }; + + if (EnumDisplaySettings(primaryScreen.DeviceName, EnumCurrentSettings, ref mode)) + { + width = mode.PelsWidth > 0 ? (int)mode.PelsWidth : width; + height = mode.PelsHeight > 0 ? (int)mode.PelsHeight : height; + refreshRate = mode.DisplayFrequency > 1 ? (int)mode.DisplayFrequency : refreshRate; + } + + return (width, height, refreshRate); + } + + public static bool IsNvidiaGpu() + { + string gpuName = GetGpuName(); + return gpuName.Contains("NVIDIA", StringComparison.OrdinalIgnoreCase) + || gpuName.Contains("GeForce", StringComparison.OrdinalIgnoreCase); + } + /// /// Grabs the name of the CPU from your system info. /// diff --git a/Helpers/TrayHandler.cs b/Helpers/TrayHandler.cs index b7f1506..4fab66e 100644 --- a/Helpers/TrayHandler.cs +++ b/Helpers/TrayHandler.cs @@ -45,10 +45,12 @@ public static void LaunchRust() try { + var displayMode = HardwareDetector.GetPrimaryDisplayMode(); Process.Start(new ProcessStartInfo { FileName = rustExe, WorkingDirectory = rustPath, + Arguments = $"-screen-width {displayMode.Width} -screen-height {displayMode.Height} -screen-fullscreen 1", UseShellExecute = true }); } diff --git a/MainFrm.Designer.cs b/MainFrm.Designer.cs index d9c7100..3fce88e 100644 --- a/MainFrm.Designer.cs +++ b/MainFrm.Designer.cs @@ -76,6 +76,7 @@ private void InitializeComponent() tabPage2 = new TabPage(); nsLabel10 = new GUI.NSLabel(); highPriority = new GUI.NSCheckBox(); + pvpGuideShortcuts = new GUI.NSCheckBox(); tabPage1 = new TabPage(); nsLabel7 = new GUI.NSLabel(); autoFlushChk = new GUI.NSCheckBox(); @@ -299,7 +300,7 @@ private void InitializeComponent() profileDropdown.DropDownStyle = ComboBoxStyle.DropDownList; profileDropdown.ForeColor = Color.White; profileDropdown.FormattingEnabled = true; - profileDropdown.Items.AddRange(new object[] { "Competitive (Max FPS)", "Balanced (Good-looking & Fast)", "Recommended (Optimized)", "Ultra (Maximum Visuals)" }); + profileDropdown.Items.AddRange(new object[] { "Competitive (Max FPS)", "PvP (Steam Guide 2026)", "Balanced (Good-looking & Fast)", "Recommended (Optimized)", "Ultra (Maximum Visuals)" }); profileDropdown.Location = new Point(71, 54); profileDropdown.Name = "profileDropdown"; profileDropdown.Size = new Size(224, 24); @@ -526,6 +527,7 @@ private void InitializeComponent() // tabPage2 // tabPage2.BackColor = Color.FromArgb(0, 0, 0); + tabPage2.Controls.Add(pvpGuideShortcuts); tabPage2.Controls.Add(nsLabel10); tabPage2.Controls.Add(highPriority); tabPage2.Location = new Point(119, 4); @@ -554,6 +556,15 @@ private void InitializeComponent() highPriority.Size = new Size(120, 23); highPriority.TabIndex = 13; highPriority.Text = "Enable/Disable"; + // + // pvpGuideShortcuts + // + pvpGuideShortcuts.Checked = false; + pvpGuideShortcuts.Location = new Point(6, 42); + pvpGuideShortcuts.Name = "pvpGuideShortcuts"; + pvpGuideShortcuts.Size = new Size(260, 23); + pvpGuideShortcuts.TabIndex = 15; + pvpGuideShortcuts.Text = "Enable guide in-game shortcuts"; // // tabPage1 // @@ -787,6 +798,7 @@ private void InitializeComponent() public GUI.NSCheckBox autoFlushChk; private GUI.NSLabel nsLabel10; public GUI.NSCheckBox highPriority; + private GUI.NSCheckBox pvpGuideShortcuts; private ToolStripMenuItem minimizeToTrayToolStripMenuItem; private GUI.NSButton launchRustBtn; private GUI.NSTabControl nsTabControl1; diff --git a/MainFrm.cs b/MainFrm.cs index 448ac74..b97566f 100644 --- a/MainFrm.cs +++ b/MainFrm.cs @@ -8,7 +8,9 @@ namespace RustOptimizer public partial class MainFrm : Form { public static MainFrm Instance { get; private set; } - private RustConfig rustConfig = new RustConfig(); + private RustConfig rustConfig = new RustConfig(); + private string CurrentGameConfigPath => UserConfigs.GetGameConfigPath(gamePathString.Text.Trim()); + private string CurrentKeysConfigPath => UserConfigs.GetKeysConfigPath(gamePathString.Text.Trim()); public System.Windows.Forms.Timer autoFlushTimer; public NotifyIcon sysTrayIcon; public MainFrm() @@ -71,9 +73,10 @@ private void MainFrm_Load(object sender, EventArgs e) autoFlushMinHour.Text = "Minutes"; } - autoFlushChk.Checked = UserConfigs.AutoFlushEnabled; - highPriority.Checked = UserConfigs.CPUHighPriority; - Optimizer.SetPriority(UserConfigs.CPUHighPriority); + autoFlushChk.Checked = UserConfigs.AutoFlushEnabled; + highPriority.Checked = UserConfigs.CPUHighPriority; + pvpGuideShortcuts.Checked = UserConfigs.PvpGuideShortcuts; + Optimizer.SetPriority(UserConfigs.CPUHighPriority); autoFlushSound.Checked = UserConfigs.AutoFlushSfx; if (autoFlushChk.Checked && !Optimizer.IsAdministrator()) @@ -210,38 +213,84 @@ private void exitToolStripMenuItem1_Click(object sender, EventArgs e) /// The main button that applies the optimization profile to the game's client.cfg file. /// It first loads the current settings, updates them with the new profile, and saves the file. /// - private void optimizeBtn_Click(object sender, EventArgs e) - { - if (string.IsNullOrEmpty(gamePathString.Text) || !Directory.Exists(gamePathString.Text)) - { - MessageBox.Show("Please select a valid game path first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - string profile = profileDropdown.SelectedItem?.ToString(); - if (string.IsNullOrEmpty(profile)) - { + private void optimizeBtn_Click(object sender, EventArgs e) + { + string gamePath = gamePathString.Text.Trim(); + if (string.IsNullOrEmpty(gamePath) || !Directory.Exists(gamePath)) + { + MessageBox.Show("Please select a valid game path first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + if (Process.GetProcessesByName("RustClient").Length > 0 || Process.GetProcessesByName("Rust").Length > 0) + { + MessageBox.Show( + "Close Rust before applying a profile so the game does not overwrite client.cfg or keys.cfg.", + "Rust Is Running", + MessageBoxButtons.OK, + MessageBoxIcon.Warning); + return; + } + + string clientConfigPath = UserConfigs.GetGameConfigPath(gamePath); + if (!File.Exists(clientConfigPath)) + { + MessageBox.Show( + $"Rust's client.cfg was not found at:\n{clientConfigPath}\n\nSelect the main Rust installation folder, not the folder containing RustOptimizer.exe.", + "Rust Config Not Found", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + return; + } + + string profile = profileDropdown.SelectedItem?.ToString(); + if (string.IsNullOrEmpty(profile)) + { MessageBox.Show("Please select an optimization profile first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - rustConfig.LoadSettings(UserConfigs.GameConfigPath); - - var optimalSettings = Optimizer.GetOptimalSettings(profile); - - foreach (var setting in optimalSettings) - { - rustConfig.SetSetting(setting.Key, setting.Value); - } - - rustConfig.SaveSettings(UserConfigs.GameConfigPath); - MessageBox.Show($"'{profile}' profile applied successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + try + { + rustConfig.LoadSettings(clientConfigPath); + + var optimalSettings = Optimizer.GetOptimalSettings(profile); + foreach (var setting in optimalSettings) + { + rustConfig.SetSetting(setting.Key, setting.Value); + } + + if (pvpGuideShortcuts.Checked) + { + foreach (var shortcut in Optimizer.GetPvpGuideShortcuts()) + { + rustConfig.SetSetting(shortcut.Key, shortcut.Value); + } + } + + rustConfig.SaveSettings(clientConfigPath); + + if (pvpGuideShortcuts.Checked) + { + RustKeyConfig.ApplyBindings(CurrentKeysConfigPath, Optimizer.GetPvpGuideBindings()); + } + + UserConfigs.GamePath = gamePath; + string shortcutStatus = pvpGuideShortcuts.Checked ? " Guide shortcuts were also enabled." : string.Empty; + MessageBox.Show($"'{profile}' profile applied successfully!{shortcutStatus}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + ExceptionHandler.LogError(ex); + MessageBox.Show($"Unable to apply the profile:\n{ex.Message}", "Optimization Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } /// /// Creates a backup of the current client.cfg file, named with a timestamp, and adds it to the list. /// private void saveBackupBtn_Click(object sender, EventArgs e) { - if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(UserConfigs.GameConfigPath)) + if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(CurrentGameConfigPath)) { MessageBox.Show("Please select a valid game path first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -251,7 +300,7 @@ private void saveBackupBtn_Click(object sender, EventArgs e) string newBackupPath = Path.Combine(UserConfigs.BackupsPath, backupFolder); Directory.CreateDirectory(newBackupPath); - rustConfig.LoadSettings(UserConfigs.GameConfigPath); + rustConfig.LoadSettings(CurrentGameConfigPath); rustConfig.SaveSettings(Path.Combine(newBackupPath, "client.cfg")); MessageBox.Show("Settings backup saved successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadBackups(); @@ -282,7 +331,7 @@ private void restoreBackupBtn_Click(object sender, EventArgs e) return; } - File.Copy(backupConfigPath, UserConfigs.GameConfigPath, true); + File.Copy(backupConfigPath, CurrentGameConfigPath, true); MessageBox.Show("Settings restored successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } /// @@ -324,7 +373,7 @@ private void restoreBackupToolStripMenuItem_Click(object sender, EventArgs e) try { - File.Copy(backupConfigPath, UserConfigs.GameConfigPath, true); + File.Copy(backupConfigPath, CurrentGameConfigPath, true); MessageBox.Show("Settings restored successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) @@ -340,7 +389,7 @@ private void restoreBackupToolStripMenuItem_Click(object sender, EventArgs e) /// private void saveToolStripMenuItem_Click(object sender, EventArgs e) { - if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(UserConfigs.GameConfigPath)) + if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(CurrentGameConfigPath)) { MessageBox.Show("Please select a valid game path first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -348,7 +397,7 @@ private void saveToolStripMenuItem_Click(object sender, EventArgs e) string backupFolder = "Backup-" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture); string newBackupPath = Path.Combine(UserConfigs.BackupsPath, backupFolder); Directory.CreateDirectory(newBackupPath); - File.Copy(UserConfigs.GameConfigPath, Path.Combine(newBackupPath, "client.cfg")); + File.Copy(CurrentGameConfigPath, Path.Combine(newBackupPath, "client.cfg")); MessageBox.Show("Settings backup saved successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadBackups(); } @@ -393,7 +442,7 @@ private void defaultSettingsToolStripMenuItem_Click(object sender, EventArgs e) try { - Helpers.EmbedResources.SaveToDisk("client.cfg", UserConfigs.GameConfigPath); + Helpers.EmbedResources.SaveToDisk("client.cfg", CurrentGameConfigPath); MessageBox.Show("Default settings restored successfully! Restart your game for changes to take effect.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) @@ -469,7 +518,7 @@ private void aboutToolStripMenuItem1_Click(object sender, EventArgs e) /// private void exportProfileToolStripMenuItem_Click(object sender, EventArgs e) { - if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(UserConfigs.GameConfigPath)) + if (string.IsNullOrEmpty(gamePathString.Text) || !File.Exists(CurrentGameConfigPath)) { MessageBox.Show("Please select a valid game path first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; @@ -485,7 +534,7 @@ private void exportProfileToolStripMenuItem_Click(object sender, EventArgs e) { try { - File.Copy(UserConfigs.GameConfigPath, sfd.FileName, true); + File.Copy(CurrentGameConfigPath, sfd.FileName, true); MessageBox.Show("Profile exported successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) @@ -516,7 +565,7 @@ private void importProfileToolStripMenuItem_Click(object sender, EventArgs e) { try { - File.Copy(ofd.FileName, UserConfigs.GameConfigPath, true); + File.Copy(ofd.FileName, CurrentGameConfigPath, true); MessageBox.Show("Profile imported successfully! Restart your game for changes to take effect.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); var result = MessageBox.Show("Would you like to save this imported profile as a new backup?", "Save as Backup", MessageBoxButtons.YesNo, MessageBoxIcon.Question); @@ -549,7 +598,8 @@ private void saveAdvancedCfgBtn_Click(object sender, EventArgs e) ini.WriteValue("AppSettings", "FlushInterval", autoFlushinterval.Value.ToString(CultureInfo.InvariantCulture), ini.Path); ini.WriteValue("AppSettings", "FlushUnit", autoFlushMinHour.Text, ini.Path); ini.WriteValue("AppSettings", "FlushSound", autoFlushSound.Checked.ToString(CultureInfo.InvariantCulture), ini.Path); - ini.WriteValue("AppSettings", "CPUHighPriority", highPriority.Checked.ToString(CultureInfo.InvariantCulture), ini.Path); + ini.WriteValue("AppSettings", "CPUHighPriority", highPriority.Checked.ToString(CultureInfo.InvariantCulture), ini.Path); + ini.WriteValue("AppSettings", "PvpGuideShortcuts", pvpGuideShortcuts.Checked.ToString(CultureInfo.InvariantCulture), ini.Path); UserConfigs.Refresh(); Optimizer.InitializeAutoFlushTimer(); Optimizer.SetPriority(highPriority.Checked); diff --git a/README.md b/README.md index ede163d..7afbf0b 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,13 @@ * **Hardware Auto-Detection:** Automatically detects your CPU, GPU, and RAM to recommend an optimal profile for your system. * **Optimization Profiles:** Choose from a list of pre-configured settings tailored for different goals: * **Competitive (Maximum FPS):** Strips down visuals for the highest possible frame rates. + * **PvP (Steam Guide 2026):** Applies the Rust-only visibility and performance settings from the [PvP settings guide](https://steamcommunity.com/sharedfiles/filedetails/?id=3288259810). It uses the primary monitor's active resolution and refresh rate, and enables DLSS Max Quality with anti-aliasing disabled on NVIDIA GPUs. AMD control-panel and Windows tweaks are not included. * **Balanced (Good Performance & Looks):** A great mix of graphical fidelity and performance. * **Recommended (Optimized):** The ideal settings for your specific hardware. * **Ultra (Maximum Visuals):** Pushes graphics to the limit for a stunning experience. * **Import & Export Custom Profiles:** Save your current game settings to a shareable file (.rop) or import a profile from a friend to use their setup. * **Easy Configuration:** Select your game folder and apply your chosen profile with a single button click. +* **Optional PvP Shortcuts:** Enable the guide's in-game zoom, weapon-view, combat log, look-radius, visibility, and auto-run commands when applying a profile. * **Backup & Restore:** Create backups of your current `client.cfg` file before making changes, so you can easily revert to your original settings at any time. You can also manually restore backups or load the default settings. * **User-Friendly Interface:** The simple and intuitive interface makes it easy for anyone to optimize their game without needing to manually edit configuration files. * **Discord Support:** Get direct support and connect with the community by joining the official Discord server.