From ca5767e57f10c2be3b30488a314c973d05835341 Mon Sep 17 00:00:00 2001
From: ParantezTech <12572227+par274@users.noreply.github.com>
Date: Sat, 19 Sep 2026 23:18:12 +0300
Subject: [PATCH] [GUI] Added Custom Environment Variables dialog and settings
---
.../CustomEnvironmentDialog.axaml | 76 +++++++++++++++
.../CustomEnvironmentDialog.axaml.cs | 92 +++++++++++++++++++
.../CustomEnvironmentVariables.cs | 70 ++++++++++++++
.../GlobalCustomEnvironmentSettings.cs | 58 ++++++++++++
src/SharpEmu.GUI/GuiSettings.cs | 3 +
src/SharpEmu.GUI/Languages/ar.json | 16 ++++
src/SharpEmu.GUI/Languages/br.json | 16 ++++
src/SharpEmu.GUI/Languages/de.json | 16 ++++
src/SharpEmu.GUI/Languages/dk.json | 16 ++++
src/SharpEmu.GUI/Languages/ee.json | 16 ++++
src/SharpEmu.GUI/Languages/en.json | 16 ++++
src/SharpEmu.GUI/Languages/es.json | 16 ++++
src/SharpEmu.GUI/Languages/fr.json | 16 ++++
src/SharpEmu.GUI/Languages/hu.json | 16 ++++
src/SharpEmu.GUI/Languages/it.json | 16 ++++
src/SharpEmu.GUI/Languages/ja.json | 16 ++++
src/SharpEmu.GUI/Languages/ko.json | 16 ++++
src/SharpEmu.GUI/Languages/nl.json | 16 ++++
src/SharpEmu.GUI/Languages/pl.json | 16 ++++
src/SharpEmu.GUI/Languages/pt.json | 16 ++++
src/SharpEmu.GUI/Languages/ru.json | 16 ++++
src/SharpEmu.GUI/Languages/tr.json | 16 ++++
src/SharpEmu.GUI/MainWindow.GameOptions.cs | 1 +
src/SharpEmu.GUI/MainWindow.axaml | 22 +++++
src/SharpEmu.GUI/MainWindow.axaml.cs | 88 ++++++++++++++++--
src/SharpEmu.GUI/PerGameSettings.cs | 12 ++-
src/SharpEmu.GUI/ProjectLinks.cs | 19 ++++
27 files changed, 703 insertions(+), 10 deletions(-)
create mode 100644 src/SharpEmu.GUI/CustomEnvironmentDialog.axaml
create mode 100644 src/SharpEmu.GUI/CustomEnvironmentDialog.axaml.cs
create mode 100644 src/SharpEmu.GUI/CustomEnvironmentVariables.cs
create mode 100644 src/SharpEmu.GUI/GlobalCustomEnvironmentSettings.cs
create mode 100644 src/SharpEmu.GUI/ProjectLinks.cs
diff --git a/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml b/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml
new file mode 100644
index 0000000..97e0fc5
--- /dev/null
+++ b/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml.cs b/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml.cs
new file mode 100644
index 0000000..031f135
--- /dev/null
+++ b/src/SharpEmu.GUI/CustomEnvironmentDialog.axaml.cs
@@ -0,0 +1,92 @@
+// Copyright (C) 2026 SharpEmu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+using Avalonia.Controls;
+using System.Diagnostics;
+
+namespace SharpEmu.GUI;
+
+public partial class CustomEnvironmentDialog : Window
+{
+ private readonly string? _titleId;
+
+ public CustomEnvironmentDialog()
+ : this(null, [])
+ {
+ }
+
+ public CustomEnvironmentDialog(string? titleId, IEnumerable initialEntries)
+ {
+ InitializeComponent();
+ _titleId = titleId;
+ EnvironmentTextBox.Text = string.Join(Environment.NewLine, initialEntries);
+ SaveGameButton.IsEnabled = !string.IsNullOrWhiteSpace(titleId);
+
+ SaveGameButton.Click += (_, _) => SaveForGame();
+ SaveGlobalButton.Click += (_, _) => SaveGlobally();
+ DocumentationButton.Click += (_, _) => OpenDocumentation();
+ CancelButton.Click += (_, _) => Close(null);
+ PlayButton.Click += (_, _) => Play();
+ }
+
+ public event Action>? SaveGlobalRequested;
+ public event Action>? SaveGameRequested;
+
+ private static void OpenDocumentation()
+ {
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = ProjectLinks.DocumentUrl("docs/sharpemu-gui-undocumented-env-vars.md"),
+ UseShellExecute = true,
+ });
+ }
+
+ private bool TryGetEntries(out IReadOnlyList entries)
+ {
+ if (!CustomEnvironmentVariables.TryParseLines(
+ EnvironmentTextBox.Text,
+ out var parsed,
+ out var invalidLine))
+ {
+ StatusText.Text = string.Format(
+ Localization.Instance.Get("Launch.CustomEnv.Invalid"),
+ invalidLine);
+ entries = [];
+ return false;
+ }
+
+ StatusText.Text = string.Empty;
+ entries = parsed;
+ return true;
+ }
+
+ private void SaveForGame()
+ {
+ if (string.IsNullOrWhiteSpace(_titleId) || !TryGetEntries(out var entries))
+ {
+ return;
+ }
+
+ SaveGameRequested?.Invoke(_titleId, entries);
+ StatusText.Text = Localization.Instance.Get("Launch.CustomEnv.SavedGame");
+ }
+
+ private void SaveGlobally()
+ {
+ if (!TryGetEntries(out var entries))
+ {
+ return;
+ }
+
+ SaveGlobalRequested?.Invoke(entries);
+ StatusText.Text = Localization.Instance.Get("Launch.CustomEnv.SavedGlobal");
+ }
+
+ private void Play()
+ {
+ if (TryGetEntries(out var entries))
+ {
+ Close(entries);
+ }
+ }
+}
diff --git a/src/SharpEmu.GUI/CustomEnvironmentVariables.cs b/src/SharpEmu.GUI/CustomEnvironmentVariables.cs
new file mode 100644
index 0000000..6e9d403
--- /dev/null
+++ b/src/SharpEmu.GUI/CustomEnvironmentVariables.cs
@@ -0,0 +1,70 @@
+// Copyright (C) 2026 SharpEmu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+namespace SharpEmu.GUI;
+
+internal static class CustomEnvironmentVariables
+{
+ public static bool TryParseLines(
+ string? text,
+ out IReadOnlyList entries,
+ out string invalidLine)
+ {
+ var parsed = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var rawLine in (text ?? string.Empty).Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries))
+ {
+ var line = rawLine.Trim();
+ if (line.Length == 0 || line.StartsWith('#'))
+ {
+ continue;
+ }
+
+ if (!TryParseEntry(line, out var name, out var value))
+ {
+ entries = [];
+ invalidLine = line;
+ return false;
+ }
+
+ parsed[name] = value;
+ }
+
+ entries = parsed.Select(pair => $"{pair.Key}={pair.Value}").ToArray();
+ invalidLine = string.Empty;
+ return true;
+ }
+
+ public static IReadOnlyList Merge(
+ params IEnumerable?[] sources)
+ {
+ var merged = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var source in sources)
+ {
+ if (source is null)
+ {
+ continue;
+ }
+
+ foreach (var entry in source)
+ {
+ if (TryParseEntry(entry, out var name, out var value))
+ {
+ merged[name] = value;
+ }
+ }
+ }
+
+ return merged.Select(pair => $"{pair.Key}={pair.Value}").ToArray();
+ }
+
+ public static bool TryParseEntry(string entry, out string name, out string value)
+ {
+ var separator = entry.IndexOf('=');
+ name = (separator >= 0 ? entry[..separator] : entry).Trim();
+ value = separator >= 0 ? entry[(separator + 1)..] : "1";
+
+ return name.Length != 0 &&
+ !name.Contains('\0') &&
+ !name.Contains('=');
+ }
+}
diff --git a/src/SharpEmu.GUI/GlobalCustomEnvironmentSettings.cs b/src/SharpEmu.GUI/GlobalCustomEnvironmentSettings.cs
new file mode 100644
index 0000000..eb4528e
--- /dev/null
+++ b/src/SharpEmu.GUI/GlobalCustomEnvironmentSettings.cs
@@ -0,0 +1,58 @@
+// Copyright (C) 2026 SharpEmu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+using System.Text.Json;
+
+namespace SharpEmu.GUI;
+
+internal sealed class GlobalCustomEnvironmentSettings
+{
+ private static readonly JsonSerializerOptions SerializerOptions = new()
+ {
+ WriteIndented = true,
+ };
+
+ public List EnvironmentVariables { get; set; } = new();
+
+ public static string FilePath =>
+ Path.Combine(AppContext.BaseDirectory, "user", "custom_envs.json");
+
+ public static IReadOnlyList Load()
+ {
+ try
+ {
+ if (!File.Exists(FilePath))
+ {
+ return [];
+ }
+
+ var settings = JsonSerializer.Deserialize(
+ File.ReadAllText(FilePath),
+ SerializerOptions);
+ return Normalize(settings?.EnvironmentVariables);
+ }
+ catch (Exception)
+ {
+ return [];
+ }
+ }
+
+ public static void Save(IEnumerable entries)
+ {
+ try
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(FilePath)!);
+ var settings = new GlobalCustomEnvironmentSettings
+ {
+ EnvironmentVariables = Normalize(entries).ToList(),
+ };
+ File.WriteAllText(FilePath, JsonSerializer.Serialize(settings, SerializerOptions));
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ private static IReadOnlyList Normalize(IEnumerable? entries) =>
+ CustomEnvironmentVariables.Merge(entries);
+}
diff --git a/src/SharpEmu.GUI/GuiSettings.cs b/src/SharpEmu.GUI/GuiSettings.cs
index f365613..cd198fa 100644
--- a/src/SharpEmu.GUI/GuiSettings.cs
+++ b/src/SharpEmu.GUI/GuiSettings.cs
@@ -72,6 +72,8 @@ public sealed class GuiSettings
/// Names of SHARPEMU_* switches set to "1" in the emulator's environment at launch.
public List EnvironmentToggles { get; set; } = new();
+ public string BinkPlaybackMode { get; set; } = "Host";
+
/// Internal render resolution scale (1.0 = native, 0.5 = half).
public double RenderResolutionScale { get; set; } = 1.0;
@@ -139,6 +141,7 @@ public sealed class GuiSettings
settings.Resolution = NormalizeResolution(settings.Resolution);
settings.ScalingMode = NormalizeChoice(settings.ScalingMode, "Fit", "Cover", "Stretch", "Integer");
settings.HdrMode = NormalizeChoice(settings.HdrMode, "Auto", "On", "Off");
+ settings.BinkPlaybackMode = NormalizeChoice(settings.BinkPlaybackMode, "Host", "Guest", "Skip");
settings.DisplayIndex = Math.Max(0, settings.DisplayIndex);
settings.RefreshRate = Math.Clamp(settings.RefreshRate, 0, 1000);
diff --git a/src/SharpEmu.GUI/Languages/ar.json b/src/SharpEmu.GUI/Languages/ar.json
index ace1310..16c65c1 100644
--- a/src/SharpEmu.GUI/Languages/ar.json
+++ b/src/SharpEmu.GUI/Languages/ar.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "تشغيل فيديو Bink",
+ "Options.Env.BinkPlayback.Desc": "يقوم Host بتشغيل فيديوهات Bink عبر جسر FFmpeg، لكن قد تظهر مشكلات في بعض الألعاب.\nيستخدم Guest وحدة فك الترميز الخاصة بمحرك اللعبة، والتي يدعمها SharpEmu حاليًا بشكل جزئي فقط.\nيتخطى Skip فيديوهات Bink، مما قد يجعل التطوير أسهل.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "تخطي",
"_languageName": "العربية",
"Page.Library": "المكتبة",
@@ -90,6 +95,17 @@
"Launch.Idle": "خامل",
"Launch.Console": "≡ نافذة السجلات",
"Launch.Launch": "▶ تشغيل",
+ "Launch.CustomEnv": "تشغيل بمتغيرات بيئة مخصصة",
+ "Launch.CustomEnv.Title": "تشغيل بمتغيرات بيئة مخصصة",
+ "Launch.CustomEnv.Desc": "أدخل متغير بيئة واحدًا في كل سطر بصيغة NAME=VALUE. القيم المخصصة تتجاوز إعدادات الواجهة وإعدادات اللعبة التي تحمل الاسم نفسه.",
+ "Launch.CustomEnv.Documentation": "عرض متغيرات البيئة غير الموثقة ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXAMPLE=1",
+ "Launch.CustomEnv.SaveGame": "حفظ للعبة",
+ "Launch.CustomEnv.SaveGlobal": "حفظ بشكل عام",
+ "Launch.CustomEnv.Play": "تشغيل",
+ "Launch.CustomEnv.Invalid": "متغير بيئة غير صالح: {0}",
+ "Launch.CustomEnv.SavedGame": "تم الحفظ لهذه اللعبة.",
+ "Launch.CustomEnv.SavedGlobal": "تم الحفظ بشكل عام.",
"Launch.Stop": "■ إيقاف",
"Launch.Running": "قيد التشغيل — {0}",
"Launch.Stopping": "جارٍ الإيقاف...",
diff --git a/src/SharpEmu.GUI/Languages/br.json b/src/SharpEmu.GUI/Languages/br.json
index d354c7e..54b2eb6 100644
--- a/src/SharpEmu.GUI/Languages/br.json
+++ b/src/SharpEmu.GUI/Languages/br.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Reprodução de vídeo Bink",
+ "Options.Env.BinkPlayback.Desc": "Host reproduz vídeos Bink pela ponte FFmpeg, mas alguns jogos podem apresentar problemas.\nGuest usa o decodificador do próprio motor do jogo, que o SharpEmu atualmente suporta apenas parcialmente.\nSkip ignora os vídeos Bink, o que pode facilitar o desenvolvimento.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Ignorar",
"_languageName": "Português (Brasil)",
"Page.Library": "Biblioteca",
@@ -104,6 +109,17 @@
"Launch.Idle": "Ocioso",
"Launch.Console": "≡ Console",
"Launch.Launch": "▶ Iniciar",
+ "Launch.CustomEnv": "Iniciar com variáveis de ambiente personalizadas",
+ "Launch.CustomEnv.Title": "Iniciar com variáveis de ambiente personalizadas",
+ "Launch.CustomEnv.Desc": "Digite uma variável de ambiente por linha no formato NOME=VALOR. Os valores personalizados substituem as configurações da GUI e específicas do jogo com o mesmo nome.",
+ "Launch.CustomEnv.Documentation": "Ver variáveis de ambiente não documentadas ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXEMPLO=1",
+ "Launch.CustomEnv.SaveGame": "Salvar para o jogo",
+ "Launch.CustomEnv.SaveGlobal": "Salvar globalmente",
+ "Launch.CustomEnv.Play": "Jogar",
+ "Launch.CustomEnv.Invalid": "Variável de ambiente inválida: {0}",
+ "Launch.CustomEnv.SavedGame": "Salvo para este jogo.",
+ "Launch.CustomEnv.SavedGlobal": "Salvo globalmente.",
"Launch.Stop": "■ Parar",
"Launch.Running": "Em execução — {0}",
"Launch.Stopping": "Encerrando…",
diff --git a/src/SharpEmu.GUI/Languages/de.json b/src/SharpEmu.GUI/Languages/de.json
index 93b2c5c..855e693 100644
--- a/src/SharpEmu.GUI/Languages/de.json
+++ b/src/SharpEmu.GUI/Languages/de.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink-Videowiedergabe",
+ "Options.Env.BinkPlayback.Desc": "Host spielt Bink-Videos über die FFmpeg-Brücke ab, bei einigen Spielen können jedoch Probleme auftreten.\nGuest verwendet den spieleigenen Decoder, den SharpEmu derzeit nur teilweise unterstützt.\nSkip überspringt Bink-Videos, was die Entwicklung erleichtern kann.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Überspringen",
"_languageName": "Deutsch",
"Page.Library": "Bibliothek",
@@ -90,6 +95,17 @@
"Launch.Idle": "Bereit",
"Launch.Console": "≡ Konsole",
"Launch.Launch": "▶ Starten",
+ "Launch.CustomEnv": "Mit benutzerdefinierten Umgebungsvariablen starten",
+ "Launch.CustomEnv.Title": "Mit benutzerdefinierten Umgebungsvariablen starten",
+ "Launch.CustomEnv.Desc": "Gib pro Zeile eine Umgebungsvariable im Format NAME=WERT ein. Benutzerdefinierte Werte überschreiben gleichnamige GUI- und spielspezifische Einstellungen.",
+ "Launch.CustomEnv.Documentation": "Undokumentierte Umgebungsvariablen anzeigen ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_BEISPIEL=1",
+ "Launch.CustomEnv.SaveGame": "Für Spiel speichern",
+ "Launch.CustomEnv.SaveGlobal": "Global speichern",
+ "Launch.CustomEnv.Play": "Spielen",
+ "Launch.CustomEnv.Invalid": "Ungültige Umgebungsvariable: {0}",
+ "Launch.CustomEnv.SavedGame": "Für dieses Spiel gespeichert.",
+ "Launch.CustomEnv.SavedGlobal": "Global gespeichert.",
"Launch.Stop": "■ Stoppen",
"Launch.Running": "Läuft -- {0}",
"Launch.Stopping": "Wird beendet…",
diff --git a/src/SharpEmu.GUI/Languages/dk.json b/src/SharpEmu.GUI/Languages/dk.json
index 714b906..89d7715 100644
--- a/src/SharpEmu.GUI/Languages/dk.json
+++ b/src/SharpEmu.GUI/Languages/dk.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink-videoafspilning",
+ "Options.Env.BinkPlayback.Desc": "Host afspiller Bink-videoer via FFmpeg-broen, men nogle spil kan opleve problemer.\nGuest bruger spilmotorens egen dekoder, som SharpEmu i øjeblikket kun understøtter delvist.\nSkip springer Bink-videoer over, hvilket kan gøre udviklingen nemmere.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Spring over",
"_languageName": "Dansk",
"Page.Library": "Bibliotek",
@@ -90,6 +95,17 @@
"Launch.Idle": "Inaktiv",
"Launch.Console": "≡ Konsol",
"Launch.Launch": "▶ Start",
+ "Launch.CustomEnv": "Start med brugerdefinerede miljøvariabler",
+ "Launch.CustomEnv.Title": "Start med brugerdefinerede miljøvariabler",
+ "Launch.CustomEnv.Desc": "Indtast én miljøvariabel pr. linje som NAVN=VÆRDI. Brugerdefinerede værdier tilsidesætter GUI- og spilspecifikke indstillinger med samme navn.",
+ "Launch.CustomEnv.Documentation": "Vis udokumenterede miljøvariabler ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EKSEMPEL=1",
+ "Launch.CustomEnv.SaveGame": "Gem for spil",
+ "Launch.CustomEnv.SaveGlobal": "Gem globalt",
+ "Launch.CustomEnv.Play": "Spil",
+ "Launch.CustomEnv.Invalid": "Ugyldig miljøvariabel: {0}",
+ "Launch.CustomEnv.SavedGame": "Gemt for dette spil.",
+ "Launch.CustomEnv.SavedGlobal": "Gemt globalt.",
"Launch.Stop": "■ Stop",
"Launch.Running": "Kører — {0}",
"Launch.Stopping": "Stopper…",
diff --git a/src/SharpEmu.GUI/Languages/ee.json b/src/SharpEmu.GUI/Languages/ee.json
index ce82cb3..efd1658 100644
--- a/src/SharpEmu.GUI/Languages/ee.json
+++ b/src/SharpEmu.GUI/Languages/ee.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink-video taasesitus",
+ "Options.Env.BinkPlayback.Desc": "Host esitab Bink-videoid FFmpegi silla kaudu, kuid mõnes mängus võib esineda probleeme.\nGuest kasutab mängumootori enda dekoodrit, mida SharpEmu praegu ainult osaliselt toetab.\nSkip jätab Bink-videod vahele, mis võib arendust lihtsustada.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Jäta vahele",
"_languageName": "Eesti",
"Page.Library": "Teek",
@@ -142,6 +147,17 @@
"Launch.Idle": "Ootel",
"Launch.Console": "≡ Konsool",
"Launch.Launch": "▶ Käivita",
+ "Launch.CustomEnv": "Käivita kohandatud keskkonnamuutujatega",
+ "Launch.CustomEnv.Title": "Käivita kohandatud keskkonnamuutujatega",
+ "Launch.CustomEnv.Desc": "Sisesta üks keskkonnamuutuja rea kohta kujul NIMI=VÄÄRTUS. Kohandatud väärtused alistavad sama nimega GUI ja mängupõhised seaded.",
+ "Launch.CustomEnv.Documentation": "Vaata dokumenteerimata keskkonnamuutujaid ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_NAIDE=1",
+ "Launch.CustomEnv.SaveGame": "Salvesta mängule",
+ "Launch.CustomEnv.SaveGlobal": "Salvesta globaalselt",
+ "Launch.CustomEnv.Play": "Mängi",
+ "Launch.CustomEnv.Invalid": "Vigane keskkonnamuutuja: {0}",
+ "Launch.CustomEnv.SavedGame": "Selle mängu jaoks salvestatud.",
+ "Launch.CustomEnv.SavedGlobal": "Globaalselt salvestatud.",
"Launch.Stop": "■ Peata",
"Launch.Running": "Käib — {0}",
"Launch.Stopping": "Peatamine…",
diff --git a/src/SharpEmu.GUI/Languages/en.json b/src/SharpEmu.GUI/Languages/en.json
index aa7bc52..6f29e82 100644
--- a/src/SharpEmu.GUI/Languages/en.json
+++ b/src/SharpEmu.GUI/Languages/en.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink video playback",
+ "Options.Env.BinkPlayback.Desc": "Host plays Bink videos through the FFmpeg bridge, but some games may have issues.\nGuest uses the game engine's own decoder, which SharpEmu currently supports only partially.\nSkip skips Bink videos, which can make development easier.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Skip",
"_languageName": "English",
"Page.Library": "Library",
@@ -142,6 +147,17 @@
"Launch.Idle": "Idle",
"Launch.Console": "≡ Console",
"Launch.Launch": "▶ Launch",
+ "Launch.CustomEnv": "Launch with custom env",
+ "Launch.CustomEnv.Title": "Launch with custom env",
+ "Launch.CustomEnv.Desc": "Enter environment variables one per line as NAME=VALUE. Custom values override matching GUI and per-game environment settings.",
+ "Launch.CustomEnv.Documentation": "View undocumented environment variables ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXAMPLE=1",
+ "Launch.CustomEnv.SaveGame": "Save for game",
+ "Launch.CustomEnv.SaveGlobal": "Save globally",
+ "Launch.CustomEnv.Play": "Play",
+ "Launch.CustomEnv.Invalid": "Invalid environment variable: {0}",
+ "Launch.CustomEnv.SavedGame": "Saved for this game.",
+ "Launch.CustomEnv.SavedGlobal": "Saved globally.",
"Launch.Stop": "■ Stop",
"Launch.Running": "Running — {0}",
"Launch.Stopping": "Stopping…",
diff --git a/src/SharpEmu.GUI/Languages/es.json b/src/SharpEmu.GUI/Languages/es.json
index bea0153..82293c2 100644
--- a/src/SharpEmu.GUI/Languages/es.json
+++ b/src/SharpEmu.GUI/Languages/es.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Reproducción de vídeo Bink",
+ "Options.Env.BinkPlayback.Desc": "Host reproduce los vídeos Bink mediante el puente FFmpeg, aunque algunos juegos pueden presentar problemas.\nGuest usa el decodificador propio del motor del juego, que SharpEmu actualmente solo admite de forma parcial.\nSkip omite los vídeos Bink, lo que puede facilitar el desarrollo.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Omitir",
"_languageName": "Español",
"Page.Library": "Biblioteca",
@@ -90,6 +95,17 @@
"Launch.Idle": "Inactivo",
"Launch.Console": "≡ Consola",
"Launch.Launch": "▶ Iniciar",
+ "Launch.CustomEnv": "Iniciar con variables de entorno personalizadas",
+ "Launch.CustomEnv.Title": "Iniciar con variables de entorno personalizadas",
+ "Launch.CustomEnv.Desc": "Introduce una variable de entorno por línea con el formato NOMBRE=VALOR. Los valores personalizados reemplazan los ajustes de la GUI y del juego con el mismo nombre.",
+ "Launch.CustomEnv.Documentation": "Ver variables de entorno no documentadas ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EJEMPLO=1",
+ "Launch.CustomEnv.SaveGame": "Guardar para el juego",
+ "Launch.CustomEnv.SaveGlobal": "Guardar globalmente",
+ "Launch.CustomEnv.Play": "Jugar",
+ "Launch.CustomEnv.Invalid": "Variable de entorno no válida: {0}",
+ "Launch.CustomEnv.SavedGame": "Guardado para este juego.",
+ "Launch.CustomEnv.SavedGlobal": "Guardado globalmente.",
"Launch.Stop": "■ Detener",
"Launch.Running": "En ejecución — {0}",
"Launch.Stopping": "Deteniendo…",
diff --git a/src/SharpEmu.GUI/Languages/fr.json b/src/SharpEmu.GUI/Languages/fr.json
index abf67a0..ca98a2b 100644
--- a/src/SharpEmu.GUI/Languages/fr.json
+++ b/src/SharpEmu.GUI/Languages/fr.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Lecture vidéo Bink",
+ "Options.Env.BinkPlayback.Desc": "Host lit les vidéos Bink via le pont FFmpeg, mais certains jeux peuvent rencontrer des problèmes.\nGuest utilise le décodeur propre au moteur du jeu, que SharpEmu ne prend actuellement en charge que partiellement.\nSkip ignore les vidéos Bink, ce qui peut faciliter le développement.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Ignorer",
"_languageName": "Français",
"Page.Library": "Bibliothèque",
@@ -104,6 +109,17 @@
"Launch.Idle": "Inactif",
"Launch.Console": "≡ Console",
"Launch.Launch": "▶ Lancer",
+ "Launch.CustomEnv": "Lancer avec des variables d'environnement personnalisées",
+ "Launch.CustomEnv.Title": "Lancer avec des variables d'environnement personnalisées",
+ "Launch.CustomEnv.Desc": "Saisissez une variable d'environnement par ligne au format NOM=VALEUR. Les valeurs personnalisées remplacent les réglages GUI et spécifiques au jeu portant le même nom.",
+ "Launch.CustomEnv.Documentation": "Voir les variables d'environnement non documentées ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXEMPLE=1",
+ "Launch.CustomEnv.SaveGame": "Enregistrer pour le jeu",
+ "Launch.CustomEnv.SaveGlobal": "Enregistrer globalement",
+ "Launch.CustomEnv.Play": "Jouer",
+ "Launch.CustomEnv.Invalid": "Variable d'environnement invalide : {0}",
+ "Launch.CustomEnv.SavedGame": "Enregistré pour ce jeu.",
+ "Launch.CustomEnv.SavedGlobal": "Enregistré globalement.",
"Launch.Stop": "■ Arrêter",
"Launch.Running": "En cours d’exécution — {0}",
"Launch.Stopping": "Arrêt en cours…",
diff --git a/src/SharpEmu.GUI/Languages/hu.json b/src/SharpEmu.GUI/Languages/hu.json
index cdb3575..1e8c68f 100644
--- a/src/SharpEmu.GUI/Languages/hu.json
+++ b/src/SharpEmu.GUI/Languages/hu.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink videólejátszás",
+ "Options.Env.BinkPlayback.Desc": "A Host az FFmpeg hídon keresztül játssza le a Bink videókat, de egyes játékoknál problémák jelentkezhetnek.\nA Guest a játékmotor saját dekóderét használja, amelyet a SharpEmu jelenleg csak részben támogat.\nA Skip kihagyja a Bink videókat, ami megkönnyítheti a fejlesztést.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Kihagyás",
"_languageName": "Hungarian",
"Page.Library": "Könyvtár",
@@ -104,6 +109,17 @@
"Launch.Idle": "Tétlen",
"Launch.Console": "≡ Konzol",
"Launch.Launch": "▶ Inditás",
+ "Launch.CustomEnv": "Indítás egyéni környezeti változókkal",
+ "Launch.CustomEnv.Title": "Indítás egyéni környezeti változókkal",
+ "Launch.CustomEnv.Desc": "Soronként egy környezeti változót adj meg NÉV=ÉRTÉK formában. Az egyéni értékek felülírják az azonos nevű GUI- és játékspecifikus beállításokat.",
+ "Launch.CustomEnv.Documentation": "Nem dokumentált környezeti változók megtekintése ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_PELDA=1",
+ "Launch.CustomEnv.SaveGame": "Mentés a játékhoz",
+ "Launch.CustomEnv.SaveGlobal": "Globális mentés",
+ "Launch.CustomEnv.Play": "Játék",
+ "Launch.CustomEnv.Invalid": "Érvénytelen környezeti változó: {0}",
+ "Launch.CustomEnv.SavedGame": "Mentve ehhez a játékhoz.",
+ "Launch.CustomEnv.SavedGlobal": "Globálisan mentve.",
"Launch.Stop": "■ Leállítás",
"Launch.Running": "Fut — {0}",
"Launch.Stopping": "Leállítás…",
diff --git a/src/SharpEmu.GUI/Languages/it.json b/src/SharpEmu.GUI/Languages/it.json
index bf24e33..96993a8 100644
--- a/src/SharpEmu.GUI/Languages/it.json
+++ b/src/SharpEmu.GUI/Languages/it.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Riproduzione video Bink",
+ "Options.Env.BinkPlayback.Desc": "Host riproduce i video Bink tramite il bridge FFmpeg, ma alcuni giochi potrebbero avere problemi.\nGuest usa il decoder del motore di gioco, che SharpEmu attualmente supporta solo in parte.\nSkip salta i video Bink, facilitando lo sviluppo.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Salta",
"_languageName": "Italiano",
"Page.Library": "Libreria",
@@ -93,6 +98,17 @@
"Launch.Idle": "Inattivo",
"Launch.Console": "≡ Console",
"Launch.Launch": "▶ Avvia",
+ "Launch.CustomEnv": "Avvia con variabili d'ambiente personalizzate",
+ "Launch.CustomEnv.Title": "Avvia con variabili d'ambiente personalizzate",
+ "Launch.CustomEnv.Desc": "Inserisci una variabile d'ambiente per riga nel formato NOME=VALORE. I valori personalizzati sostituiscono le impostazioni GUI e specifiche del gioco con lo stesso nome.",
+ "Launch.CustomEnv.Documentation": "Visualizza le variabili d'ambiente non documentate ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_ESEMPIO=1",
+ "Launch.CustomEnv.SaveGame": "Salva per il gioco",
+ "Launch.CustomEnv.SaveGlobal": "Salva globalmente",
+ "Launch.CustomEnv.Play": "Gioca",
+ "Launch.CustomEnv.Invalid": "Variabile d'ambiente non valida: {0}",
+ "Launch.CustomEnv.SavedGame": "Salvato per questo gioco.",
+ "Launch.CustomEnv.SavedGlobal": "Salvato globalmente.",
"Launch.Stop": "■ Ferma",
"Launch.Running": "In esecuzione — {0}",
"Launch.Stopping": "Arresto in corso…",
diff --git a/src/SharpEmu.GUI/Languages/ja.json b/src/SharpEmu.GUI/Languages/ja.json
index 00e9a87..0cbc375 100644
--- a/src/SharpEmu.GUI/Languages/ja.json
+++ b/src/SharpEmu.GUI/Languages/ja.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink 動画再生",
+ "Options.Env.BinkPlayback.Desc": "Host は FFmpeg ブリッジ経由で Bink 動画を再生しますが、一部のゲームで問題が発生する場合があります。\nGuest はゲームエンジン独自のデコーダーを使用しますが、SharpEmu は現在これを部分的にしかサポートしていません。\nSkip は Bink 動画をスキップし、開発を容易にする場合があります。",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "スキップ",
"_languageName": "日本語",
"Page.Library": "ライブラリ",
@@ -90,6 +95,17 @@
"Launch.Idle": "待機中",
"Launch.Console": "≡ コンソール",
"Launch.Launch": "▶ 起動",
+ "Launch.CustomEnv": "カスタム環境変数で起動",
+ "Launch.CustomEnv.Title": "カスタム環境変数で起動",
+ "Launch.CustomEnv.Desc": "環境変数を 1 行に 1 つ、NAME=VALUE 形式で入力します。カスタム値は、同名の GUI およびゲーム固有の環境設定を上書きします。",
+ "Launch.CustomEnv.Documentation": "未文書化の環境変数を表示 ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXAMPLE=1",
+ "Launch.CustomEnv.SaveGame": "ゲーム用に保存",
+ "Launch.CustomEnv.SaveGlobal": "全体設定として保存",
+ "Launch.CustomEnv.Play": "プレイ",
+ "Launch.CustomEnv.Invalid": "無効な環境変数: {0}",
+ "Launch.CustomEnv.SavedGame": "このゲーム用に保存しました。",
+ "Launch.CustomEnv.SavedGlobal": "全体設定として保存しました。",
"Launch.Stop": "■ 停止",
"Launch.Running": "実行中 — {0}",
"Launch.Stopping": "停止中…",
diff --git a/src/SharpEmu.GUI/Languages/ko.json b/src/SharpEmu.GUI/Languages/ko.json
index dab46ed..11b26ff 100644
--- a/src/SharpEmu.GUI/Languages/ko.json
+++ b/src/SharpEmu.GUI/Languages/ko.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink 비디오 재생",
+ "Options.Env.BinkPlayback.Desc": "Host는 FFmpeg 브리지를 통해 Bink 비디오를 재생하지만 일부 게임에서 문제가 발생할 수 있습니다.\nGuest는 게임 엔진 자체 디코더를 사용하며, SharpEmu는 현재 이를 부분적으로만 지원합니다.\nSkip은 Bink 비디오를 건너뛰어 개발을 더 쉽게 할 수 있습니다.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "건너뛰기",
"_languageName": "한국어",
"Page.Library": "라이브러리",
@@ -90,6 +95,17 @@
"Launch.Idle": "대기 중",
"Launch.Console": "≡ 콘솔",
"Launch.Launch": "▶ 실행",
+ "Launch.CustomEnv": "사용자 지정 환경 변수로 실행",
+ "Launch.CustomEnv.Title": "사용자 지정 환경 변수로 실행",
+ "Launch.CustomEnv.Desc": "환경 변수를 NAME=VALUE 형식으로 한 줄에 하나씩 입력하세요. 사용자 지정 값은 이름이 같은 GUI 및 게임별 환경 설정을 덮어씁니다.",
+ "Launch.CustomEnv.Documentation": "문서화되지 않은 환경 변수 보기 ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXAMPLE=1",
+ "Launch.CustomEnv.SaveGame": "게임용으로 저장",
+ "Launch.CustomEnv.SaveGlobal": "전역으로 저장",
+ "Launch.CustomEnv.Play": "플레이",
+ "Launch.CustomEnv.Invalid": "잘못된 환경 변수: {0}",
+ "Launch.CustomEnv.SavedGame": "이 게임용으로 저장했습니다.",
+ "Launch.CustomEnv.SavedGlobal": "전역으로 저장했습니다.",
"Launch.Stop": "■ 중지",
"Launch.Running": "실행 중 — {0}",
"Launch.Stopping": "중지 중…",
diff --git a/src/SharpEmu.GUI/Languages/nl.json b/src/SharpEmu.GUI/Languages/nl.json
index 15e954a..5aa76e4 100644
--- a/src/SharpEmu.GUI/Languages/nl.json
+++ b/src/SharpEmu.GUI/Languages/nl.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink-video afspelen",
+ "Options.Env.BinkPlayback.Desc": "Host speelt Bink-video's af via de FFmpeg-brug, maar sommige games kunnen problemen hebben.\nGuest gebruikt de eigen decoder van de game-engine, die SharpEmu momenteel slechts gedeeltelijk ondersteunt.\nSkip slaat Bink-video's over, wat de ontwikkeling kan vergemakkelijken.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Overslaan",
"_languageName": "Nederlands",
"Page.Library": "Bibliotheek",
@@ -90,6 +95,17 @@
"Launch.Idle": "Inactief",
"Launch.Console": "≡ Console",
"Launch.Launch": "▶ Starten",
+ "Launch.CustomEnv": "Starten met aangepaste omgevingsvariabelen",
+ "Launch.CustomEnv.Title": "Starten met aangepaste omgevingsvariabelen",
+ "Launch.CustomEnv.Desc": "Voer per regel één omgevingsvariabele in als NAAM=WAARDE. Aangepaste waarden overschrijven GUI- en spelspecifieke instellingen met dezelfde naam.",
+ "Launch.CustomEnv.Documentation": "Ongedocumenteerde omgevingsvariabelen bekijken ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_VOORBEELD=1",
+ "Launch.CustomEnv.SaveGame": "Opslaan voor spel",
+ "Launch.CustomEnv.SaveGlobal": "Globaal opslaan",
+ "Launch.CustomEnv.Play": "Spelen",
+ "Launch.CustomEnv.Invalid": "Ongeldige omgevingsvariabele: {0}",
+ "Launch.CustomEnv.SavedGame": "Opgeslagen voor dit spel.",
+ "Launch.CustomEnv.SavedGlobal": "Globaal opgeslagen.",
"Launch.Stop": "■ Stoppen",
"Launch.Running": "Actief — {0}",
"Launch.Stopping": "Stoppen…",
diff --git a/src/SharpEmu.GUI/Languages/pl.json b/src/SharpEmu.GUI/Languages/pl.json
index 1dacf65..4709450 100644
--- a/src/SharpEmu.GUI/Languages/pl.json
+++ b/src/SharpEmu.GUI/Languages/pl.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Odtwarzanie wideo Bink",
+ "Options.Env.BinkPlayback.Desc": "Host odtwarza filmy Bink przez most FFmpeg, ale w niektórych grach mogą wystąpić problemy.\nGuest używa dekodera silnika gry, który SharpEmu obecnie obsługuje tylko częściowo.\nSkip pomija filmy Bink, co może ułatwić rozwój.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Pomiń",
"_languageName": "Polski",
"Page.Library": "Biblioteka",
@@ -142,6 +147,17 @@
"Launch.Idle": "Bezczynny",
"Launch.Console": "≡ Konsola",
"Launch.Launch": "▶ Uruchom",
+ "Launch.CustomEnv": "Uruchom z własnymi zmiennymi środowiskowymi",
+ "Launch.CustomEnv.Title": "Uruchom z własnymi zmiennymi środowiskowymi",
+ "Launch.CustomEnv.Desc": "Wpisz po jednej zmiennej środowiskowej w wierszu w formacie NAZWA=WARTOŚĆ. Własne wartości zastępują ustawienia GUI i ustawienia gry o tej samej nazwie.",
+ "Launch.CustomEnv.Documentation": "Wyświetl nieudokumentowane zmienne środowiskowe ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_PRZYKLAD=1",
+ "Launch.CustomEnv.SaveGame": "Zapisz dla gry",
+ "Launch.CustomEnv.SaveGlobal": "Zapisz globalnie",
+ "Launch.CustomEnv.Play": "Graj",
+ "Launch.CustomEnv.Invalid": "Nieprawidłowa zmienna środowiskowa: {0}",
+ "Launch.CustomEnv.SavedGame": "Zapisano dla tej gry.",
+ "Launch.CustomEnv.SavedGlobal": "Zapisano globalnie.",
"Launch.Stop": "■ Zatrzymaj",
"Launch.Running": "Działa — {0}",
"Launch.Stopping": "Zatrzymywanie…",
diff --git a/src/SharpEmu.GUI/Languages/pt.json b/src/SharpEmu.GUI/Languages/pt.json
index 5dff0ea..9749d4f 100644
--- a/src/SharpEmu.GUI/Languages/pt.json
+++ b/src/SharpEmu.GUI/Languages/pt.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Reprodução de vídeo Bink",
+ "Options.Env.BinkPlayback.Desc": "Host reproduz vídeos Bink pela ponte FFmpeg, mas alguns jogos podem apresentar problemas.\nGuest usa o descodificador do próprio motor do jogo, que o SharpEmu atualmente suporta apenas parcialmente.\nSkip ignora os vídeos Bink, o que pode facilitar o desenvolvimento.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Ignorar",
"_languageName": "Português (Portugal)",
"Page.Library": "Biblioteca",
@@ -104,6 +109,17 @@
"Launch.Idle": "Inativo",
"Launch.Console": "≡ Consola",
"Launch.Launch": "▶ Iniciar",
+ "Launch.CustomEnv": "Iniciar com variáveis de ambiente personalizadas",
+ "Launch.CustomEnv.Title": "Iniciar com variáveis de ambiente personalizadas",
+ "Launch.CustomEnv.Desc": "Introduza uma variável de ambiente por linha no formato NOME=VALOR. Os valores personalizados substituem as definições da GUI e específicas do jogo com o mesmo nome.",
+ "Launch.CustomEnv.Documentation": "Ver variáveis de ambiente não documentadas ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_EXEMPLO=1",
+ "Launch.CustomEnv.SaveGame": "Guardar para o jogo",
+ "Launch.CustomEnv.SaveGlobal": "Guardar globalmente",
+ "Launch.CustomEnv.Play": "Jogar",
+ "Launch.CustomEnv.Invalid": "Variável de ambiente inválida: {0}",
+ "Launch.CustomEnv.SavedGame": "Guardado para este jogo.",
+ "Launch.CustomEnv.SavedGlobal": "Guardado globalmente.",
"Launch.Stop": "■ Parar",
"Launch.Running": "Em execução — {0}",
"Launch.Stopping": "A parar…",
diff --git a/src/SharpEmu.GUI/Languages/ru.json b/src/SharpEmu.GUI/Languages/ru.json
index f48f87f..6d68ec2 100644
--- a/src/SharpEmu.GUI/Languages/ru.json
+++ b/src/SharpEmu.GUI/Languages/ru.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Воспроизведение видео Bink",
+ "Options.Env.BinkPlayback.Desc": "Host воспроизводит видео Bink через мост FFmpeg, однако в некоторых играх могут возникать проблемы.\nGuest использует собственный декодер игрового движка, который SharpEmu сейчас поддерживает лишь частично.\nSkip пропускает видео Bink, что может упростить разработку.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Пропустить",
"_languageName": "Русский",
"Page.Library": "Библиотека",
@@ -140,6 +145,17 @@
"Launch.Idle": "Ожидание",
"Launch.Console": "≡ Консоль",
"Launch.Launch": "▶ Запустить",
+ "Launch.CustomEnv": "Запустить с пользовательскими переменными среды",
+ "Launch.CustomEnv.Title": "Запустить с пользовательскими переменными среды",
+ "Launch.CustomEnv.Desc": "Введите по одной переменной среды на строку в формате ИМЯ=ЗНАЧЕНИЕ. Пользовательские значения переопределяют одноимённые настройки GUI и игры.",
+ "Launch.CustomEnv.Documentation": "Показать недокументированные переменные среды ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_PRIMER=1",
+ "Launch.CustomEnv.SaveGame": "Сохранить для игры",
+ "Launch.CustomEnv.SaveGlobal": "Сохранить глобально",
+ "Launch.CustomEnv.Play": "Играть",
+ "Launch.CustomEnv.Invalid": "Недопустимая переменная среды: {0}",
+ "Launch.CustomEnv.SavedGame": "Сохранено для этой игры.",
+ "Launch.CustomEnv.SavedGlobal": "Сохранено глобально.",
"Launch.Stop": "■ Остановить",
"Launch.Running": "Запущено - {0}",
"Launch.Stopping": "Остановка…",
diff --git a/src/SharpEmu.GUI/Languages/tr.json b/src/SharpEmu.GUI/Languages/tr.json
index e5175a1..849bd82 100644
--- a/src/SharpEmu.GUI/Languages/tr.json
+++ b/src/SharpEmu.GUI/Languages/tr.json
@@ -1,4 +1,9 @@
{
+ "Options.Env.BinkPlayback.Label": "Bink video oynatma",
+ "Options.Env.BinkPlayback.Desc": "Host, Bink videolarını FFmpeg köprüsüyle oynatır ancak bazı oyunlarda sorunlarla karşılaşabilir.\nGuest, oyun motorunun kendi kod çözücüsünü kullanır ancak SharpEmu bunu şu anda yalnızca kısmen desteklemektedir.\nSkip, Bink videolarını atlar; bu, geliştirmeyi kolaylaştırabilir.",
+ "Options.Env.BinkPlayback.Host": "Host (FFmpeg)",
+ "Options.Env.BinkPlayback.Guest": "Guest",
+ "Options.Env.BinkPlayback.Skip": "Atla",
"_languageName": "Türkçe",
"Page.Library": "Kütüphane",
@@ -108,6 +113,17 @@
"Launch.Idle": "Boşta",
"Launch.Console": "≡ Konsol",
"Launch.Launch": "▶ Başlat",
+ "Launch.CustomEnv": "Özel env ile başlat",
+ "Launch.CustomEnv.Title": "Özel env ile başlat",
+ "Launch.CustomEnv.Desc": "Ortam değişkenlerini NAME=VALUE biçiminde her satıra bir tane yazın. Özel değerler, aynı isimdeki GUI ve oyuna özel ortam ayarlarını geçersiz kılar.",
+ "Launch.CustomEnv.Documentation": "Belgelenmemiş ortam değişkenlerini görüntüle ↗",
+ "Launch.CustomEnv.Placeholder": "SHARPEMU_ORNEK=1",
+ "Launch.CustomEnv.SaveGame": "Oyun için kaydet",
+ "Launch.CustomEnv.SaveGlobal": "Genel olarak kaydet",
+ "Launch.CustomEnv.Play": "Oyna",
+ "Launch.CustomEnv.Invalid": "Geçersiz ortam değişkeni: {0}",
+ "Launch.CustomEnv.SavedGame": "Bu oyun için kaydedildi.",
+ "Launch.CustomEnv.SavedGlobal": "Genel olarak kaydedildi.",
"Launch.Stop": "■ Durdur",
"Launch.Running": "Çalışıyor — {0}",
"Launch.Stopping": "Durduruluyor…",
diff --git a/src/SharpEmu.GUI/MainWindow.GameOptions.cs b/src/SharpEmu.GUI/MainWindow.GameOptions.cs
index dd4e0a1..1f5c1e9 100644
--- a/src/SharpEmu.GUI/MainWindow.GameOptions.cs
+++ b/src/SharpEmu.GUI/MainWindow.GameOptions.cs
@@ -273,6 +273,7 @@ public partial class MainWindow
VSync = GameVSyncToggle.IsChecked == true,
HdrMode = SelectedComboText(GameHdrModeBox, "Auto"),
EnvironmentToggles = BuildGameEnvironmentEntries(),
+ CustomEnvironmentVariables = PerGameSettings.Load(_gameSettingsTitleId)?.CustomEnvironmentVariables,
};
settings.RemoveInheritedValues(_settings);
settings.Save(_gameSettingsTitleId);
diff --git a/src/SharpEmu.GUI/MainWindow.axaml b/src/SharpEmu.GUI/MainWindow.axaml
index 433cde6..af5598b 100644
--- a/src/SharpEmu.GUI/MainWindow.axaml
+++ b/src/SharpEmu.GUI/MainWindow.axaml
@@ -339,6 +339,18 @@ SPDX-License-Identifier: GPL-2.0-or-later
Classes="playButton"
Content="Launch"
IsEnabled="False" />
+
+
+
+
+
+
diff --git a/src/SharpEmu.GUI/MainWindow.axaml.cs b/src/SharpEmu.GUI/MainWindow.axaml.cs
index 8772a11..94f36cc 100644
--- a/src/SharpEmu.GUI/MainWindow.axaml.cs
+++ b/src/SharpEmu.GUI/MainWindow.axaml.cs
@@ -83,6 +83,12 @@ public partial class MainWindow : Window
LocalizedChoice.FromKey("On", "Common.On"),
LocalizedChoice.FromKey("Off", "Common.Off"),
];
+ private readonly LocalizedChoice[] _binkPlaybackChoices =
+ [
+ LocalizedChoice.FromKey("Host", "Options.Env.BinkPlayback.Host"),
+ LocalizedChoice.FromKey("Guest", "Options.Env.BinkPlayback.Guest"),
+ LocalizedChoice.FromKey("Skip", "Options.Env.BinkPlayback.Skip"),
+ ];
private readonly List _allGames = new();
private readonly ObservableCollection _visibleGames = new();
private readonly LibraryTileCollection _libraryTiles;
@@ -216,6 +222,7 @@ public partial class MainWindow : Window
LaunchSelected();
}
};
+ LaunchCustomEnvButton.Click += async (_, _) => await OpenCustomEnvironmentDialogAsync();
ClearLogButton.Click += (_, _) => { _consoleLines.Clear(); _allConsoleLines.Clear(); };
CopyLogButton.Click += async (_, _) => await CopyConsoleAsync();
DetachConsoleButton.Click += (_, _) => ShowConsoleWindow();
@@ -276,6 +283,8 @@ public partial class MainWindow : Window
SetEnvironmentToggle("SHARPEMU_DISABLE_IMPORT_LOOP_GUARD", EnvLoopGuardToggle.IsChecked == true);
EnvWritableApp0Toggle.IsCheckedChanged += (_, _) =>
SetEnvironmentToggle("SHARPEMU_WRITABLE_APP0", EnvWritableApp0Toggle.IsChecked == true);
+ BinkPlaybackBox.SelectionChanged += (_, _) =>
+ _settings.BinkPlaybackMode = SelectedComboText(BinkPlaybackBox, "Host");
EnvVkValidationToggle.IsCheckedChanged += (_, _) =>
SetEnvironmentToggle("SHARPEMU_VK_VALIDATION", EnvVkValidationToggle.IsChecked == true);
EnvDumpSpirvToggle.IsCheckedChanged += (_, _) =>
@@ -355,7 +364,7 @@ public partial class MainWindow : Window
{
Process.Start(new ProcessStartInfo
{
- FileName = "https://github.com/sharpemu/sharpemu",
+ FileName = ProjectLinks.RepositoryUrl,
UseShellExecute = true
});
};
@@ -378,8 +387,7 @@ public partial class MainWindow : Window
Process.Start(new ProcessStartInfo
{
- FileName =
- $"https://github.com/sharpemu/sharpemu/commit/{_latestCommitSha}",
+ FileName = ProjectLinks.CommitUrl(_latestCommitSha),
UseShellExecute = true
});
};
@@ -658,16 +666,13 @@ public partial class MainWindow : Window
}
private async Task LoadLatestCommitAsync()
{
- const string apiUrl =
- "https://api.github.com/repos/sharpemu/sharpemu/commits/main";
-
_latestCommitSha = null;
LatestCommitHashText.Content = "Loading…";
LatestCommitHashText.IsEnabled = false;
try
{
- using var response = await GithubHttpClient.GetAsync(apiUrl);
+ using var response = await GithubHttpClient.GetAsync(ProjectLinks.LatestCommitApiUrl);
var responseBody =
(await response.Content.ReadAsStringAsync()).Trim();
@@ -1168,6 +1173,7 @@ public partial class MainWindow : Window
WindowModeBox.ItemsSource = _windowModeChoices;
ScalingModeBox.ItemsSource = _scalingModeChoices;
HdrModeBox.ItemsSource = _hdrModeChoices;
+ BinkPlaybackBox.ItemsSource = _binkPlaybackChoices;
}
private void RefreshLocalizedChoices()
@@ -1178,6 +1184,7 @@ public partial class MainWindow : Window
RefreshChoices(_windowModeChoices);
RefreshChoices(_scalingModeChoices);
RefreshChoices(_hdrModeChoices);
+ RefreshChoices(_binkPlaybackChoices);
}
private static void RefreshChoices(IEnumerable choices)
@@ -1219,6 +1226,7 @@ public partial class MainWindow : Window
EnvBthidToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_BTHID_UNAVAILABLE");
EnvLoopGuardToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_DISABLE_IMPORT_LOOP_GUARD");
EnvWritableApp0Toggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_WRITABLE_APP0");
+ BinkPlaybackBox.SelectedIndex = ChoiceIndex(_settings.BinkPlaybackMode, "Host", "Guest", "Skip");
EnvVkValidationToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_VK_VALIDATION");
EnvDumpSpirvToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_DUMP_SPIRV");
EnvLogDirectMemoryToggle.IsChecked = _settings.EnvironmentToggles.Contains("SHARPEMU_LOG_DIRECT_MEMORY");
@@ -1458,6 +1466,7 @@ public partial class MainWindow : Window
}
private const string DefaultProfileEnvironmentName = "SHARPEMU_DEFAULT_PROFILE";
+ private const string BinkModeEnvironmentName = "SHARPEMU_BINK_MODE";
private string SelectedLogLevel()
{
@@ -2330,6 +2339,34 @@ public partial class MainWindow : Window
}
}
+ private async Task OpenCustomEnvironmentDialogAsync()
+ {
+ if (_isRunning || GameList.SelectedItem is not GameEntry game)
+ {
+ return;
+ }
+
+ var perGame = PerGameSettings.Load(game.TitleId);
+ var initialEntries = CustomEnvironmentVariables.Merge(
+ GlobalCustomEnvironmentSettings.Load(),
+ perGame?.CustomEnvironmentVariables);
+ var dialog = new CustomEnvironmentDialog(game.TitleId, initialEntries);
+ dialog.SaveGlobalRequested += entries => GlobalCustomEnvironmentSettings.Save(entries);
+ dialog.SaveGameRequested += (titleId, entries) =>
+ {
+ var settings = PerGameSettings.Load(titleId) ?? new PerGameSettings();
+ settings.CustomEnvironmentVariables = entries.Count == 0 ? null : entries.ToList();
+ settings.RemoveInheritedValues(_settings);
+ settings.Save(titleId);
+ };
+
+ var customEntries = await dialog.ShowDialog?>(this);
+ if (customEntries is not null && !_isRunning)
+ {
+ Launch(game.Path, game.Name, game.TitleId, customEntries);
+ }
+ }
+
private void LaunchSelected()
{
if (GameList.SelectedItem is GameEntry game)
@@ -2338,7 +2375,11 @@ public partial class MainWindow : Window
}
}
- private void Launch(string ebootPath, string displayName, string? titleId = null)
+ private void Launch(
+ string ebootPath,
+ string displayName,
+ string? titleId = null,
+ IReadOnlyList? oneShotCustomEnvironment = null)
{
if (_isRunning)
{
@@ -2349,7 +2390,12 @@ public partial class MainWindow : Window
? _allGames.FirstOrDefault(game =>
game.Path.Equals(ebootPath, GameLibraryPath.Comparison))?.TitleId
: titleId;
- var effective = EffectiveLaunchSettings.Resolve(_settings, PerGameSettings.Load(resolvedTitleId));
+ var perGame = PerGameSettings.Load(resolvedTitleId);
+ var effective = EffectiveLaunchSettings.Resolve(_settings, perGame);
+ var customEnvironment = CustomEnvironmentVariables.Merge(
+ GlobalCustomEnvironmentSettings.Load(),
+ perGame?.CustomEnvironmentVariables,
+ oneShotCustomEnvironment);
_sndPreview.Stop();
_consoleLines.Clear();
@@ -2395,11 +2441,33 @@ public partial class MainWindow : Window
GuiSettings.NormalizeDefaultProfile(_settings.DefaultProfile));
_appliedEnvironmentVariables.Add(DefaultProfileEnvironmentName);
+ Environment.SetEnvironmentVariable(
+ BinkModeEnvironmentName,
+ _settings.BinkPlaybackMode switch
+ {
+ "Guest" => "guest",
+ "Skip" => "skip",
+ _ => "native",
+ });
+ _appliedEnvironmentVariables.Add(BinkModeEnvironmentName);
+
Environment.SetEnvironmentVariable(
"SHARPEMU_RENDER_SCALE",
_settings.RenderResolutionScale.ToString(
"0.###",
System.Globalization.CultureInfo.InvariantCulture));
+ _appliedEnvironmentVariables.Add("SHARPEMU_RENDER_SCALE");
+
+ foreach (var entry in customEnvironment)
+ {
+ if (!CustomEnvironmentVariables.TryParseEntry(entry, out var name, out var value))
+ {
+ continue;
+ }
+
+ Environment.SetEnvironmentVariable(name, value);
+ _appliedEnvironmentVariables.Add(name);
+ }
if (SharpEmuLog.TryParseLevel(effective.LogLevel, out var logLevel))
{
@@ -2688,6 +2756,8 @@ public partial class MainWindow : Window
LaunchButton.IsEnabled = GameList.SelectedItem is GameEntry;
}
+ LaunchCustomEnvButton.IsEnabled = !_isRunning && GameList.SelectedItem is GameEntry;
+
GameSettingsButton.IsEnabled =
GameList.SelectedItem is GameEntry game &&
!string.IsNullOrWhiteSpace(game.TitleId);
diff --git a/src/SharpEmu.GUI/PerGameSettings.cs b/src/SharpEmu.GUI/PerGameSettings.cs
index 43846e4..12873f5 100644
--- a/src/SharpEmu.GUI/PerGameSettings.cs
+++ b/src/SharpEmu.GUI/PerGameSettings.cs
@@ -37,6 +37,8 @@ public sealed class PerGameSettings
public List? EnvironmentToggles { get; set; }
+ public List? CustomEnvironmentVariables { get; set; }
+
[JsonIgnore]
public bool IsEmpty =>
LogLevel is null &&
@@ -50,7 +52,8 @@ public sealed class PerGameSettings
ScalingMode is null &&
VSync is null &&
HdrMode is null &&
- EnvironmentToggles is null;
+ EnvironmentToggles is null &&
+ CustomEnvironmentVariables is null;
public static string DirectoryPath =>
Path.Combine(AppContext.BaseDirectory, "user", "custom_configs");
@@ -88,6 +91,12 @@ public sealed class PerGameSettings
{
settings.EnvironmentToggles = toggles.Where(entry => !string.IsNullOrEmpty(entry)).ToList();
}
+ if (settings?.CustomEnvironmentVariables is { } customEnvironmentVariables)
+ {
+ settings.CustomEnvironmentVariables = customEnvironmentVariables
+ .Where(entry => !string.IsNullOrWhiteSpace(entry))
+ .ToList();
+ }
return settings;
}
@@ -158,6 +167,7 @@ public sealed class PerGameSettings
{
EnvironmentToggles = null;
}
+
}
public void Save(string titleId)
diff --git a/src/SharpEmu.GUI/ProjectLinks.cs b/src/SharpEmu.GUI/ProjectLinks.cs
new file mode 100644
index 0000000..1f59fa1
--- /dev/null
+++ b/src/SharpEmu.GUI/ProjectLinks.cs
@@ -0,0 +1,19 @@
+// Copyright (C) 2026 SharpEmu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+namespace SharpEmu.GUI;
+
+internal static class ProjectLinks
+{
+ private const string RepositorySlug = "sharpemu/sharpemu";
+
+ public static string RepositoryUrl => $"https://github.com/{RepositorySlug}";
+
+ public static string LatestCommitApiUrl =>
+ $"https://api.github.com/repos/{RepositorySlug}/commits/main";
+
+ public static string CommitUrl(string sha) => $"{RepositoryUrl}/commit/{sha}";
+
+ public static string DocumentUrl(string path) =>
+ $"{RepositoryUrl}/blob/main/{path.TrimStart('/')}";
+}