diff --git a/ExternalToolProjects/.build_from_cwd_debug.sh b/ExternalToolProjects/.build_net48_from_cwd_debug.sh
similarity index 65%
rename from ExternalToolProjects/.build_from_cwd_debug.sh
rename to ExternalToolProjects/.build_net48_from_cwd_debug.sh
index d9cec13428..2f0184cb55 100755
--- a/ExternalToolProjects/.build_from_cwd_debug.sh
+++ b/ExternalToolProjects/.build_net48_from_cwd_debug.sh
@@ -1,3 +1,3 @@
#!/bin/sh
name="$(basename "$PWD").dll"
-CscToolExe="$(which csc)" dotnet build -c Debug -m && cp -f "bin/Debug/$name" "../../output/ExternalTools/$name"
+CscToolExe="$(which csc)" dotnet build -c Debug -m && cp -f "bin/Debug/net48/$name" "../../output/ExternalTools/$name"
diff --git a/ExternalToolProjects/.build_from_cwd_release.sh b/ExternalToolProjects/.build_net48_from_cwd_release.sh
similarity index 63%
rename from ExternalToolProjects/.build_from_cwd_release.sh
rename to ExternalToolProjects/.build_net48_from_cwd_release.sh
index 3315f6f4e6..40d7ba70db 100755
--- a/ExternalToolProjects/.build_from_cwd_release.sh
+++ b/ExternalToolProjects/.build_net48_from_cwd_release.sh
@@ -1,3 +1,3 @@
#!/bin/sh
name="$(basename "$PWD").dll"
-CscToolExe="$(which csc)" dotnet build -c Release -m && cp -f "bin/Release/$name" "../../output/ExternalTools/$name"
+CscToolExe="$(which csc)" dotnet build -c Release -m && cp -f "bin/Release/net48/$name" "../../output/ExternalTools/$name"
diff --git a/ExternalToolProjects/Common.props b/ExternalToolProjects/Common.props
new file mode 100644
index 0000000000..76d80bbf9a
--- /dev/null
+++ b/ExternalToolProjects/Common.props
@@ -0,0 +1,29 @@
+
+
+ $(ProjectDir)../../Common.ruleset
+ prompt
+ false
+ 8.0
+ enable
+ $(ProjectDir)bin/$(Configuration)
+ AnyCPU
+ false
+ false
+
+
+ true
+ full
+ DEBUG;TRACE
+ false
+
+
+ false
+ pdbonly
+ TRACE
+ true
+
+
+
+
+
+
diff --git a/ExternalToolProjects/HelloWorld/CustomMainForm.cs b/ExternalToolProjects/HelloWorld/CustomMainForm.cs
index d112a3da4b..14a80644b6 100644
--- a/ExternalToolProjects/HelloWorld/CustomMainForm.cs
+++ b/ExternalToolProjects/HelloWorld/CustomMainForm.cs
@@ -5,65 +5,115 @@ using System.IO;
using BizHawk.Client.ApiHawk;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
-using BizHawk.Client.ApiHawk.Classes.Events;
+
+using DisplayType = BizHawk.Client.Common.DisplayType;
namespace BizHawk.Client.EmuHawk
{
- ///
- /// Here your first form
- /// /!\ it MUST be called CustomMainForm and implements IExternalToolForm
- /// Take also care of the namespace
- ///
+ /// ExternalToolForms must be a class named CustomMainForm in namespace BizHawk.Client.EmuHawk.
public partial class CustomMainForm : Form, IExternalToolForm
{
- #region Fields
-
- /*
- The following stuff will be automatically filled
- by BizHawk runtime
- */
+ /// RequiredServices are populated by EmuHawk at runtime.
[RequiredService]
- internal IMemoryDomains _memoryDomains { get; set; }
+ private IEmulator? _emu { get; set; }
+
[RequiredService]
- private IEmulator _emu { get; set; }
+ private IMemoryDomains? _memoryDomains { get; set; }
- /*private members for our needed*/
- private WatchList _watches;
+ private WatchList? _watches;
- #endregion
-
- #region cTor(s)
+ private WatchList Watches
+ {
+ get
+ {
+ WatchList CreateWatches()
+ {
+ var w = new WatchList(_memoryDomains, _emu?.SystemId ?? string.Empty);
+ w.AddRange(new[] {
+ Watch.GenerateWatch(_memoryDomains?.MainMemory, 0x40, WatchSize.Byte, DisplayType.Hex, true),
+ Watch.GenerateWatch(_memoryDomains?.MainMemory, 0x50, WatchSize.Word, DisplayType.Unsigned, true),
+ Watch.GenerateWatch(_memoryDomains?.MainMemory, 0x60, WatchSize.DWord, DisplayType.Hex, true)
+ });
+ return w;
+ }
+ _watches ??= CreateWatches();
+ return _watches;
+ }
+ }
public CustomMainForm()
{
InitializeComponent();
- label_GameHash.Click += Label_GameHash_Click;
+ label_GameHash.Click += label_GameHash_Click;
- ClientApi.BeforeQuickSave += ClientApi_BeforeQuickSave;
- ClientApi.BeforeQuickLoad += ClientApi_BeforeQuickLoad;
+ ClientApi.BeforeQuickSave += (sender, e) =>
+ {
+ if (e.Slot != 0) return; // only take effect on slot 0
+ var basePath = Path.Combine(PathManager.GetSaveStatePath(Global.Game), "Test");
+ if (!Directory.Exists(basePath)) Directory.CreateDirectory(basePath);
+ ClientApi.SaveState(Path.Combine(basePath, e.Name));
+ e.Handled = true;
+ };
+ ClientApi.BeforeQuickLoad += (sender, e) =>
+ {
+ if (e.Slot != 0) return; // only take effect on slot 0
+ var basePath = Path.Combine(PathManager.GetSaveStatePath(Global.Game), "Test");
+ ClientApi.LoadState(Path.Combine(basePath, e.Name));
+ e.Handled = true;
+ };
}
- #endregion
+ /// We want to be called before rendering.
+ public bool UpdateBefore => true;
- #region Methods
+ public bool AskSaveChanges() => true;
- private void button1_Click(object sender, EventArgs e)
+ /// This is called instead of the usual when EmuHawk is turboing.
+ public void FastUpdate() {}
+
+ public void NewUpdate(ToolFormUpdateType type) {}
+
+ /// This is called once when the form is opened, and every time a new movie session starts.
+ public void Restart()
{
- ClientApi.DoFrameAdvance();
+#if false
+ ClientApi.SetExtraPadding(50, 50);
+#endif
+
+ if (Global.Game.Name != "Null")
+ {
+ Watches.RefreshDomains(_memoryDomains);
+ label_Game.Text = $"You're playing {Global.Game.Name}";
+ label_GameHash.Text = $"Hash: {Global.Game.Hash}";
+ }
+ else
+ {
+ label_Game.Text = "You're playing... nothing";
+ label_GameHash.Text = string.Empty;
+ }
}
- private void button2_Click(object sender, EventArgs e)
+ /// Called just before every video frame.
+ public void UpdateValues()
{
- ClientApi.GetInput(1);
+ if (Global.Game.Name == "Null" || Watches.Count < 3) return;
+ Watches.UpdateValues();
+ label_Watch1.Text = $"First watch ({Watches[0].AddressString}) current value: {Watches[0].ValueString}";
+ label_Watch2.Text = $"Second watch ({Watches[1].AddressString}) current value: {Watches[1].ValueString}";
+ label_Watch3.Text = $"Third watch ({Watches[2].AddressString}) current value: {Watches[2].ValueString}";
}
+ private void button1_Click(object sender, EventArgs e) => ClientApi.DoFrameAdvance();
+
+ private void button2_Click(object sender, EventArgs e) => ClientApi.GetInput(1);
+
private void button3_Click(object sender, EventArgs e)
{
- for (int i = 0; i < 600; i++)
+ for (var i = 0; i < 600; i++)
{
if (i % 60 == 0)
{
- Joypad j1 = ClientApi.GetInput(1);
+ var j1 = ClientApi.GetInput(1);
j1.AddInput(JoypadButton.A);
ClientApi.SetInput(1, j1);
@@ -75,154 +125,29 @@ namespace BizHawk.Client.EmuHawk
}
ClientApi.DoFrameAdvance();
}
- Joypad j = ClientApi.GetInput(1);
+ var j = ClientApi.GetInput(1);
j.ClearInputs();
ClientApi.SetInput(1, j);
}
- private void Label_GameHash_Click(object sender, EventArgs e)
- {
- Clipboard.SetText(Global.Game.Hash);
- }
+ private void label_GameHash_Click(object sender, EventArgs e) => Clipboard.SetText(Global.Game.Hash);
private void loadstate_Click(object sender, EventArgs e)
{
- if (savestateName.Text.Trim() != string.Empty)
+ if (string.IsNullOrWhiteSpace(savestateName.Text)) return;
+ ClientApi.LoadState(savestateName.Text);
+#if false
+ static void Test(BinaryReader r)
{
- ClientApi.LoadState(savestateName.Text);
- //BinaryStateLoader.LoadAndDetect(savestateName.Text + ".State").GetLump(BinaryStateLump.Framebuffer, false, Test);
+ var b = new System.Drawing.Bitmap(r.BaseStream);
}
+ BinaryStateLoader.LoadAndDetect($"{savestateName.Text}.State").GetLump(BinaryStateLump.Framebuffer, false, Test);
+#endif
}
- /*private void Test(BinaryReader r)
- {
- System.Drawing.Bitmap b = new System.Drawing.Bitmap(r.BaseStream);
- }*/
-
private void saveState_Click(object sender, EventArgs e)
{
- if (savestateName.Text.Trim() != string.Empty)
- {
- ClientApi.SaveState(savestateName.Text);
- }
+ if (!string.IsNullOrWhiteSpace(savestateName.Text)) ClientApi.SaveState(savestateName.Text);
}
-
- //We will override F10 quicksave behavior
- private void ClientApi_BeforeQuickSave(object sender, BeforeQuickSaveEventArgs e)
- {
- if(e.Slot == 0)
- {
- string basePath = Path.Combine(PathManager.GetSaveStatePath(Global.Game), "Test");
- if (!Directory.Exists(basePath))
- {
- Directory.CreateDirectory(basePath);
- }
- ClientApi.SaveState(Path.Combine(basePath, e.Name));
- e.Handled = true;
- }
- }
-
- //We will override F10 quickload behavior
- private void ClientApi_BeforeQuickLoad(object sender, BeforeQuickLoadEventArgs e)
- {
- if (e.Slot == 0)
- {
- string basePath = Path.Combine(PathManager.GetSaveStatePath(Global.Game), "Test");
- ClientApi.LoadState(Path.Combine(basePath, e.Name));
- e.Handled = true;
- }
- }
-
- #endregion
-
- #region BizHawk Required methods
-
- ///
- /// Return true if you want the method
- /// to be called before rendering
- ///
- public bool UpdateBefore
- {
- get
- {
- return true;
- }
- }
-
- public bool AskSaveChanges()
- {
- return true;
- }
-
- ///
- /// This method is called instead of regular
- /// when emulator is runnig in turbo mode
- ///
- public void FastUpdate()
- { }
-
- public void NewUpdate(ToolFormUpdateType type) {}
-
- ///
- /// Restart is called the first time you call the form
- /// but also when you start playing a movie
- ///
- public void Restart()
- {
- //set a client padding
-// ClientApi.SetExtraPadding(50, 50);
-
- if (Global.Game.Name != "Null")
- {
- //first initialization of WatchList
- if (_watches == null)
- {
- _watches = new WatchList(_memoryDomains, _emu.SystemId ?? string.Empty);
-
- //Create some watch
- Watch myFirstWatch = Watch.GenerateWatch(_memoryDomains.MainMemory, 0x40, WatchSize.Byte, BizHawk.Client.Common.DisplayType.Hex, true);
- Watch mySecondWatch = Watch.GenerateWatch(_memoryDomains.MainMemory, 0x50, WatchSize.Word, BizHawk.Client.Common.DisplayType.Unsigned, true);
- Watch myThirdWatch = Watch.GenerateWatch(_memoryDomains.MainMemory, 0x60, WatchSize.DWord, BizHawk.Client.Common.DisplayType.Hex, true);
-
- //add them into the list
- _watches.Add(myFirstWatch);
- _watches.Add(mySecondWatch);
- _watches.Add(myThirdWatch);
-
- label_Game.Text = string.Format("You're playing {0}", Global.Game.Name);
- label_GameHash.Text = string.Format("Hash: {0}", Global.Game.Hash);
- }
- //refresh it
- else
- {
- _watches.RefreshDomains(_memoryDomains);
- label_Game.Text = string.Format("You're playing {0}", Global.Game.Name);
- label_GameHash.Text = string.Format("Hash: {0}", Global.Game.Hash);
- }
- }
- else
- {
- label_Game.Text = string.Format("You aren't playing to anything");
- label_GameHash.Text = string.Empty;
- }
- }
-
- ///
- /// This method is called when a frame is rendered
- /// You can comapre it the lua equivalent emu.frameadvance()
- ///
- public void UpdateValues()
- {
- if (Global.Game.Name != "Null")
- {
- //we update our watches
- _watches.UpdateValues();
- label_Watch1.Text = string.Format("First watch ({0}) current value: {1}", _watches[0].AddressString, _watches[0].ValueString);
- label_Watch2.Text = string.Format("Second watch ({0}) current value: {1}", _watches[1].AddressString, _watches[1].ValueString);
- label_Watch3.Text = string.Format("Third watch ({0}) current value: {1}", _watches[2].AddressString, _watches[2].ValueString);
- }
- }
-
- #endregion BizHawk Required methods
}
}
diff --git a/ExternalToolProjects/HelloWorld/CustomMainForm.resx b/ExternalToolProjects/HelloWorld/CustomMainForm.resx
deleted file mode 100644
index 29dcb1b3a3..0000000000
--- a/ExternalToolProjects/HelloWorld/CustomMainForm.resx
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- text/microsoft-resx
-
-
- 2.0
-
-
- System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
\ No newline at end of file
diff --git a/ExternalToolProjects/HelloWorld/HelloWorld.csproj b/ExternalToolProjects/HelloWorld/HelloWorld.csproj
index f79340d31e..7827027f2b 100644
--- a/ExternalToolProjects/HelloWorld/HelloWorld.csproj
+++ b/ExternalToolProjects/HelloWorld/HelloWorld.csproj
@@ -1,80 +1,11 @@
-
-
-
-
-
- Debug
- AnyCPU
- {288D598F-1019-4EA2-802D-14D3CC73EE90}
- Library
- Properties
- HelloWorld
- HelloWorld
- v4.6.1
- 512
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
- x64
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
- x64
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Form
-
-
- CustomMainForm.cs
-
-
-
-
-
- CustomMainForm.cs
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ExternalToolProjects/HelloWorld/build_debug.sh b/ExternalToolProjects/HelloWorld/build_debug.sh
index 43e0170d2e..c4d41e9cbf 120000
--- a/ExternalToolProjects/HelloWorld/build_debug.sh
+++ b/ExternalToolProjects/HelloWorld/build_debug.sh
@@ -1 +1 @@
-../.build_from_cwd_debug.sh
\ No newline at end of file
+../.build_net48_from_cwd_debug.sh
\ No newline at end of file
diff --git a/ExternalToolProjects/HelloWorld/build_release.sh b/ExternalToolProjects/HelloWorld/build_release.sh
index 89b0b361c0..73e473fcc2 120000
--- a/ExternalToolProjects/HelloWorld/build_release.sh
+++ b/ExternalToolProjects/HelloWorld/build_release.sh
@@ -1 +1 @@
-../.build_from_cwd_release.sh
\ No newline at end of file
+../.build_net48_from_cwd_release.sh
\ No newline at end of file
diff --git a/ExternalToolProjects/NET48ExternalToolForm.props b/ExternalToolProjects/NET48ExternalToolForm.props
new file mode 100644
index 0000000000..740015a650
--- /dev/null
+++ b/ExternalToolProjects/NET48ExternalToolForm.props
@@ -0,0 +1,27 @@
+
+
+ net48
+
+
+
+
+
+
+
+
+
+
+
+