Initial commit: SpdUp Windows Gaming Booster v1.0.0
- .NET 8 WPF app with full MVVM architecture - One-click boost: CPU, RAM, GPU, network, services, timer resolution - Real-time system monitor (LibreHardwareMonitor) - Auto game detection (30+ games) - RAM optimizer with kernel-level cleanup - Network optimizer (TCP registry tweaks) - Service manager, process manager, shader cache cleaner - Desktop widget overlay - Debug log viewer - Custom dark gaming theme with trans pride colors - 84 unit tests (xUnit) - Inno Setup installer script - Landing page website
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
using System.Diagnostics;
|
||||
using System.ServiceProcess;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Models;
|
||||
|
||||
namespace SpdUp.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Manages the full boost lifecycle: activate → monitor → restore.
|
||||
/// </summary>
|
||||
public sealed class OptimizationService
|
||||
{
|
||||
private readonly RamOptimizationService _ramService = new();
|
||||
private readonly AppSettings _settings;
|
||||
|
||||
private readonly List<string> _stoppedServices = new();
|
||||
private uint _previousTimerResolution;
|
||||
private bool _timerResolutionChanged;
|
||||
private string? _boostedProcessName;
|
||||
private bool _isBoosted;
|
||||
|
||||
public bool IsBoosted => _isBoosted;
|
||||
public string? BoostedProcessName => _boostedProcessName;
|
||||
|
||||
public event Action<string>? BoostActivated;
|
||||
public event Action? BoostDeactivated;
|
||||
|
||||
public OptimizationService(AppSettings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate all boost optimizations. Thread-safe.
|
||||
/// </summary>
|
||||
public async Task<BoostResult> ActivateBoostAsync(string? gameProcessName = null)
|
||||
{
|
||||
if (_isBoosted) return new BoostResult(false, "Boost is already active.");
|
||||
|
||||
var messages = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Enable required privileges
|
||||
NativeMethods.EnablePrivilege(NativeMethods.SE_DEBUG_NAME);
|
||||
NativeMethods.EnablePrivilege(NativeMethods.SE_INC_BASE_PRIORITY_NAME);
|
||||
NativeMethods.EnablePrivilege(NativeMethods.SE_PROF_SINGLE_PROCESS_NAME);
|
||||
|
||||
// 2. RAM Cleanup
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var result = _ramService.FullCleanup();
|
||||
messages.Add($"RAM: trimmed {result.TrimmedCount} processes, standby purge {(result.StandbyPurged > 0 ? "OK" : "skipped")}.");
|
||||
});
|
||||
|
||||
// 3. Stop non-critical services
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (var svcName in _settings.ServicesToStop)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var sc = new ServiceController(svcName);
|
||||
if (sc.Status == ServiceControllerStatus.Running)
|
||||
{
|
||||
sc.Stop();
|
||||
_stoppedServices.Add(svcName);
|
||||
messages.Add($"Stopped service: {sc.DisplayName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warn($"Could not stop {svcName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Set game to HIGH priority
|
||||
if (!string.IsNullOrEmpty(gameProcessName))
|
||||
{
|
||||
_boostedProcessName = gameProcessName;
|
||||
await Task.Run(() => SetProcessPriority(gameProcessName, ProcessPriorityClass.High));
|
||||
messages.Add($"Set {gameProcessName} to HIGH priority.");
|
||||
}
|
||||
|
||||
// 5. Reduce timer resolution (0.5 ms)
|
||||
await Task.Run(() =>
|
||||
{
|
||||
NativeMethods.NtQueryTimerResolution(out _, out _, out _previousTimerResolution);
|
||||
int status = NativeMethods.NtSetTimerResolution(5000, true, out _);
|
||||
_timerResolutionChanged = status == 0;
|
||||
if (_timerResolutionChanged)
|
||||
messages.Add("Timer resolution set to 0.5 ms.");
|
||||
});
|
||||
|
||||
_isBoosted = true;
|
||||
BoostActivated?.Invoke(string.Join("\n", messages));
|
||||
Logger.Info("Boost activated: " + string.Join(" | ", messages));
|
||||
|
||||
return new BoostResult(true, string.Join("\n", messages));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Boost activation failed", ex);
|
||||
return new BoostResult(false, $"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore all changes made during boost.
|
||||
/// </summary>
|
||||
public async Task DeactivateBoostAsync()
|
||||
{
|
||||
if (!_isBoosted) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Restore timer resolution
|
||||
if (_timerResolutionChanged)
|
||||
{
|
||||
NativeMethods.NtSetTimerResolution(_previousTimerResolution, true, out _);
|
||||
_timerResolutionChanged = false;
|
||||
Logger.Info("Timer resolution restored.");
|
||||
}
|
||||
|
||||
// 2. Restart stopped services
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (var svcName in _stoppedServices)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var sc = new ServiceController(svcName);
|
||||
if (sc.Status == ServiceControllerStatus.Stopped)
|
||||
{
|
||||
sc.Start();
|
||||
Logger.Info($"Restarted service: {sc.DisplayName}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warn($"Could not restart {svcName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
_stoppedServices.Clear();
|
||||
});
|
||||
|
||||
// 3. Restore process priority
|
||||
if (_boostedProcessName is not null)
|
||||
{
|
||||
await Task.Run(() => SetProcessPriority(_boostedProcessName, ProcessPriorityClass.Normal));
|
||||
_boostedProcessName = null;
|
||||
}
|
||||
|
||||
_isBoosted = false;
|
||||
BoostDeactivated?.Invoke();
|
||||
Logger.Info("Boost deactivated – all settings restored.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error("Boost deactivation error", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set priority class for a process by name.
|
||||
/// </summary>
|
||||
public static void SetProcessPriority(string processName, ProcessPriorityClass priority)
|
||||
{
|
||||
foreach (var proc in Process.GetProcessesByName(processName))
|
||||
{
|
||||
try
|
||||
{
|
||||
proc.PriorityClass = priority;
|
||||
Logger.Info($"Set {processName} (PID {proc.Id}) priority to {priority}.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warn($"Cannot set priority for {processName}: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
proc.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Kill a process by PID.
|
||||
/// </summary>
|
||||
public static bool KillProcess(int pid)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var proc = Process.GetProcessById(pid);
|
||||
proc.Kill(entireProcessTree: true);
|
||||
Logger.Info($"Killed process {proc.ProcessName} (PID {pid}).");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"Failed to kill PID {pid}", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record BoostResult(bool Success, string Message);
|
||||
Reference in New Issue
Block a user