Debugger: Added "test runner" headless mode to run Lua scripts w/o UI
This commit is contained in:
parent
1e47897ca6
commit
fd4a8cbf43
12 changed files with 190 additions and 64 deletions
|
@ -360,9 +360,10 @@ void Console::ResetComponents(bool softReset)
|
|||
_controlManager->UpdateInputState();
|
||||
}
|
||||
|
||||
void Console::Stop()
|
||||
void Console::Stop(int stopCode)
|
||||
{
|
||||
_stop = true;
|
||||
_stopCode = stopCode;
|
||||
|
||||
shared_ptr<Debugger> debugger = _debugger;
|
||||
if(debugger) {
|
||||
|
@ -510,6 +511,7 @@ void Console::Run()
|
|||
}
|
||||
} catch(const std::runtime_error &ex) {
|
||||
crashed = true;
|
||||
_stopCode = -1;
|
||||
MessageManager::DisplayMessage("Error", "GameCrash", ex.what());
|
||||
}
|
||||
|
||||
|
@ -726,6 +728,11 @@ void Console::SetNextFrameOverclockStatus(bool disabled)
|
|||
Instance->_disableOcNextFrame = disabled;
|
||||
}
|
||||
|
||||
int32_t Console::GetStopCode()
|
||||
{
|
||||
return _stopCode;
|
||||
}
|
||||
|
||||
HdPackData* Console::GetHdData()
|
||||
{
|
||||
return Instance->_hdData.get();
|
||||
|
|
|
@ -58,6 +58,7 @@ class Console
|
|||
|
||||
bool _stop = false;
|
||||
bool _running = false;
|
||||
int32_t _stopCode = 0;
|
||||
|
||||
bool _disableOcNextFrame = false;
|
||||
|
||||
|
@ -77,7 +78,9 @@ class Console
|
|||
void SaveBatteries();
|
||||
|
||||
void Run();
|
||||
void Stop();
|
||||
void Stop(int stopCode = 0);
|
||||
|
||||
int32_t GetStopCode();
|
||||
|
||||
void RunSingleFrame();
|
||||
bool UpdateHdPackMode();
|
||||
|
|
|
@ -81,6 +81,7 @@ int LuaApi::GetLibrary(lua_State *lua)
|
|||
{ "log", LuaApi::Log },
|
||||
{ "displayMessage", LuaApi::DisplayMessage },
|
||||
{ "reset", LuaApi::Reset },
|
||||
{ "stop", LuaApi::Stop },
|
||||
{ "breakExecution", LuaApi::Break },
|
||||
{ "resume", LuaApi::Resume },
|
||||
{ "execute", LuaApi::Execute },
|
||||
|
@ -464,6 +465,15 @@ int LuaApi::Reset(lua_State *lua)
|
|||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Stop(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
int32_t stopCode = l.ReadInteger(0);
|
||||
checkminparams(0);
|
||||
Console::GetInstance()->Stop(stopCode);
|
||||
return l.ReturnCount();
|
||||
}
|
||||
|
||||
int LuaApi::Break(lua_State *lua)
|
||||
{
|
||||
LuaCallHelper l(lua);
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
static int DisplayMessage(lua_State *lua);
|
||||
|
||||
static int Reset(lua_State *lua);
|
||||
static int Stop(lua_State *lua);
|
||||
static int Break(lua_State *lua);
|
||||
static int Resume(lua_State *lua);
|
||||
static int Execute(lua_State *lua);
|
||||
|
|
70
GUI.NET/CommandLineHelper.cs
Normal file
70
GUI.NET/CommandLineHelper.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.GUI
|
||||
{
|
||||
class CommandLineHelper
|
||||
{
|
||||
public static List<string> PreprocessCommandLineArguments(string[] args, bool toLower)
|
||||
{
|
||||
var switches = new List<string>();
|
||||
for(int i = 0; i < args.Length; i++) {
|
||||
if(args[i] != null) {
|
||||
string arg = args[i].Trim();
|
||||
if(arg.StartsWith("--")) {
|
||||
arg = "/" + arg.Substring(2);
|
||||
} else if(arg.StartsWith("-")) {
|
||||
arg = "/" + arg.Substring(1);
|
||||
}
|
||||
|
||||
if(toLower) {
|
||||
arg = arg.ToLowerInvariant();
|
||||
}
|
||||
switches.Add(arg);
|
||||
}
|
||||
}
|
||||
return switches;
|
||||
}
|
||||
|
||||
public static void GetRomPathFromCommandLine(List<string> switches, out string romPath, out List<string> luaScriptsToLoad)
|
||||
{
|
||||
Func<string, bool, string> getValidPath = (string path, bool forLua) => {
|
||||
path = path.Trim();
|
||||
if(path.ToLower().EndsWith(".lua") == forLua) {
|
||||
try {
|
||||
if(!File.Exists(path)) {
|
||||
//Try loading file as a relative path to the folder Mesen was started from
|
||||
path = Path.Combine(Program.OriginalFolder, path);
|
||||
}
|
||||
if(File.Exists(path)) {
|
||||
return path;
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
//Check if any Lua scripts were specified
|
||||
luaScriptsToLoad = new List<string>();
|
||||
foreach(string arg in switches) {
|
||||
string path = getValidPath(arg, true);
|
||||
if(path != null) {
|
||||
luaScriptsToLoad.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
romPath = null;
|
||||
foreach(string arg in switches) {
|
||||
string path = getValidPath(arg, false);
|
||||
if(path != null) {
|
||||
romPath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,7 +101,11 @@ namespace Mesen.GUI.Debugger
|
|||
if(_openedWindows.Count == 0) {
|
||||
//All windows have been closed, disable debugger
|
||||
DebugWorkspaceManager.Clear();
|
||||
|
||||
Task.Run(() => {
|
||||
//Run this in another thread to avoid deadlocks when this is called within a notification handler
|
||||
InteropEmu.DebugRelease();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,27 +83,6 @@ namespace Mesen.GUI.Forms
|
|||
this.FormClosed += (s, e) => Application.RemoveMessageFilter(this);
|
||||
}
|
||||
|
||||
public List<string> PreprocessCommandLineArguments(string[] args, bool toLower)
|
||||
{
|
||||
var switches = new List<string>();
|
||||
for(int i = 0; i < args.Length; i++) {
|
||||
if(args[i] != null) {
|
||||
string arg = args[i].Trim();
|
||||
if(arg.StartsWith("--")) {
|
||||
arg = "/" + arg.Substring(2);
|
||||
} else if(arg.StartsWith("-")) {
|
||||
arg = "/" + arg.Substring(1);
|
||||
}
|
||||
|
||||
if(toLower) {
|
||||
arg = arg.ToLowerInvariant();
|
||||
}
|
||||
switches.Add(arg);
|
||||
}
|
||||
}
|
||||
return switches;
|
||||
}
|
||||
|
||||
public void ProcessCommandLineArguments(List<string> switches, bool forStartup)
|
||||
{
|
||||
if(forStartup) {
|
||||
|
@ -121,42 +100,13 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
public void LoadGameFromCommandLine(List<string> switches)
|
||||
{
|
||||
Func<string, bool, string> getValidPath = (string path, bool forLua) => {
|
||||
path = path.Trim();
|
||||
if(path.ToLower().EndsWith(".lua") == forLua) {
|
||||
try {
|
||||
if(!File.Exists(path)) {
|
||||
//Try loading file as a relative path to the folder Mesen was started from
|
||||
path = Path.Combine(Program.OriginalFolder, path);
|
||||
}
|
||||
if(File.Exists(path)) {
|
||||
return path;
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
return null;
|
||||
};
|
||||
string romPath;
|
||||
CommandLineHelper.GetRomPathFromCommandLine(switches, out romPath, out _luaScriptsToLoad);
|
||||
|
||||
//Check if any Lua scripts were specified
|
||||
_luaScriptsToLoad = new List<string>();
|
||||
foreach(string arg in switches) {
|
||||
string path = getValidPath(arg, true);
|
||||
if(path != null) {
|
||||
_luaScriptsToLoad.Add(path);
|
||||
}
|
||||
}
|
||||
if(romPath != null) {
|
||||
this.LoadFile(romPath);
|
||||
} else {
|
||||
|
||||
bool fileLoaded = false;
|
||||
foreach(string arg in switches) {
|
||||
string path = getValidPath(arg, false);
|
||||
if(path != null) {
|
||||
this.LoadFile(path);
|
||||
fileLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!fileLoaded) {
|
||||
if(_emuThread == null) {
|
||||
//When no ROM is loaded, only process Lua scripts if a ROM was specified as a command line param
|
||||
_luaScriptsToLoad.Clear();
|
||||
|
@ -196,7 +146,7 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
InteropEmu.ScreenSize originalSize = InteropEmu.GetScreenSize(false);
|
||||
VideoInfo.ApplyConfig();
|
||||
this.ProcessCommandLineArguments(this.PreprocessCommandLineArguments(_commandLineArgs, true), true);
|
||||
this.ProcessCommandLineArguments(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, true), true);
|
||||
VideoInfo.ApplyConfig();
|
||||
InteropEmu.ScreenSize newSize = InteropEmu.GetScreenSize(false);
|
||||
if(originalSize.Width != newSize.Width || originalSize.Height != newSize.Height) {
|
||||
|
@ -267,7 +217,7 @@ namespace Mesen.GUI.Forms
|
|||
this.Size = ConfigManager.Config.WindowSize.Value;
|
||||
}
|
||||
|
||||
this.LoadGameFromCommandLine(this.PreprocessCommandLineArguments(_commandLineArgs, false));
|
||||
this.LoadGameFromCommandLine(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, false));
|
||||
|
||||
this.menuStrip.VisibleChanged += new System.EventHandler(this.menuStrip_VisibleChanged);
|
||||
this.UpdateRendererLocation();
|
||||
|
@ -281,7 +231,7 @@ namespace Mesen.GUI.Forms
|
|||
//This is needed when DPI display settings is not set to 100%
|
||||
_enableResize = true;
|
||||
|
||||
ProcessFullscreenSwitch(this.PreprocessCommandLineArguments(_commandLineArgs, true));
|
||||
ProcessFullscreenSwitch(CommandLineHelper.PreprocessCommandLineArguments(_commandLineArgs, true));
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
|
|
|
@ -238,6 +238,7 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CommandLineHelper.cs" />
|
||||
<Compile Include="Config\DebuggerShortcutsConfig.cs" />
|
||||
<Compile Include="Config\MovieRecordInfo.cs" />
|
||||
<Compile Include="Config\ConfigAttributes.cs" />
|
||||
|
@ -1166,6 +1167,7 @@
|
|||
<Compile Include="ResourceManager.cs" />
|
||||
<Compile Include="RuntimeChecker.cs" />
|
||||
<Compile Include="SingleInstance.cs" />
|
||||
<Compile Include="TestRunner.cs" />
|
||||
<None Include="Resources\SwitchView.png" />
|
||||
<None Include="Resources\SelectAll.png" />
|
||||
<None Include="Resources\Paste.png" />
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void SetFullscreenMode([MarshalAs(UnmanagedType.I1)]bool fullscreen, IntPtr windowHandle, UInt32 monitorWidth, UInt32 monitorHeight);
|
||||
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsRunning();
|
||||
[DllImport(DLLPath)] public static extern Int32 GetStopCode();
|
||||
|
||||
[DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string patchFile);
|
||||
[DllImport(DLLPath)] public static extern void AddKnownGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string folder);
|
||||
|
|
|
@ -129,6 +129,11 @@ namespace Mesen.GUI
|
|||
return;
|
||||
}
|
||||
|
||||
if(CommandLineHelper.PreprocessCommandLineArguments(args, true).Contains("/testrunner")) {
|
||||
Environment.ExitCode = TestRunner.Run(args);
|
||||
return;
|
||||
}
|
||||
|
||||
using(SingleInstance singleInstance = new SingleInstance()) {
|
||||
if(singleInstance.FirstInstance || !ConfigManager.Config.PreferenceInfo.SingleInstance) {
|
||||
frmMain frmMain = new frmMain(args);
|
||||
|
@ -137,8 +142,8 @@ namespace Mesen.GUI
|
|||
singleInstance.ArgumentsReceived += (object sender, ArgumentsReceivedEventArgs e) => {
|
||||
if(frmMain.IsHandleCreated) {
|
||||
frmMain.BeginInvoke((MethodInvoker)(() => {
|
||||
frmMain.ProcessCommandLineArguments(frmMain.PreprocessCommandLineArguments(e.Args, true), false);
|
||||
frmMain.LoadGameFromCommandLine(frmMain.PreprocessCommandLineArguments(e.Args, false));
|
||||
frmMain.ProcessCommandLineArguments(CommandLineHelper.PreprocessCommandLineArguments(e.Args, true), false);
|
||||
frmMain.LoadGameFromCommandLine(CommandLineHelper.PreprocessCommandLineArguments(e.Args, false));
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
|
72
GUI.NET/TestRunner.cs
Normal file
72
GUI.NET/TestRunner.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using Mesen.GUI.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Mesen.GUI
|
||||
{
|
||||
internal class TestRunner
|
||||
{
|
||||
internal static int Run(string[] args)
|
||||
{
|
||||
ConfigManager.DoNotSaveSettings = true;
|
||||
string romPath;
|
||||
List<string> luaScriptsToLoad;
|
||||
CommandLineHelper.GetRomPathFromCommandLine(CommandLineHelper.PreprocessCommandLineArguments(args, false), out romPath, out luaScriptsToLoad);
|
||||
if(romPath == null) {
|
||||
//No rom specified
|
||||
return -1;
|
||||
}
|
||||
|
||||
List<string> lcArgs = CommandLineHelper.PreprocessCommandLineArguments(args, true);
|
||||
|
||||
int timeout = 100; //100 seconds
|
||||
string timeoutArg = lcArgs.Find(arg => arg.StartsWith("/timeout="));
|
||||
if(timeoutArg != null) {
|
||||
int timeoutValue;
|
||||
if(Int32.TryParse(timeoutArg.Substring(timeoutArg.IndexOf("=") + 1), out timeoutValue)) {
|
||||
timeout = timeoutValue;
|
||||
}
|
||||
}
|
||||
|
||||
ConfigManager.ProcessSwitches(lcArgs);
|
||||
ConfigManager.Config.ApplyConfig();
|
||||
InteropEmu.SetFlag(EmulationFlags.ConsoleMode, true);
|
||||
|
||||
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, IntPtr.Zero, IntPtr.Zero, true, true, true);
|
||||
|
||||
InteropEmu.LoadROM(romPath, string.Empty);
|
||||
|
||||
foreach(string luaScript in luaScriptsToLoad) {
|
||||
try {
|
||||
string script = File.ReadAllText(luaScript);
|
||||
InteropEmu.DebugLoadScript(luaScript, script);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
||||
Task.Run(() => {
|
||||
InteropEmu.Run();
|
||||
});
|
||||
|
||||
InteropEmu.SetFlag(EmulationFlags.ForceMaxSpeed, true);
|
||||
|
||||
sw.Start();
|
||||
int result = -1;
|
||||
while(sw.ElapsedMilliseconds < timeout * 1000) {
|
||||
System.Threading.Thread.Sleep(100);
|
||||
|
||||
if(!InteropEmu.IsRunning()) {
|
||||
result = InteropEmu.GetStopCode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InteropEmu.Stop();
|
||||
InteropEmu.Release();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -132,6 +132,7 @@ namespace InteropEmu {
|
|||
|
||||
|
||||
DllExport bool __stdcall IsRunning() { return Console::IsRunning(); }
|
||||
DllExport int32_t __stdcall GetStopCode() { return Console::GetInstance()->GetStopCode(); }
|
||||
|
||||
DllExport void __stdcall LoadROM(char* filename, char* patchFile) { Console::LoadROM((string)filename, (string)patchFile); }
|
||||
DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
|
||||
|
|
Loading…
Add table
Reference in a new issue