Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buildtest #9

Closed
wants to merge 49 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
9800da3
Let’s start again
IsaacMarovitz Jun 4, 2023
fe74d3b
Read folders and such
IsaacMarovitz Jun 4, 2023
98b3cd1
Remove Open Mod Folder menu items
IsaacMarovitz Jun 4, 2023
d291cd8
Fix folder opening, Selecting/deselecting
IsaacMarovitz Jun 4, 2023
99b7fe2
She works
IsaacMarovitz Jun 5, 2023
a4b69c5
Fix GTK
IsaacMarovitz Jun 5, 2023
e8d523b
AddMod
IsaacMarovitz Jun 5, 2023
83ef331
Delete
IsaacMarovitz Jun 5, 2023
600940d
Fix duplicate entries
IsaacMarovitz Jun 27, 2023
4b64616
Fix file check
IsaacMarovitz Jun 27, 2023
b14f808
Avalonia 11
IsaacMarovitz Aug 14, 2023
0aec0c5
Style fixes
IsaacMarovitz Aug 14, 2023
78eae90
Final style fixes
IsaacMarovitz Aug 14, 2023
73439b9
Might be too general
IsaacMarovitz Aug 14, 2023
3f2c2a1
Remove unnecessary using
IsaacMarovitz Aug 14, 2023
9979193
Enable new mods by default
IsaacMarovitz Aug 14, 2023
928b91b
More cleanup
IsaacMarovitz Aug 14, 2023
243654e
Fix saving metadata
IsaacMarovitz Aug 14, 2023
6dc8355
Dont deseralise ModMetadata several times
IsaacMarovitz Oct 23, 2023
288ad6f
Avalonia I hate you
IsaacMarovitz Oct 23, 2023
48d5bbf
Confirmation dialgoues
IsaacMarovitz Oct 23, 2023
c910c11
Allow selecting multiple folders
IsaacMarovitz Oct 24, 2023
fc8f819
Add back secondary folder
IsaacMarovitz Jan 11, 2024
a986fe3
Search both paths
IsaacMarovitz Jan 11, 2024
e0acdc4
Fix formatting
IsaacMarovitz Jan 11, 2024
0bae0d1
Add custom refresh interval target
Sep 22, 2023
4089ba9
revise naming, UX to conform closer to legacy
Oct 8, 2023
e6916ea
move setting to 'Hacks', tweak UI and tooltips accordingly
Oct 8, 2023
30552cc
Rename to VSyncMode internally, code cleanup
Jan 13, 2024
fc52e4f
Turn from Window -> Dialog
IsaacMarovitz Oct 30, 2023
793f830
Match cheats heading to other managers
IsaacMarovitz Oct 30, 2023
09214d3
Respect MVVM
IsaacMarovitz Jan 16, 2024
a665f92
initial Layout
IsaacMarovitz Oct 30, 2023
d4622c5
Tweak layout
IsaacMarovitz Oct 30, 2023
254e074
Format
IsaacMarovitz Jan 16, 2024
e5817a2
Fix Push Descriptors
riperiperi Jan 19, 2024
d76a023
Use push descriptor templates
riperiperi Jan 20, 2024
29a1356
Use reserved bindings
riperiperi Jan 20, 2024
61b66fd
Formatting
riperiperi Jan 20, 2024
961e73f
Vulkan: Enumerate Query Pool properly
riperiperi Jan 22, 2024
3368763
Merge pull request #6 from IsaacMarovitz/mod-manager
ryzendew Jan 23, 2024
d4954a2
Merge pull request #7 from IsaacMarovitz/cheat-refactor
ryzendew Jan 23, 2024
b751ead
Merge pull request #8 from jcm93/refreshinterval
ryzendew Jan 23, 2024
bd83221
Vulkan: Use staging buffer for temporary constants
riperiperi Jan 23, 2024
1b17ecc
Use temporary buffer for ConvertIndexBufferIndirect
riperiperi Jan 23, 2024
f2b895f
Simplify alignment passing for now
riperiperi Jan 24, 2024
5dcad74
Merge pull request #10 from riperiperi/perf/query-queue
ryzendew Jan 24, 2024
f5e120d
Merge pull request #11 from riperiperi/perf/push-descriptor
ryzendew Jan 24, 2024
a84a042
Merge pull request #12 from riperiperi/perf/helper-shader-staging
ryzendew Jan 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 93 additions & 9 deletions src/Ryujinx.Ava/AppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Size = Avalonia.Size;
using Switch = Ryujinx.HLE.Switch;
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;

namespace Ryujinx.Ava
{
Expand Down Expand Up @@ -188,6 +189,9 @@ public AppHost(
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
ConfigurationState.Instance.Graphics.VSyncMode.Event += UpdateVSyncMode;
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Event += UpdateCustomVSyncIntervalValue;
ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Event += UpdateCustomVSyncIntervalEnabled;

ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState;
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
Expand Down Expand Up @@ -235,6 +239,69 @@ private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool>
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
}

public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
{
if (Device != null)
{
Device.VSyncMode = e.NewValue;
Device.UpdateVSyncInterval();
}
//vulkan present mode may change in response, so recreate the swapchain
_renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue);

_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);

ConfigurationState.Instance.Graphics.VSyncMode.Value = e.NewValue;
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
}

public void VSyncModeToggle()
{
VSyncMode oldVSyncMode = Device.VSyncMode;
VSyncMode newVSyncMode = VSyncMode.Switch;
bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value;

switch (oldVSyncMode)
{
case VSyncMode.Switch:
newVSyncMode = VSyncMode.Unbounded;
break;
case VSyncMode.Unbounded:
if (customVSyncIntervalEnabled)
{
newVSyncMode = VSyncMode.Custom;
}
else
{
newVSyncMode = VSyncMode.Switch;
}

break;
case VSyncMode.Custom:
newVSyncMode = VSyncMode.Switch;
break;
}
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(oldVSyncMode, newVSyncMode));
}

private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs<int> e)
{
if (Device != null)
{
Device.TargetVSyncInterval = e.NewValue;
Device.UpdateVSyncInterval();
}
}

private void UpdateCustomVSyncIntervalEnabled(object sender, ReactiveEventArgs<bool> e)
{
if (Device != null)
{
Device.CustomVSyncIntervalEnabled = e.NewValue;
Device.UpdateVSyncInterval();
}
}

private void ShowCursor()
{
Dispatcher.UIThread.Post(() =>
Expand Down Expand Up @@ -777,7 +844,7 @@ private void InitializeSwitchInstance()
_viewModel.UiHandler,
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
(RegionCode)ConfigurationState.Instance.System.Region.Value,
ConfigurationState.Instance.Graphics.EnableVsync,
ConfigurationState.Instance.Graphics.VSyncMode,
ConfigurationState.Instance.System.EnableDockedMode,
ConfigurationState.Instance.System.EnablePtc,
ConfigurationState.Instance.System.EnableInternetAccess,
Expand All @@ -791,7 +858,8 @@ private void InitializeSwitchInstance()
ConfigurationState.Instance.System.AudioVolume,
ConfigurationState.Instance.System.UseHypervisor,
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value,
ConfigurationState.Instance.Multiplayer.Mode);
ConfigurationState.Instance.Multiplayer.Mode,
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value);

Device = new Switch(configuration);
}
Expand Down Expand Up @@ -916,7 +984,7 @@ private void RenderLoop()
Device.Gpu.SetGpuThread();
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);

_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
_renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode);

while (_isActive)
{
Expand Down Expand Up @@ -964,14 +1032,15 @@ public void UpdateStatus()
{
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
string vSyncMode = Device.VSyncMode.ToString();

if (GraphicsConfig.ResScale != 1)
{
dockedMode += $" ({GraphicsConfig.ResScale}x)";
}

StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
Device.EnableDeviceVsync,
vSyncMode,
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan ? "Vulkan" : "OpenGL",
dockedMode,
Expand Down Expand Up @@ -1063,9 +1132,16 @@ private bool UpdateFrame()
{
switch (currentHotkeyState)
{
case KeyboardHotkeyState.ToggleVSync:
Device.EnableDeviceVsync = !Device.EnableDeviceVsync;

case KeyboardHotkeyState.ToggleVSyncMode:
VSyncModeToggle();
break;
case KeyboardHotkeyState.CustomVSyncIntervalDecrement:
Device.DecrementCustomVSyncInterval();
_viewModel.CustomVSyncInterval -= 1;
break;
case KeyboardHotkeyState.CustomVSyncIntervalIncrement:
Device.IncrementCustomVSyncInterval();
_viewModel.CustomVSyncInterval += 1;
break;
case KeyboardHotkeyState.Screenshot:
ScreenshotRequested = true;
Expand Down Expand Up @@ -1152,9 +1228,9 @@ private KeyboardHotkeyState GetHotkeyState()
{
KeyboardHotkeyState state = KeyboardHotkeyState.None;

if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync))
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.VSyncMode))
{
state = KeyboardHotkeyState.ToggleVSync;
state = KeyboardHotkeyState.ToggleVSyncMode;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot))
{
Expand Down Expand Up @@ -1188,6 +1264,14 @@ private KeyboardHotkeyState GetHotkeyState()
{
state = KeyboardHotkeyState.VolumeDown;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalIncrement))
{
state = KeyboardHotkeyState.CustomVSyncIntervalIncrement;
}
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalDecrement))
{
state = KeyboardHotkeyState.CustomVSyncIntervalDecrement;
}

return state;
}
Expand Down
36 changes: 26 additions & 10 deletions src/Ryujinx.Ava/Assets/Locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
"GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window",
"GameListContextMenuManageDlc": "Manage DLC",
"GameListContextMenuManageDlcToolTip": "Opens the DLC management window",
"GameListContextMenuOpenModsDirectory": "Open Mods Directory",
"GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods",
"GameListContextMenuCacheManagement": "Cache Management",
"GameListContextMenuCacheManagementPurgePptc": "Queue PPTC Rebuild",
"GameListContextMenuCacheManagementPurgePptcToolTip": "Trigger PPTC to rebuild at boot time on the next game launch",
Expand Down Expand Up @@ -124,16 +122,27 @@
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latin American Spanish",
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Simplified Chinese",
"SettingsTabSystemSystemLanguageTraditionalChinese": "Traditional Chinese",
"SettingsTabSystemSystemTimeZone": "System TimeZone:",
"SettingsTabSystemSystemTimeZone": "System Time Zone:",
"SettingsTabSystemSystemTime": "System Time:",
"SettingsTabSystemEnableVsync": "VSync",
"SettingsTabSystemVSyncMode": "VSync:",
"SettingsTabSystemEnableCustomVSyncInterval": "Enable custom refresh rate (Experimental)",
"SettingsTabSystemVSyncModeSwitch": "On",
"SettingsTabSystemVSyncModeUnbounded": "Off",
"SettingsTabSystemVSyncModeCustom": "Custom Refresh Rate",
"SettingsTabSystemVSyncModeTooltip": "Emulated Vertical Sync. 'On' emulates the Switch's refresh rate of 60Hz. 'Off' is an unbounded refresh rate.",
"SettingsTabSystemVSyncModeTooltipCustom": "Emulated Vertical Sync. 'On' emulates the Switch's refresh rate of 60Hz. 'Off' is an unbounded refresh rate. 'Custom' emulates the specified custom refresh rate.",
"SettingsTabSystemEnableCustomVSyncIntervalTooltip": "Allows the user to specify an emulated refresh rate. In some titles, this may speed up or slow down the rate of gameplay logic. In other titles, it may allow for capping FPS at some multiple of the refresh rate, or lead to unpredictable behavior. This is an experimental feature, with no guarantees for how gameplay will be affected. \n\nLeave OFF if unsure.",
"SettingsTabSystemCustomVSyncIntervalValueTooltip": "The custom refresh rate target value.",
"SettingsTabSystemCustomVSyncIntervalSliderTooltip": "The custom refresh rate, as a percentage of the normal Switch refresh rate.",
"SettingsTabSystemCustomVSyncIntervalValue": "Custom Refresh Rate Value:",
"SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)",
"SettingsTabSystemEnableFsIntegrityChecks": "FS Integrity Checks",
"SettingsTabSystemAudioBackend": "Audio Backend:",
"SettingsTabSystemAudioBackendDummy": "Dummy",
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
"SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemCustomVSyncInterval": "Interval",
"SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": "May cause instability",
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
Expand Down Expand Up @@ -388,6 +397,7 @@
"DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.",
"DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
"DialogLoadNcaErrorMessage": "{0}. Errored File: {1}",
"DialogLoadModErrorMessage": "{0}. Errored File: {1}",
"DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!",
"DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.",
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
Expand All @@ -398,6 +408,8 @@
"DialogUpdateAddUpdateErrorMessage": "The specified file does not contain an update for the selected title!",
"DialogSettingsBackendThreadingWarningTitle": "Warning - Backend Threading",
"DialogSettingsBackendThreadingWarningMessage": "Ryujinx must be restarted after changing this option for it to apply fully. Depending on your platform, you may need to manually disable your driver's own multithreading when using Ryujinx's.",
"DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?",
"DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?",
"SettingsTabGraphicsFeaturesOptions": "Features",
"SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading:",
"CommonAuto": "Auto",
Expand Down Expand Up @@ -432,6 +444,7 @@
"DlcManagerRemoveAllButton": "Remove All",
"DlcManagerEnableAllButton": "Enable All",
"DlcManagerDisableAllButton": "Disable All",
"ModManagerDeleteAllButton": "Delete All",
"MenuBarOptionsChangeLanguage": "Change Language",
"MenuBarShowFileTypes": "Show File Types",
"CommonSort": "Sort",
Expand Down Expand Up @@ -506,6 +519,8 @@
"EnableInternetAccessTooltip": "Allows the emulated application to connect to the Internet.\n\nGames with a LAN mode can connect to each other when this is enabled and the systems are connected to the same access point. This includes real consoles as well.\n\nDoes NOT allow connecting to Nintendo servers. May cause crashing in certain games that try to connect to the Internet.\n\nLeave OFF if unsure.",
"GameListContextMenuManageCheatToolTip": "Manage Cheats",
"GameListContextMenuManageCheat": "Manage Cheats",
"GameListContextMenuManageModToolTip": "Manage Mods",
"GameListContextMenuManageMod": "Manage Mods",
"ControllerSettingsStickRange": "Range:",
"DialogStopEmulationTitle": "Ryujinx - Stop Emulation",
"DialogStopEmulationMessage": "Are you sure you want to stop emulation?",
Expand All @@ -517,8 +532,6 @@
"SettingsTabCpuMemory": "CPU Mode",
"DialogUpdaterFlatpakNotSupportedMessage": "Please update Ryujinx via FlatHub.",
"UpdaterDisabledWarningTitle": "Updater Disabled!",
"GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory",
"GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.",
"ControllerSettingsRotate90": "Rotate 90° Clockwise",
"IconSize": "Icon Size",
"IconSizeTooltip": "Change the size of game icons",
Expand Down Expand Up @@ -574,11 +587,13 @@
"RyujinxUpdater": "Ryujinx Updater",
"SettingsTabHotkeys": "Keyboard Hotkeys",
"SettingsTabHotkeysHotkeys": "Keyboard Hotkeys",
"SettingsTabHotkeysToggleVsyncHotkey": "Toggle VSync:",
"SettingsTabHotkeysToggleVSyncModeHotkey": "Toggle VSync mode:",
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
"SettingsTabHotkeysShowUiHotkey": "Show UI:",
"SettingsTabHotkeysPauseHotkey": "Pause:",
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
"SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey": "Raise custom refresh rate",
"SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey": "Lower custom refresh rate",
"ControllerMotionTitle": "Motion Control Settings",
"ControllerRumbleTitle": "Rumble Settings",
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
Expand All @@ -590,13 +605,14 @@
"Writable": "Writable",
"SelectDlcDialogTitle": "Select DLC files",
"SelectUpdateDialogTitle": "Select update files",
"SelectModDialogTitle": "Select mod directory",
"UserProfileWindowTitle": "User Profiles Manager",
"CheatWindowTitle": "Cheats Manager",
"DlcWindowTitle": "Manage Downloadable Content for {0} ({1})",
"UpdateWindowTitle": "Title Update Manager",
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
"BuildId": "BuildId:",
"CheatWindowHeading": "Manage Cheats for {0} ({1})",
"BuildId": "Build ID:",
"DlcWindowHeading": "{0} Downloadable Content(s)",
"ModWindowHeading": "{0} Mod(s)",
"UserProfilesEditProfile": "Edit Selected",
"Cancel": "Cancel",
"Save": "Save",
Expand Down
5 changes: 3 additions & 2 deletions src/Ryujinx.Ava/Assets/Styles/Themes.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
<Color x:Key="SecondaryTextColor">#A0000000</Color>
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
<Color x:Key="Switch">#FF2EEAC9</Color>
<Color x:Key="Unbounded">#FFFF4554</Color>
<Color x:Key="Custom">#6483F5</Color>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Expand Down
4 changes: 3 additions & 1 deletion src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Ryujinx.Ava.Common
public enum KeyboardHotkeyState
{
None,
ToggleVSync,
ToggleVSyncMode,
Screenshot,
ShowUi,
Pause,
Expand All @@ -12,5 +12,7 @@ public enum KeyboardHotkeyState
ResScaleDown,
VolumeUp,
VolumeDown,
CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement,
}
}
10 changes: 3 additions & 7 deletions src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,9 @@
Header="{locale:Locale GameListContextMenuManageCheat}"
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
<MenuItem
Click="OpenModsDirectory_Click"
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
<MenuItem
Click="OpenSdModsDirectory_Click"
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
Click="OpenModManager_Click"
Header="{locale:Locale GameListContextMenuManageMod}"
ToolTip.Tip="{locale:Locale GameListContextMenuManageModToolTip}" />
<Separator />
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
<MenuItem
Expand Down
Loading
Loading