From 1f2214fe2ab5efba33e01a0b4b395d1d84771d8f Mon Sep 17 00:00:00 2001 From: Gamaiel Zavala Date: Fri, 29 Mar 2024 17:12:05 -0600 Subject: [PATCH 1/3] Debugger: Tile Viewer - Add copy/paste tile memory --- UI/Debugger/Utilities/ContextMenuAction.cs | 6 ++ UI/Debugger/Utilities/MemCopyHelper.cs | 82 +++++++++++++++++++ UI/Debugger/ViewModels/TileViewerViewModel.cs | 22 +++++ UI/Localization/resources.en.xml | 2 + 4 files changed, 112 insertions(+) create mode 100644 UI/Debugger/Utilities/MemCopyHelper.cs diff --git a/UI/Debugger/Utilities/ContextMenuAction.cs b/UI/Debugger/Utilities/ContextMenuAction.cs index 35e39d3ad..19b7f884a 100644 --- a/UI/Debugger/Utilities/ContextMenuAction.cs +++ b/UI/Debugger/Utilities/ContextMenuAction.cs @@ -835,6 +835,12 @@ public enum ActionType [IconFile("HdPack")] CopyToHdPackFormat, + + [IconFile("CheatCode")] + CopyTileMemory, + + [IconFile("Paste")] + PasteTileMemory, [IconFile("Find")] CheatDatabase, diff --git a/UI/Debugger/Utilities/MemCopyHelper.cs b/UI/Debugger/Utilities/MemCopyHelper.cs new file mode 100644 index 000000000..42da426ce --- /dev/null +++ b/UI/Debugger/Utilities/MemCopyHelper.cs @@ -0,0 +1,82 @@ +using Avalonia; +using Mesen.Interop; +using Mesen.Utilities; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Tmds.DBus; + +namespace Mesen.Debugger.Utilities +{ + public static class MemCopyHelper + { + public static bool IsActionAllowed(MemoryType type) + { + return type switch { + MemoryType.NesPpuMemory => true, + MemoryType.NesChrRam => true, + MemoryType.NesChrRom => true, + MemoryType.NesPrgRom => true, + _ => false, + }; + } + + public static string ToString(AddressInfo tileAddr, int len) + { + StringBuilder sb = new StringBuilder(); + + if(tileAddr.Type == MemoryType.NesPpuMemory) { + tileAddr = DebugApi.GetAbsoluteAddress(tileAddr); + } + + switch(tileAddr.Type) { + case MemoryType.NesPrgRom: + case MemoryType.NesChrRom: + case MemoryType.NesChrRam: + for(int i = 0; i < len; i++) { + if (sb.Length > 0) { + sb.Append(" "); + } + sb.Append(DebugApi.GetMemoryValue(tileAddr.Type, (uint)(tileAddr.Address + i)).ToString("X2")); + } + break; + + default: + return ""; + } + + return sb.ToString(); + } + + public static void CopyTileMem(int address, MemoryType memoryType) + { + AddressInfo addr = new AddressInfo() { Address = address, Type = memoryType }; + string tileMem = MemCopyHelper.ToString(addr, 16); + + if(tileMem.Length > 0) { + ApplicationHelper.GetMainWindow()?.Clipboard?.SetTextAsync(tileMem); + } + } + + public static void PasteTileMem(int address, MemoryType memoryType) + { + var clipboard = ApplicationHelper.GetMainWindow()?.Clipboard; + if(clipboard != null) { + string? text = Task.Run(() => clipboard?.GetTextAsync()).GetAwaiter().GetResult(); + if(text != null) { + text = text.Replace("\n", "").Replace("\r", "").Replace(" ", ""); + if(Regex.IsMatch(text, "^[A-F0-9]{32}$", RegexOptions.IgnoreCase)) { + byte[] pastedData = HexUtilities.HexToArray(text); + for(int i = 0; i < 16; i++) { + DebugApi.SetMemoryValue(memoryType, (uint)(address + i), (byte)pastedData[i]); + } + } + } + } + } + } +} diff --git a/UI/Debugger/ViewModels/TileViewerViewModel.cs b/UI/Debugger/ViewModels/TileViewerViewModel.cs index fb3fee4d6..f97d3e61b 100644 --- a/UI/Debugger/ViewModels/TileViewerViewModel.cs +++ b/UI/Debugger/ViewModels/TileViewerViewModel.cs @@ -197,6 +197,28 @@ public TileViewerViewModel(CpuType cpuType, PictureViewer picViewer, Window? wnd HdPackCopyHelper.CopyToHdPackFormat(address, Config.Source, RawPalette, SelectedPalette, false); } } + }, + new ContextMenuAction() { + ActionType = ActionType.CopyTileMemory, + IsVisible = () => CpuType == CpuType.Nes, + IsEnabled = () => GetSelectedTileAddress() >= 0, + OnClick = () => { + int address = GetSelectedTileAddress(); + if(address >= 0) { + MemCopyHelper.CopyTileMem(address, Config.Source); + } + } + }, + new ContextMenuAction() { + ActionType = ActionType.PasteTileMemory, + IsVisible = () => CpuType == CpuType.Nes, + IsEnabled = () => GetSelectedTileAddress() >= 0, + OnClick = () => { + int address = GetSelectedTileAddress(); + if(address >= 0) { + MemCopyHelper.PasteTileMem(address, Config.Source); + } + } } }); diff --git a/UI/Localization/resources.en.xml b/UI/Localization/resources.en.xml index e390e7814..39e32ebe6 100644 --- a/UI/Localization/resources.en.xml +++ b/UI/Localization/resources.en.xml @@ -3296,6 +3296,8 @@ E Reset access stats Copy tile (HD pack format) + Copy tile (memory) + Paste tile (memory) Cheat database Use bilinear interpolation From e2c414de443db638999fbf0b0406a58d65696ac4 Mon Sep 17 00:00:00 2001 From: Gamaiel Zavala Date: Fri, 29 Mar 2024 17:45:14 -0600 Subject: [PATCH 2/3] Fix spacing --- UI/Debugger/Utilities/MemCopyHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UI/Debugger/Utilities/MemCopyHelper.cs b/UI/Debugger/Utilities/MemCopyHelper.cs index 42da426ce..299ba0ffc 100644 --- a/UI/Debugger/Utilities/MemCopyHelper.cs +++ b/UI/Debugger/Utilities/MemCopyHelper.cs @@ -38,9 +38,9 @@ public static string ToString(AddressInfo tileAddr, int len) case MemoryType.NesChrRom: case MemoryType.NesChrRam: for(int i = 0; i < len; i++) { - if (sb.Length > 0) { - sb.Append(" "); - } + if(sb.Length > 0) { + sb.Append(" "); + } sb.Append(DebugApi.GetMemoryValue(tileAddr.Type, (uint)(tileAddr.Address + i)).ToString("X2")); } break; From f3590f32432c1878b092448ceb9d4070fb863701 Mon Sep 17 00:00:00 2001 From: Gamaiel Zavala Date: Sat, 30 Mar 2024 13:56:56 -0600 Subject: [PATCH 3/3] Debugger: Tile Viewer - Make copy/paste tile compatible with all systems --- UI/Debugger/Utilities/MemCopyHelper.cs | 55 +++++++++---------- UI/Debugger/ViewModels/TileViewerViewModel.cs | 10 ++-- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/UI/Debugger/Utilities/MemCopyHelper.cs b/UI/Debugger/Utilities/MemCopyHelper.cs index 299ba0ffc..a5f01294d 100644 --- a/UI/Debugger/Utilities/MemCopyHelper.cs +++ b/UI/Debugger/Utilities/MemCopyHelper.cs @@ -14,17 +14,6 @@ namespace Mesen.Debugger.Utilities { public static class MemCopyHelper { - public static bool IsActionAllowed(MemoryType type) - { - return type switch { - MemoryType.NesPpuMemory => true, - MemoryType.NesChrRam => true, - MemoryType.NesChrRom => true, - MemoryType.NesPrgRom => true, - _ => false, - }; - } - public static string ToString(AddressInfo tileAddr, int len) { StringBuilder sb = new StringBuilder(); @@ -33,45 +22,51 @@ public static string ToString(AddressInfo tileAddr, int len) tileAddr = DebugApi.GetAbsoluteAddress(tileAddr); } - switch(tileAddr.Type) { - case MemoryType.NesPrgRom: - case MemoryType.NesChrRom: - case MemoryType.NesChrRam: - for(int i = 0; i < len; i++) { - if(sb.Length > 0) { - sb.Append(" "); - } - sb.Append(DebugApi.GetMemoryValue(tileAddr.Type, (uint)(tileAddr.Address + i)).ToString("X2")); - } - break; - - default: - return ""; + for(int i = 0; i < len; i++) { + if(sb.Length > 0) { + sb.Append(" "); + } + sb.Append(DebugApi.GetMemoryValue(tileAddr.Type, (uint)(tileAddr.Address + i)).ToString("X2")); } return sb.ToString(); } - public static void CopyTileMem(int address, MemoryType memoryType) + public static int GetBytesPerTile(TileFormat format) { + int bitsPerPixel = format.GetBitsPerPixel(); + PixelSize tileSize = format.GetTileSize(); + int bytesPerTile = tileSize.Width * tileSize.Height * bitsPerPixel / 8; + + return bytesPerTile; + } + + public static void CopyTileMem(int address, MemoryType memoryType, TileFormat format) + { + int bytesPerTile = GetBytesPerTile(format); + AddressInfo addr = new AddressInfo() { Address = address, Type = memoryType }; - string tileMem = MemCopyHelper.ToString(addr, 16); + string tileMem = MemCopyHelper.ToString(addr, bytesPerTile); if(tileMem.Length > 0) { ApplicationHelper.GetMainWindow()?.Clipboard?.SetTextAsync(tileMem); } } - public static void PasteTileMem(int address, MemoryType memoryType) + public static void PasteTileMem(int address, MemoryType memoryType, TileFormat format) { var clipboard = ApplicationHelper.GetMainWindow()?.Clipboard; if(clipboard != null) { string? text = Task.Run(() => clipboard?.GetTextAsync()).GetAwaiter().GetResult(); if(text != null) { text = text.Replace("\n", "").Replace("\r", "").Replace(" ", ""); - if(Regex.IsMatch(text, "^[A-F0-9]{32}$", RegexOptions.IgnoreCase)) { + int bytesPerTile = GetBytesPerTile(format); + int charsPerTile = bytesPerTile * 2; + string pattern = $"^[A-F0-9]{{{charsPerTile}}}$"; + + if(Regex.IsMatch(text, pattern, RegexOptions.IgnoreCase)) { byte[] pastedData = HexUtilities.HexToArray(text); - for(int i = 0; i < 16; i++) { + for(int i = 0; i < bytesPerTile; i++) { DebugApi.SetMemoryValue(memoryType, (uint)(address + i), (byte)pastedData[i]); } } diff --git a/UI/Debugger/ViewModels/TileViewerViewModel.cs b/UI/Debugger/ViewModels/TileViewerViewModel.cs index f97d3e61b..3be539421 100644 --- a/UI/Debugger/ViewModels/TileViewerViewModel.cs +++ b/UI/Debugger/ViewModels/TileViewerViewModel.cs @@ -186,7 +186,7 @@ public TileViewerViewModel(CpuType cpuType, PictureViewer picViewer, Window? wnd } } }, - new ContextMenuSeparator() { IsVisible = () => CpuType == CpuType.Nes }, + new ContextMenuSeparator(), new ContextMenuAction() { ActionType = ActionType.CopyToHdPackFormat, IsVisible = () => CpuType == CpuType.Nes, @@ -200,23 +200,23 @@ public TileViewerViewModel(CpuType cpuType, PictureViewer picViewer, Window? wnd }, new ContextMenuAction() { ActionType = ActionType.CopyTileMemory, - IsVisible = () => CpuType == CpuType.Nes, + Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.Copy), IsEnabled = () => GetSelectedTileAddress() >= 0, OnClick = () => { int address = GetSelectedTileAddress(); if(address >= 0) { - MemCopyHelper.CopyTileMem(address, Config.Source); + MemCopyHelper.CopyTileMem(address, Config.Source, Config.Format); } } }, new ContextMenuAction() { ActionType = ActionType.PasteTileMemory, - IsVisible = () => CpuType == CpuType.Nes, + Shortcut = () => ConfigManager.Config.Debug.Shortcuts.Get(DebuggerShortcut.Paste), IsEnabled = () => GetSelectedTileAddress() >= 0, OnClick = () => { int address = GetSelectedTileAddress(); if(address >= 0) { - MemCopyHelper.PasteTileMem(address, Config.Source); + MemCopyHelper.PasteTileMem(address, Config.Source, Config.Format); } } }