Files
SpdUp/Services/OptimizationService.cs
Phil-icyou 19ba425e79 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
2026-03-08 17:34:45 +01:00

209 lines
6.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);