Mesen2/NewUI/ViewModels/MainMenuViewModel.cs

944 lines
34 KiB
C#

using Avalonia.Controls;
using Mesen.Config;
using Mesen.Config.Shortcuts;
using Mesen.Controls;
using Mesen.Debugger.Utilities;
using Mesen.Debugger.ViewModels;
using Mesen.Debugger.Windows;
using Mesen.Interop;
using Mesen.Localization;
using Mesen.Utilities;
using Mesen.Windows;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Mesen.ViewModels
{
public class MainMenuViewModel : ViewModelBase
{
public MainWindowViewModel MainWindow { get; set; }
[Reactive] public bool IsGameRunning { get; private set; }
[Reactive] public bool IsFdsGame { get; private set; }
[Reactive] public bool IsVsSystemGame { get; private set; }
[Reactive] public bool IsVsDualSystemGame { get; private set; }
[Reactive] public bool IsNesGame { get; private set; }
[Reactive] public bool IsGbGame { get; private set; }
[Reactive] public ObservableCollection<RecentItem> RecentItems { get; private set; }
[Reactive] public bool HasRecentItems { get; private set; }
[Reactive] public List<object> FileMenuItems { get; set; } = new();
[Reactive] public List<object> GameMenuItems { get; set; } = new();
[Reactive] public List<object> OptionsMenuItems { get; set; } = new();
[Reactive] public List<object> ToolsMenuItems { get; set; } = new();
[Reactive] public List<object> DebugMenuItems { get; set; } = new();
[Reactive] public List<object> HelpMenuItems { get; set; } = new();
private ConfigWindow? _cfgWindow = null;
[Obsolete("For designer only")]
public MainMenuViewModel() : this(new MainWindowViewModel()) { }
public MainMenuViewModel(MainWindowViewModel windowModel)
{
MainWindow = windowModel;
RecentItems = ConfigManager.Config.RecentFiles.Items;
this.WhenAnyValue(x => x.RecentItems.Count).Subscribe(count => {
HasRecentItems = count > 0;
});
this.WhenAnyValue(x => x.MainWindow.RomInfo).Subscribe(x => {
IsGameRunning = x.Format != RomFormat.Unknown;
IsFdsGame = x.Format == RomFormat.Fds;
IsVsSystemGame = x.Format == RomFormat.VsSystem || x.Format == RomFormat.VsDualSystem;
IsVsDualSystemGame = x.Format == RomFormat.VsDualSystem;
});
}
private void OpenConfig(MainWindow wnd, ConfigWindowTab tab)
{
if(_cfgWindow == null) {
_cfgWindow = new ConfigWindow(tab);
_cfgWindow.Closed += cfgWindow_Closed;
_cfgWindow.ShowCentered((Control)wnd);
} else {
(_cfgWindow.DataContext as ConfigViewModel)!.SelectTab(tab);
_cfgWindow.Activate();
}
}
private void cfgWindow_Closed(object? sender, EventArgs e)
{
_cfgWindow = null;
if(ConfigManager.Config.Preferences.DisableGameSelectionScreen && MainWindow.RecentGames.Visible) {
MainWindow.RecentGames.Visible = false;
} else if(!ConfigManager.Config.Preferences.DisableGameSelectionScreen && !IsGameRunning) {
MainWindow.RecentGames.Init(GameScreenMode.RecentGames);
}
}
public void Initialize(MainWindow wnd)
{
InitFileMenu(wnd);
InitGameMenu(wnd);
InitOptionsMenu(wnd);
InitToolMenu(wnd);
InitDebugMenu(wnd);
InitHelpMenu(wnd);
}
private void InitFileMenu(MainWindow wnd)
{
FileMenuItems = new List<object>() {
new MainMenuAction(EmulatorShortcut.OpenFile) { ActionType = ActionType.Open },
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.SaveState,
SubActions = new List<object> {
GetSaveStateMenuItem(1, true),
GetSaveStateMenuItem(2, true),
GetSaveStateMenuItem(3, true),
GetSaveStateMenuItem(4, true),
GetSaveStateMenuItem(5, true),
GetSaveStateMenuItem(6, true),
GetSaveStateMenuItem(7, true),
GetSaveStateMenuItem(8, true),
GetSaveStateMenuItem(9, true),
GetSaveStateMenuItem(10, true),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.SaveStateDialog) { ActionType = ActionType.SaveStateDialog },
new MainMenuAction(EmulatorShortcut.SaveStateToFile) { ActionType = ActionType.SaveStateToFile },
}
},
new MainMenuAction() {
ActionType = ActionType.LoadState,
SubActions = new List<object> {
GetSaveStateMenuItem(1, false),
GetSaveStateMenuItem(2, false),
GetSaveStateMenuItem(3, false),
GetSaveStateMenuItem(4, false),
GetSaveStateMenuItem(5, false),
GetSaveStateMenuItem(6, false),
GetSaveStateMenuItem(7, false),
GetSaveStateMenuItem(8, false),
GetSaveStateMenuItem(9, false),
GetSaveStateMenuItem(10, false),
new ContextMenuSeparator(),
GetSaveStateMenuItem(11, false),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.LoadStateDialog) { ActionType = ActionType.LoadStateDialog },
new MainMenuAction(EmulatorShortcut.LoadStateFromFile) { ActionType = ActionType.LoadStateFromFile },
}
},
new MainMenuAction(EmulatorShortcut.LoadLastSession) {
ActionType = ActionType.LoadLastSession,
IsEnabled = () => File.Exists(Path.Combine(ConfigManager.RecentGamesFolder, MainWindow.RomInfo.GetRomName() + ".rgd"))
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.RecentFiles,
IsEnabled = () => HasRecentItems,
SubActions = new List<object>() {
GetRecentMenuItem(0),
GetRecentMenuItem(1),
GetRecentMenuItem(2),
GetRecentMenuItem(3),
GetRecentMenuItem(4),
GetRecentMenuItem(5),
GetRecentMenuItem(6),
GetRecentMenuItem(7),
GetRecentMenuItem(8),
GetRecentMenuItem(9)
}
},
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.Exit) { ActionType = ActionType.Exit },
};
}
private MainMenuAction GetRecentMenuItem(int index)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
DynamicText = () => index < RecentItems.Count ? RecentItems[index].DisplayText : "",
CustomShortcutText = () => index < RecentItems.Count ? RecentItems[index].ShortenedFolder : "",
IsVisible = () => index < RecentItems.Count,
OnClick = () => {
if(index < RecentItems.Count) {
LoadRomHelper.LoadRom(RecentItems[index].RomFile, RecentItems[index].PatchFile);
}
}
};
}
private MainMenuAction GetSaveStateMenuItem(int slot, bool forSave)
{
EmulatorShortcut shortcut;
if(forSave) {
shortcut = (EmulatorShortcut)((int)EmulatorShortcut.SaveStateSlot1 + slot - 1);
} else {
shortcut = (EmulatorShortcut)((int)EmulatorShortcut.LoadStateSlot1 + slot - 1);
}
bool isAutoSaveSlot = slot == 11;
return new MainMenuAction(shortcut) {
ActionType = ActionType.Custom,
DynamicText = () => {
string statePath = Path.Combine(ConfigManager.SaveStateFolder, EmuApi.GetRomInfo().GetRomName() + "_" + slot + ".mss");
string slotName = isAutoSaveSlot ? "Auto" : slot.ToString();
string header;
if(!File.Exists(statePath)) {
header = slotName + ". " + ResourceHelper.GetMessage("EmptyState");
} else {
DateTime dateTime = new FileInfo(statePath).LastWriteTime;
header = slotName + ". " + dateTime.ToShortDateString() + " " + dateTime.ToShortTimeString();
}
return header;
},
OnClick = () => {
if(forSave) {
EmuApi.SaveState((uint)slot);
} else {
EmuApi.LoadState((uint)slot);
}
}
};
}
private void InitGameMenu(MainWindow wnd)
{
GameMenuItems = new List<object>() {
new MainMenuAction(EmulatorShortcut.Pause) { ActionType = ActionType.Pause, IsVisible = () => !EmuApi.IsPaused() },
new MainMenuAction(EmulatorShortcut.Pause) { ActionType = ActionType.Resume, IsVisible = () => EmuApi.IsPaused() },
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.Reset) { ActionType = ActionType.Reset },
new MainMenuAction(EmulatorShortcut.PowerCycle) { ActionType = ActionType.PowerCycle },
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.PowerOff) { ActionType = ActionType.PowerOff },
new ContextMenuSeparator() { IsVisible = () => IsFdsGame },
new MainMenuAction() {
ActionType = ActionType.SelectDisk,
IsVisible = () => IsFdsGame,
SubActions = new List<object>() {
GetFdsInsertDiskItem(0),
GetFdsInsertDiskItem(1),
GetFdsInsertDiskItem(2),
GetFdsInsertDiskItem(3),
GetFdsInsertDiskItem(4),
GetFdsInsertDiskItem(5),
GetFdsInsertDiskItem(6),
GetFdsInsertDiskItem(7),
}
},
new MainMenuAction(EmulatorShortcut.FdsEjectDisk) {
ActionType = ActionType.EjectDisk,
IsVisible = () => IsFdsGame,
},
new ContextMenuSeparator() { IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin1) { ActionType = ActionType.InsertCoin1, IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin2) { ActionType = ActionType.InsertCoin2, IsVisible = () => IsVsSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin3) { ActionType = ActionType.InsertCoin3, IsVisible = () => IsVsDualSystemGame },
new MainMenuAction(EmulatorShortcut.VsInsertCoin4) { ActionType = ActionType.InsertCoin4, IsVisible = () => IsVsDualSystemGame }
};
}
private MainMenuAction GetFdsInsertDiskItem(int diskSide)
{
return new MainMenuAction(EmulatorShortcut.FdsInsertDiskNumber) {
ActionType = ActionType.Custom,
CustomText = "Disk " + ((diskSide / 2) + 1) + " Side " + ((diskSide % 2 == 0) ? "A" : "B"),
ShortcutParam = (uint)diskSide,
IsVisible = () => EmuApi.IsShortcutAllowed(EmulatorShortcut.FdsInsertDiskNumber, (uint)diskSide)
};
}
private void InitOptionsMenu(MainWindow wnd)
{
OptionsMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.Speed,
SubActions = new List<object> {
GetSpeedMenuItem(ActionType.NormalSpeed, 100),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.IncreaseSpeed) {
ActionType = ActionType.IncreaseSpeed
},
new MainMenuAction(EmulatorShortcut.DecreaseSpeed) {
ActionType = ActionType.DecreaseSpeed
},
GetSpeedMenuItem(ActionType.MaximumSpeed, 0, EmulatorShortcut.MaxSpeed),
new ContextMenuSeparator(),
GetSpeedMenuItem(ActionType.TripleSpeed, 300),
GetSpeedMenuItem(ActionType.DoubleSpeed, 200),
GetSpeedMenuItem(ActionType.HalfSpeed, 50),
GetSpeedMenuItem(ActionType.QuarterSpeed, 25),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.ToggleFps) {
ActionType = ActionType.ShowFps,
IsSelected = () => ConfigManager.Config.Preferences.ShowFps
}
}
},
new MainMenuAction() {
ActionType = ActionType.VideoScale,
SubActions = new List<object>() {
GetScaleMenuItem(1, EmulatorShortcut.SetScale1x),
GetScaleMenuItem(2, EmulatorShortcut.SetScale2x),
GetScaleMenuItem(3, EmulatorShortcut.SetScale3x),
GetScaleMenuItem(4, EmulatorShortcut.SetScale4x),
GetScaleMenuItem(5, EmulatorShortcut.SetScale5x),
GetScaleMenuItem(6, EmulatorShortcut.SetScale6x),
new ContextMenuSeparator(),
new MainMenuAction(EmulatorShortcut.ToggleFullscreen) {
ActionType = ActionType.Fullscreen
},
}
},
new MainMenuAction() {
ActionType = ActionType.VideoFilter,
SubActions = new List<object>() {
GetVideoFilterMenuItem(VideoFilterType.None),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.NTSC),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.xBRZ2x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ3x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ4x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ5x),
GetVideoFilterMenuItem(VideoFilterType.xBRZ6x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.HQ2x),
GetVideoFilterMenuItem(VideoFilterType.HQ3x),
GetVideoFilterMenuItem(VideoFilterType.HQ4x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.Scale2x),
GetVideoFilterMenuItem(VideoFilterType.Scale3x),
GetVideoFilterMenuItem(VideoFilterType.Scale4x),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType._2xSai),
GetVideoFilterMenuItem(VideoFilterType.Super2xSai),
GetVideoFilterMenuItem(VideoFilterType.SuperEagle),
new ContextMenuSeparator(),
GetVideoFilterMenuItem(VideoFilterType.Prescale2x),
GetVideoFilterMenuItem(VideoFilterType.Prescale3x),
GetVideoFilterMenuItem(VideoFilterType.Prescale4x),
GetVideoFilterMenuItem(VideoFilterType.Prescale6x),
GetVideoFilterMenuItem(VideoFilterType.Prescale8x),
GetVideoFilterMenuItem(VideoFilterType.Prescale10x)
}
},
new MainMenuAction() {
ActionType = ActionType.Region,
IsEnabled = () => IsGameRunning && MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
SubActions = new List<object>() {
GetRegionMenuItem(ConsoleRegion.Auto),
new ContextMenuSeparator(),
GetRegionMenuItem(ConsoleRegion.Ntsc),
GetRegionMenuItem(ConsoleRegion.Pal),
GetRegionMenuItem(ConsoleRegion.Dendy),
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Audio,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Audio)
},
new MainMenuAction() {
ActionType = ActionType.Emulation,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Emulation)
},
new MainMenuAction() {
ActionType = ActionType.Input,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Input)
},
new MainMenuAction() {
ActionType = ActionType.Video,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Video)
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Nes,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Nes)
},
new MainMenuAction() {
ActionType = ActionType.Snes,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Snes)
},
new MainMenuAction() {
ActionType = ActionType.Gameboy,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Gameboy)
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.Preferences,
OnClick = () => OpenConfig(wnd, ConfigWindowTab.Preferences)
}
};
}
private MainMenuAction GetRegionMenuItem(ConsoleRegion region)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetEnumText(region),
IsVisible = () => region switch {
ConsoleRegion.Ntsc => MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
ConsoleRegion.Pal => MainWindow.RomInfo.ConsoleType != ConsoleType.Gameboy,
ConsoleRegion.Dendy => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes,
ConsoleRegion.Auto or _ => true,
},
IsSelected = () => MainWindow.RomInfo.ConsoleType switch {
ConsoleType.Snes => ConfigManager.Config.Snes.Region == region,
ConsoleType.Nes => ConfigManager.Config.Nes.Region == region,
_ => region == ConsoleRegion.Auto
},
OnClick = () => {
switch(MainWindow.RomInfo.ConsoleType) {
case ConsoleType.Snes:
ConfigManager.Config.Snes.Region = region;
ConfigManager.Config.Snes.ApplyConfig();
break;
case ConsoleType.Nes:
ConfigManager.Config.Nes.Region = region;
ConfigManager.Config.Nes.ApplyConfig();
break;
default:
break;
}
}
};
}
private MainMenuAction GetVideoFilterMenuItem(VideoFilterType filter)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetEnumText(filter),
IsSelected = () => ConfigManager.Config.Video.VideoFilter == filter,
OnClick = () => {
ConfigManager.Config.Video.VideoFilter = filter;
ConfigManager.Config.Video.ApplyConfig();
}
};
}
private MainMenuAction GetScaleMenuItem(int scale, EmulatorShortcut shortcut)
{
return new MainMenuAction(shortcut) {
ActionType = ActionType.Custom,
CustomText = scale + "x",
IsSelected = () => (int)((double)MainWindow.RendererSize.Width / EmuApi.GetBaseScreenSize().Width) == scale
};
}
private MainMenuAction GetSpeedMenuItem(ActionType action, int speed, EmulatorShortcut? shortcut = null)
{
MainMenuAction item = new MainMenuAction(shortcut) {
ActionType = action,
IsSelected = () => ConfigManager.Config.Emulation.EmulationSpeed == speed,
};
if(shortcut == null) {
item.OnClick = () => {
ConfigManager.Config.Emulation.EmulationSpeed = (uint)speed;
ConfigManager.Config.Emulation.ApplyConfig();
};
}
return item;
}
private MainMenuAction GetMoviesMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.Movies,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Play,
IsEnabled = () => IsGameRunning && !RecordApi.MovieRecording() && !RecordApi.MoviePlaying(),
OnClick = async () => {
string? filename = await FileDialogHelper.OpenFile(ConfigManager.MovieFolder, wnd, FileDialogHelper.MesenMovieExt);
if(filename != null) {
RecordApi.MoviePlay(filename);
}
}
},
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.MovieRecording() && !RecordApi.MoviePlaying(),
OnClick = () => {
new MovieRecordWindow() {
DataContext = new MovieRecordConfigViewModel()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && (RecordApi.MovieRecording() || RecordApi.MoviePlaying()),
OnClick = async () => {
string? filename = await FileDialogHelper.OpenFile(ConfigManager.MovieFolder, wnd, FileDialogHelper.MesenMovieExt);
if(filename != null) {
RecordApi.MovieStop();
}
}
}
}
};
}
private void InitToolMenu(MainWindow wnd)
{
ToolsMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.Cheats,
IsEnabled = () => IsGameRunning,
OnClick = () => { }
},
new MainMenuAction() {
ActionType = ActionType.HistoryViewer,
IsEnabled = () => IsGameRunning,
OnClick = () => { }
},
GetMoviesMenu(wnd),
GetNetPlayMenu(wnd),
new ContextMenuSeparator(),
GetSoundRecorderMenu(wnd),
GetVideoRecorderMenu(wnd),
new ContextMenuSeparator() {
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes
},
new MainMenuAction() {
ActionType = ActionType.HdPacks,
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Nes,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.InstallHdPack,
OnClick = () => InstallHdPack(wnd)
},
new MainMenuAction() {
ActionType = ActionType.HdPackBuilder,
IsEnabled = () => false,
OnClick = () => { }
}
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.LogWindow,
OnClick = () => {
LogWindow? logWindow = ApplicationHelper.GetExistingWindow<LogWindow>();
if(logWindow != null) {
logWindow.Activate();
} else {
new LogWindow().ShowCentered((Control)wnd);
}
}
},
new MainMenuAction(EmulatorShortcut.TakeScreenshot) {
ActionType = ActionType.TakeScreenshot,
},
};
}
private MainMenuAction GetVideoRecorderMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.VideoRecorder,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.AviIsRecording(),
OnClick = () => {
new VideoRecordWindow() {
DataContext = new VideoRecordConfigViewModel()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && RecordApi.AviIsRecording(),
OnClick = () => {
RecordApi.AviStop();
}
}
}
};
}
private MainMenuAction GetSoundRecorderMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.SoundRecorder,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Record,
IsEnabled = () => IsGameRunning && !RecordApi.WaveIsRecording(),
OnClick = async () => {
string? filename = await FileDialogHelper.SaveFile(ConfigManager.WaveFolder, EmuApi.GetRomInfo().GetRomName() + ".wav", wnd, FileDialogHelper.WaveExt);
if(filename != null) {
RecordApi.WaveRecord(filename);
}
}
},
new MainMenuAction() {
ActionType = ActionType.Stop,
IsEnabled = () => IsGameRunning && RecordApi.WaveIsRecording(),
OnClick = () => {
RecordApi.WaveStop();
}
}
}
};
}
private MainMenuAction GetNetPlayMenu(MainWindow wnd)
{
return new MainMenuAction() {
ActionType = ActionType.NetPlay,
SubActions = new List<object> {
new MainMenuAction() {
ActionType = ActionType.Connect,
IsEnabled = () => !NetplayApi.IsConnected() && !NetplayApi.IsServerRunning(),
OnClick = () => {
new NetplayConnectWindow() {
DataContext = ConfigManager.Config.Netplay.Clone()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.Disconnect,
IsEnabled = () => NetplayApi.IsConnected(),
OnClick = () => {
NetplayApi.Disconnect();
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.StartServer,
IsEnabled = () => !NetplayApi.IsConnected() && !NetplayApi.IsServerRunning(),
OnClick = () => {
new NetplayStartServerWindow() {
DataContext = ConfigManager.Config.Netplay.Clone()
}.ShowCenteredDialog((Control)wnd);
}
},
new MainMenuAction() {
ActionType = ActionType.StopServer,
IsEnabled = () => NetplayApi.IsServerRunning(),
OnClick = () => {
NetplayApi.StopServer();
}
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.SelectController,
IsEnabled = () => NetplayApi.IsConnected() || NetplayApi.IsServerRunning(),
SubActions = new List<object> {
GetSelectControllerAction(0),
GetSelectControllerAction(1),
GetSelectControllerAction(2),
GetSelectControllerAction(3),
GetSelectControllerAction(4),
}
}
}
};
}
private MainMenuAction GetSelectControllerAction(int i)
{
return new MainMenuAction() {
ActionType = ActionType.Custom,
CustomText = ResourceHelper.GetMessage("Player") + " " + (i + 1) + " (" + ResourceHelper.GetEnumText(ConfigApi.GetControllerType(i)) + ")",
IsSelected = () => i == NetplayApi.NetPlayGetControllerPort(),
IsEnabled = () => (NetplayApi.NetPlayGetAvailableControllers() & (1 << i)) != 0,
OnClick = () => NetplayApi.NetPlaySelectController(i)
};
}
private void InitDebugMenu(Window wnd)
{
DebugMenuItems = new List<object>() {
new ContextMenuAction() {
ActionType = ActionType.OpenDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenDebugger),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(null))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSpcDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSpcDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Spc),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Spc))
},
new ContextMenuAction() {
ActionType = ActionType.OpenCx4Debugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenCx4Debugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Cx4),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Cx4))
},
new ContextMenuAction() {
ActionType = ActionType.OpenNecDspDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenNecDspDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.NecDsp),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.NecDsp))
},
new ContextMenuAction() {
ActionType = ActionType.OpenGsuDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGsuDebugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gsu),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gsu))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSa1Debugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSa1Debugger),
IsVisible = () => MainWindow.RomInfo.CpuTypes.Contains(CpuType.Sa1),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Sa1))
},
new ContextMenuAction() {
ActionType = ActionType.OpenGameboyDebugger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenGameboyDebugger),
IsVisible = () => MainWindow.RomInfo.ConsoleType == ConsoleType.Snes && MainWindow.RomInfo.CpuTypes.Contains(CpuType.Gameboy),
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebuggerWindow(CpuType.Gameboy))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenEventViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenEventViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new EventViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenMemoryTools,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenMemoryTools),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new MemoryToolsWindow(new MemoryToolsViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenRegisterViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenRegisterViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new RegisterViewerWindow(new RegisterViewerWindowViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenTraceLogger,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTraceLogger),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TraceLoggerWindow(new TraceLoggerViewModel()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenTilemapViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTilemapViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TilemapViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenTileViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenTileViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new TileViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenSpriteViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenSpriteViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new SpriteViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenPaletteViewer,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenPaletteViewer),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new PaletteViewerWindow(MainWindow.RomInfo.ConsoleType.GetMainCpuType()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenAssembler,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenAssembler),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new AssemblerWindow(new AssemblerWindowViewModel(MainWindow.RomInfo.ConsoleType.GetMainCpuType())))
},
new ContextMenuAction() {
ActionType = ActionType.OpenDebugLog,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenDebugLog),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new DebugLogWindow())
},
new ContextMenuAction() {
ActionType = ActionType.OpenProfiler,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenProfiler),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new ProfilerWindow(new ProfilerWindowViewModel()))
},
new ContextMenuAction() {
ActionType = ActionType.OpenScriptWindow,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenScriptWindow),
IsEnabled = () => IsGameRunning,
OnClick = () => DebugWindowManager.OpenDebugWindow(() => new ScriptWindow(new ScriptWindowViewModel()))
},
new ContextMenuSeparator(),
new ContextMenuAction() {
ActionType = ActionType.OpenDebugSettings,
Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.OpenDebugSettings),
OnClick = () => DebuggerConfigWindow.Open(DebugConfigWindowTab.Debugger, wnd)
}
};
DebugShortcutManager.RegisterActions(wnd, DebugMenuItems);
}
private void InitHelpMenu(Window wnd)
{
HelpMenuItems = new List<object>() {
new MainMenuAction() {
ActionType = ActionType.OnlineHelp,
OnClick = () => ApplicationHelper.OpenBrowser("https://www.mesen.ca/docs/")
},
new MainMenuAction() {
ActionType = ActionType.CheckForUpdates,
OnClick = () => { }
},
new MainMenuAction() {
ActionType = ActionType.ReportBug,
OnClick = () => { }
},
new ContextMenuSeparator(),
new MainMenuAction() {
ActionType = ActionType.About,
OnClick = () => {
new AboutWindow().ShowCenteredDialog((Control)wnd);
}
},
};
}
private async void InstallHdPack(Window wnd)
{
string? filename = await FileDialogHelper.OpenFile(null, wnd, FileDialogHelper.ZipExt);
if(filename == null) {
return;
}
try {
using(FileStream stream = File.Open(filename, FileMode.Open)) {
ZipArchive zip = new ZipArchive(stream);
//Find the hires.txt file
ZipArchiveEntry? hiresEntry = null;
foreach(ZipArchiveEntry entry in zip.Entries) {
if(entry.Name == "hires.txt") {
hiresEntry = entry;
break;
}
}
if(hiresEntry == null) {
await MesenMsgBox.Show(wnd, "InstallHdPackInvalidPack", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
using Stream entryStream = hiresEntry.Open();
using StreamReader reader = new StreamReader(entryStream);
string hiresData = reader.ReadToEnd();
RomInfo romInfo = EmuApi.GetRomInfo();
//If there's a "supportedRom" tag, check if it matches the current ROM
Regex supportedRomRegex = new Regex("<supportedRom>([^\\n]*)");
Match match = supportedRomRegex.Match(hiresData);
if(match.Success) {
if(!match.Groups[1].Value.ToUpper().Contains(romInfo.Sha1.ToUpper())) {
await MesenMsgBox.Show(wnd, "InstallHdPackWrongRom", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
//Extract HD pack
try {
string targetFolder = Path.Combine(ConfigManager.HdPackFolder, romInfo.GetRomName());
if(Directory.Exists(targetFolder)) {
//Warn if the folder already exists
if(await MesenMsgBox.Show(wnd, "InstallHdPackConfirmOverwrite", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, targetFolder) != DialogResult.OK) {
return;
}
} else {
Directory.CreateDirectory(targetFolder);
}
string hiresFileFolder = hiresEntry.FullName.Substring(0, hiresEntry.FullName.Length - "hires.txt".Length);
foreach(ZipArchiveEntry entry in zip.Entries) {
//Extract only the files in the same subfolder as the hires.txt file (and only if they have a name & size > 0)
if(!string.IsNullOrWhiteSpace(entry.Name) && entry.Length > 0 && entry.FullName.StartsWith(hiresFileFolder)) {
entry.ExtractToFile(Path.Combine(targetFolder, entry.Name), true);
}
}
} catch(Exception ex) {
await MesenMsgBox.Show(wnd, "InstallHdPackError", MessageBoxButtons.OK, MessageBoxIcon.Error, ex.ToString());
return;
}
//Turn on HD Pack support automatically after installation succeeds
if(!ConfigManager.Config.Nes.EnableHdPacks) {
ConfigManager.Config.Nes.EnableHdPacks = true;
ConfigManager.Config.Nes.ApplyConfig();
}
if(await MesenMsgBox.Show(wnd, "InstallHdPackConfirmReset", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) {
//Power cycle game if the user agrees
EmuApi.PowerCycle();
}
}
} catch {
//Invalid file (file missing, not a zip file, etc.)
await MesenMsgBox.Show(wnd, "InstallHdPackInvalidZipFile", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}