using ReactiveUI.Fody.Helpers; using System; using System.Collections.Generic; using System.Reactive.Linq; using System.Linq; using Mesen.Debugger.Utilities; using Mesen.Config; using Avalonia.Controls; using Avalonia.Input; using Mesen.Windows; using Avalonia.Collections; using Mesen.Interop; using Avalonia.Controls.Selection; using DataBoxControl; using System.ComponentModel; using Mesen.Utilities; using Avalonia.VisualTree; using Mesen.Debugger; namespace Mesen.ViewModels { public class CheatListWindowViewModel : DisposableViewModel { [Reactive] public MesenList Cheats { get; private set; } = new(); [Reactive] public List ToolbarActions { get; private set; } = new(); [Reactive] public bool DisableAllCheats { get; set; } = false; [Reactive] public SelectionModel Selection { get; set; } = new(); [Reactive] public SortState SortState { get; set; } = new(); public CheatWindowConfig Config { get; } private CheatCodes _cheatCodes = new(); public CheatListWindowViewModel() { Config = ConfigManager.Config.Cheats; Selection.SingleSelect = false; LoadCheats(); DisableAllCheats = Config.DisableAllCheats; SortState.SetColumnSort("Description", ListSortDirection.Ascending, true); Sort(); } private Dictionary> _comparers = new() { { "Enabled", (a, b) => a.Enabled.CompareTo(b.Enabled) }, { "Description", (a, b) => string.Compare(a.Description, b.Description, StringComparison.OrdinalIgnoreCase) }, { "Codes", (a, b) => string.Compare(a.Codes, b.Codes, StringComparison.OrdinalIgnoreCase) } }; public void Sort(object? param = null) { List selectedIndexes = Selection.SelectedIndexes.ToList(); List sortedCheats = new List(Cheats); SortHelper.SortList(sortedCheats, SortState.SortOrder, _comparers, "Codes"); Cheats.Replace(sortedCheats); Selection.SelectIndexes(selectedIndexes, Cheats.Count); } public void LoadCheats() { _cheatCodes = CheatCodes.LoadCheatCodes(); Cheats = new MesenList(_cheatCodes.Cheats); } public void SaveCheats() { ConfigManager.Config.Cheats.DisableAllCheats = DisableAllCheats; _cheatCodes.Cheats = new List(Cheats); _cheatCodes.Save(); } public void ApplyCheats() { if(DisableAllCheats) { EmuApi.ClearCheats(); } else { CheatCodes.ApplyCheats(Cheats); } } public void InitActions(Control parent) { List toolbarActions = GetActions(parent); toolbarActions.Add(new ContextMenuSeparator()); toolbarActions.Add(new ContextMenuAction() { ActionType = ActionType.CheatDatabase, AlwaysShowLabel = true, IsEnabled = () => MainWindowViewModel.Instance.RomInfo.ConsoleType switch { ConsoleType.Nes => true, ConsoleType.Snes => true, _ => false }, OnClick = async () => { ConsoleType consoleType = MainWindowViewModel.Instance.RomInfo.ConsoleType; CheatDbGameEntry? dbEntry = await CheatDatabaseWindow.Show(consoleType, parent); if(dbEntry != null && consoleType == MainWindowViewModel.Instance.RomInfo.ConsoleType) { List newCheats = new(); HashSet existingCheats = new(); foreach(CheatCode cheatCode in Cheats) { string key = cheatCode.Description + cheatCode.Codes + cheatCode.Type.ToString(); existingCheats.Add(key); } foreach(CheatDbCheatEntry cheatEntry in dbEntry.Cheats) { CheatCode newCheat = new CheatCode(); newCheat.Description = cheatEntry.Desc; newCheat.Enabled = false; newCheat.Type = GetCheatType(consoleType, cheatEntry.Code); newCheat.Codes = string.Join(Environment.NewLine, cheatEntry.Code.Split(";", StringSplitOptions.RemoveEmptyEntries)); string key = newCheat.Description + newCheat.Codes + newCheat.Type.ToString(); if(!existingCheats.Contains(key)) { newCheats.Add(newCheat); } } Cheats.AddRange(newCheats); Sort(); ApplyCheats(); } } }); ToolbarActions = toolbarActions; AddDisposables(DebugShortcutManager.CreateContextMenu(parent, GetActions(parent))); } private CheatType GetCheatType(ConsoleType consoleType, string code) { switch(consoleType) { case ConsoleType.Snes: return code.Contains("-") ? CheatType.SnesGameGenie : CheatType.SnesProActionReplay; case ConsoleType.Nes: return code.Contains(":") ? CheatType.NesCustom : CheatType.NesGameGenie; default: throw new Exception("Unsupported cheat type"); } } private List GetActions(Control parent) { return new List { new ContextMenuAction() { ActionType = ActionType.Add, AlwaysShowLabel = true, Shortcut = () => new DbgShortKeys(Key.Insert), OnClick = async () => { CheatCode newCheat = new CheatCode(); if(await CheatEditWindow.EditCheat(newCheat, parent)) { Cheats.Add(newCheat); Sort(); ApplyCheats(); } } }, new ContextMenuAction() { ActionType = ActionType.Edit, AlwaysShowLabel = true, IsEnabled = () => Selection.SelectedItems.Count == 1, OnClick = async () => { if(Selection.SelectedItem is CheatCode cheat) { await CheatEditWindow.EditCheat(cheat, parent); Sort(); ApplyCheats(); } } }, new ContextMenuAction() { ActionType = ActionType.Delete, AlwaysShowLabel = true, Shortcut = () => new DbgShortKeys(Key.Delete), IsEnabled = () => Selection.SelectedItems.Count > 0, OnClick = () => { foreach(CheatCode cheat in Selection.SelectedItems.Cast().ToArray()) { Cheats.Remove(cheat); } ApplyCheats(); } } }; } } }