Skip to main content

optiscaler-client-integration

Expert guidance for integrating OptiScaler Client, a C# Windows application that manages AI upscaling (DLSS/FSR/XeSS) and frame generation mods for games

インストールへ移動

ソース情報

リポジトリ
reason-machines/devtools-skills
ソースの最終更新活動
2026年6月1日 07:57
検出された SKILL.md の言語
英語
スター
4
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
optiscaler-client-integration
description
Expert guidance for integrating OptiScaler Client, a C# Windows application that manages AI upscaling (DLSS/FSR/XeSS) and frame generation mods for games
triggers
["how do I use optiscaler client","integrate optiscaler with my game manager","add optiscaler functionality to my app","work with optiscaler client codebase","understand optiscaler client architecture","build features for optiscaler client","contribute to optiscaler client","extend optiscaler client functionality"]
# OptiScaler Client Integration > Skill by [ara.so](https://ara.so) — Devtools Skills collection. OptiScaler Client is a C# Windows application that automates the installation and management of AI upscaling technologies (DLSS, FSR, XeSS) and frame generation mods for games. It scans game libraries across multiple platforms (Steam, Epic, GOG, etc.), downloads necessary components, and manages configuration profiles. ## Project Overview **Repository**: `optiscalerclient/optiscaler-client` **Language**: C# (WPF/Windows Forms) **License**: MIT (note: README mentions GPL v3, but metadata shows MIT) **Platform**: Windows 10/11 (with limited Linux Steam support) ### Core Capabilities - Multi-platform game library scanning (Steam, Epic, GOG, EA, Ubisoft, Battle.net, Xbox) - Automatic download and installation of OptiScaler, Fakenvapi, and frame generation mods - Profile-based INI configuration management - DLL injection method selection (dxgi, winmm, d3d12, etc.) - GPU detection and component selection logic - Backup/restore system for game files - Localization support (14 languages) ## Installation & Setup ### For Users 1. Download from releases: ``` https://github.com/optiscalerclient/optiscaler-client/releases/download/Optiscaler/optiscaler-client.zip ``` 2. Extract and run `OptiscalerClient.exe` (self-contained, no .NET runtime needed) ### For Developers ```bash # Clone repository git clone https://github.com/optiscalerclient/optiscaler-client.git cd optiscaler-client # Open in Visual Studio or Rider # Build configuration: .NET (likely .NET 6/7/8 based on modern C# features) ``` ## Architecture Patterns ### Game Discovery System The scanner system likely uses multiple provider classes: ```csharp // Example scanner interface pattern public interface IGameScanner { Task<List<GameEntry>> ScanAsync(CancellationToken cancellationToken); string PlatformName { get; } bool IsEnabled { get; set; } } // Steam scanner example public class SteamScanner : IGameScanner { public string PlatformName => "Steam"; public async Task<List<GameEntry>> ScanAsync(CancellationToken ct) { var games = new List<GameEntry>(); // Read Steam library folders from libraryfolders.vdf string steamPath = GetSteamInstallPath(); string vdfPath = Path.Combine(steamPath, "steamapps", "libraryfolders.vdf"); // Parse VDF and iterate through library folders var libraries = ParseLibraryFolders(vdfPath); foreach (var library in libraries) { var acfFiles = Directory.GetFiles( Path.Combine(library, "steamapps"), "appmanifest_*.acf" ); foreach (var acfFile in acfFiles) { var game = ParseAppManifest(acfFile); if (game != null && !IsExcluded(game.Name)) { games.Add(game); } } } return games; } private string GetSteamInstallPath() { using var key = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\WOW6432Node\Valve\Steam" ); return key?.GetValue("InstallPath") as string ?? @"C:\Program Files (x86)\Steam"; } } ``` ### Component Download & Installation ```csharp // Component manager pattern public class ComponentManager { private readonly HttpClient _httpClient; private readonly string _cacheDirectory; public ComponentManager(string cacheDir) { _cacheDirectory = cacheDir; _httpClient = new HttpClient(); // Configure proxy if needed ConfigureProxy(); } public async Task<string> DownloadOptiScalerAsync( string version, bool isBeta, IProgress<double> progress, CancellationToken ct ) { string cacheKey = $"optiscaler_{version}_{(isBeta ? "beta" : "stable")}"; string cachePath = Path.Combine(_cacheDirectory, cacheKey); if (Directory.Exists(cachePath)) { return cachePath; } // GitHub release URL string url = isBeta ? $"https://github.com/optiscaler/OptiScaler/releases/download/beta-{version}/OptiScaler.zip" : $"https://github.com/optiscaler/OptiScaler/releases/download/v{version}/OptiScaler.zip"; string zipPath = Path.Combine(_cacheDirectory, $"{cacheKey}.zip"); // Download with progress using (var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, ct)) { response.EnsureSuccessStatusCode(); var totalBytes = response.Content.Headers.ContentLength ?? -1L; using var contentStream = await response.Content.ReadAsStreamAsync(ct); using var fileStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write, FileShare.None); var buffer = new byte[8192]; long totalRead = 0; int bytesRead; while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, ct)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead, ct); totalRead += bytesRead; if (totalBytes > 0) { progress?.Report((double)totalRead / totalBytes * 100); } } } // Extract ZipFile.ExtractToDirectory(zipPath, cachePath); File.Delete(zipPath); return cachePath; } private void ConfigureProxy() { var proxyUrl = Environment.GetEnvironmentVariable("HTTP_PROXY") ?? Environment.GetEnvironmentVariable("HTTPS_PROXY"); if (!string.IsNullOrEmpty(proxyUrl)) { var proxy = new WebProxy(proxyUrl); var handler = new HttpClientHandler { Proxy = proxy }; _httpClient = new HttpClient(handler); } } } ``` ### Game Installation Logic ```csharp public class GameInstaller { public async Task<InstallResult> InstallOptiScalerAsync( GameEntry game, InstallOptions options, CancellationToken ct ) { // 1. Detect game structure string targetExe = options.ManualPath ?? DetectMainExecutable(game.InstallPath); string gameDir = Path.GetDirectoryName(targetExe); // 2. Create backup string backupDir = Path.Combine(gameDir, ".optiscaler_backup"); Directory.CreateDirectory(backupDir); string injectionDll = options.InjectionMethod; // e.g., "dxgi.dll" string originalDll = Path.Combine(gameDir, injectionDll); if (File.Exists(originalDll)) { File.Copy(originalDll, Path.Combine(backupDir, injectionDll), true); } // 3. Download components string optiScalerPath = await _componentManager.DownloadOptiScalerAsync( options.OptiScalerVersion, options.UseBeta, options.Progress, ct ); // 4. Copy files CopyOptiScalerFiles(optiScalerPath, gameDir); // Copy injection DLL File.Copy( Path.Combine(optiScalerPath, "nvngx.dll"), Path.Combine(gameDir, injectionDll), overwrite: true ); // 5. Install Fakenvapi if AMD/Intel GPU if (options.NeedsFakenvapi) { await InstallFakenaviAsync(gameDir, options.FakenaviVersion, ct); } // 6. Install frame generation if requested if (options.InstallFrameGen) { await InstallNukemFGAsync(gameDir, ct); } // 7. Apply profile if (!string.IsNullOrEmpty(options.ProfileName)) { await ApplyProfileAsync(gameDir, options.ProfileName); } // 8. Configure OptiPatcher if needed if (options.InstallOptiPatcher) { await ConfigureOptiPatcherAsync(gameDir); } return new InstallResult { Success = true, InstalledComponents = GetInstalledComponents(gameDir) }; } private string DetectMainExecutable(string installPath) { // UE5/Phoenix game detection var phoenixDirs = new[] { "Phoenix", "Engine/Binaries/Win64" }; foreach (var subDir in phoenixDirs) { string path = Path.Combine(installPath, subDir); if (Directory.Exists(path)) { var exes = Directory.GetFiles(path, "*.exe", SearchOption.TopDirectoryOnly) .Where(f => !f.Contains("Crash") && !f.Contains("UnrealEditor")) .ToList(); if (exes.Any()) { return exes.First(); } } } // Standard detection: largest .exe in root or bin folder var candidates = Directory.GetFiles(installPath, "*.exe", SearchOption.AllDirectories) .Where(f => !IsSystemExecutable(f)) .OrderByDescending(f => new FileInfo(f).Length) .ToList(); return candidates.FirstOrDefault(); } private bool IsSystemExecutable(string path) { var excludeNames = new[] { "unins", "crash", "reporter", "launcher", "redist", "vcredist", "directx", "unity" }; string fileName = Path.GetFileNameWithoutExtension(path).ToLower(); return excludeNames.Any(e => fileName.Contains(e)); } } ``` ### Profile Management ```csharp public class ProfileManager { private readonly string _profilesDirectory; public ProfileManager(string profilesDir) { _profilesDirectory = profilesDir; Directory.CreateDirectory(_profilesDirectory); } public Profile LoadProfile(string name) { string path = Path.Combine(_profilesDirectory, $"{name}.ini"); if (!File.Exists(path)) { throw new FileNotFoundException($"Profile '{name}' not found"); } var profile = new Profile { Name = name }; var parser = new IniParser(); var data = parser.ReadFile(path); foreach (var section in data.Sections) { profile.Sections[section.SectionName] = section.Keys .ToDictionary(k => k.KeyName, k => k.Value); } return profile; } public void SaveProfile(Profile profile) { string path = Path.Combine(_profilesDirectory, $"{profile.Name}.ini"); using var writer = new StreamWriter(path); foreach (var section in profile.Sections) { writer.WriteLine($"[{section.Key}]"); foreach (var kvp in section.Value) { writer.WriteLine($"{kvp.Key}={kvp.Value}"); } writer.WriteLine(); } } public Profile CreateDefaultProfile() { return new Profile { Name = "OptiScaler Standard", Sections = new Dictionary<string, Dictionary<string, string>> { ["Upscaling"] = new() { ["Enabled"] = "true", ["Mode"] = "Quality", ["Sharpness"] = "0.5" }, ["FrameGeneration"] = new() { ["Enabled"] = "false", ["FrameInterpolation"] = "true" }, ["Advanced"] = new() { ["MotionVectors"] = "Auto", ["DepthBuffer"] = "Auto", ["HDR"] = "true" } } }; } } public class Profile { public string Name { get; set; } public Dictionary<string, Dictionary<string, string>> Sections { get; set; } = new(); } ``` ### GPU Detection ```csharp public class GpuDetector { public List<GpuInfo> DetectGpus() { var gpus = new List<GpuInfo>(); try { using var searcher = new ManagementObjectSearcher( "SELECT * FROM Win32_VideoController" ); foreach (ManagementObject obj in searcher.Get()) { var name = obj["Name"]?.ToString(); var vendor = obj["AdapterCompatibility"]?.ToString(); var driverVersion = obj["DriverVersion"]?.ToString(); if (string.IsNullOrEmpty(name)) continue; var gpu = new GpuInfo { Name = name, Vendor = DetermineVendor(name, vendor), DriverVersion = driverVersion, IsDiscrete = IsDiscreteGpu(name) }; gpus.Add(gpu); } } catch (Exception ex) { // Fallback to manual detection Console.WriteLine($"WMI detection failed: {ex.Message}"); } // Sort: discrete GPUs first, then by vendor preference (NVIDIA > AMD > Intel) return gpus .OrderByDescending(g => g.IsDiscrete) .ThenBy(g => g.Vendor == GpuVendor.NVIDIA ? 0 : g.Vendor == GpuVendor.AMD ? 1 : 2) .ToList(); } private GpuVendor DetermineVendor(string name, string vendor) { name = name.ToLower(); vendor = vendor?.ToLower() ?? ""; if (name.Contains("nvidia") || name.Contains("geforce") || name.Contains("rtx")) return GpuVendor.NVIDIA; if (name.Contains("amd") || name.Contains("radeon") || name.Contains("rx ")) return GpuVendor.AMD; if (name.Contains("intel") || name.Contains("uhd") || name.Contains("iris")) return GpuVendor.Intel; return GpuVendor.Unknown; } private bool IsDiscreteGpu(string name) { name = name.ToLower(); return !name.Contains("intel") || name.Contains("arc"); } public bool NeedsFakenvapi(GpuInfo gpu) { return gpu.Vendor == GpuVendor.AMD || gpu.Vendor == GpuVendor.Intel; }
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る