diff --git a/NHSE.Injection/NHSE.Injection.csproj b/NHSE.Injection/NHSE.Injection.csproj index 477e3a3..45ec128 100644 --- a/NHSE.Injection/NHSE.Injection.csproj +++ b/NHSE.Injection/NHSE.Injection.csproj @@ -6,6 +6,10 @@ enable + + + + diff --git a/NHSE.Injection/SysBot/SwitchCommand.cs b/NHSE.Injection/SysBot/SwitchCommand.cs index ea1acdf..ddd4f3b 100644 --- a/NHSE.Injection/SysBot/SwitchCommand.cs +++ b/NHSE.Injection/SysBot/SwitchCommand.cs @@ -9,7 +9,7 @@ namespace NHSE.Injection public static class SwitchCommand { private static readonly Encoding Encoder = Encoding.UTF8; - private static byte[] Encode(string command) => Encoder.GetBytes(command + "\r\n"); + private static byte[] Encode(string command, bool addrn = true) => Encoder.GetBytes(addrn ? command + "\r\n" : command); /// /// Removes the virtual controller from the bot. Allows physical controllers to control manually. @@ -66,5 +66,13 @@ public static class SwitchCommand /// Data to write /// Encoded command bytes public static byte[] Poke(uint offset, byte[] data) => Encode($"poke 0x{offset:X8} 0x{string.Concat(data.Select(z => $"{z:X2}"))}"); + + /// + /// (Without return) Requests the Bot to send bytes from . + /// + /// Address of the data + /// Amount of bytes + /// Encoded command bytes + public static byte[] PeekRaw(uint offset, int count) => Encode($"peek 0x{offset:X8} {count}", false); } } \ No newline at end of file diff --git a/NHSE.Injection/SysBot/USBBot.cs b/NHSE.Injection/SysBot/USBBot.cs new file mode 100644 index 0000000..e59b918 --- /dev/null +++ b/NHSE.Injection/SysBot/USBBot.cs @@ -0,0 +1,164 @@ +using System; +using System.Threading; +using LibUsbDotNet; +using LibUsbDotNet.Main; + +namespace NHSE.Injection +{ + public class USBBot : IRAMReadWriter + { + private UsbDevice? SwDevice; + private UsbEndpointReader? reader; + private UsbEndpointWriter? writer; + + public bool Connected { get; private set; } + + private readonly object _sync = new object(); + + public bool Connect() + { + lock (_sync) + { + // Find and open the usb device. + //SwDevice = UsbDevice.OpenUsbDevice(SwFinder); + foreach (UsbRegistry ur in UsbDevice.AllDevices) + { + if (ur.Vid == 1406 && ur.Pid == 12288) + SwDevice = ur.Device; + } + //SwDevice = UsbDevice.OpenUsbDevice(MyUsbFinder); + + // If the device is open and ready + if (SwDevice == null) + { + throw new Exception("Device Not Found."); + } + + if (SwDevice.IsOpen) + SwDevice.Close(); + SwDevice.Open(); + + if (SwDevice is IUsbDevice wholeUsbDevice) + { + // This is a "whole" USB device. Before it can be used, + // the desired configuration and interface must be selected. + + // Select config #1 + wholeUsbDevice.SetConfiguration(1); + + // Claim interface #0. + bool resagain = wholeUsbDevice.ClaimInterface(0); + if (!resagain) + { + wholeUsbDevice.ReleaseInterface(0); + wholeUsbDevice.ClaimInterface(0); + } + } + else + { + Disconnect(); + throw new Exception("Device is using WinUSB driver. Use libusbK and create a filter"); + } + + // open read write endpoints 1. + reader = SwDevice.OpenEndpointReader(ReadEndpointID.Ep01); + writer = SwDevice.OpenEndpointWriter(WriteEndpointID.Ep01); + + Connected = true; + return true; + } + } + + public void Disconnect() + { + lock (_sync) + { + if (SwDevice != null) + { + if (SwDevice.IsOpen) + { + IUsbDevice? wholeUsbDevice = SwDevice as IUsbDevice; + wholeUsbDevice?.ReleaseInterface(0); + SwDevice.Close(); + } + } + + reader?.Dispose(); + writer?.Dispose(); + Connected = false; + } + } + + private int ReadInternal(byte[] buffer) + { + byte[] sizeOfReturn = new byte[4]; + + //read size, no error checking as of yet, should be the required 368 bytes + if (reader == null) + throw new Exception("USB writer is null, you may have disconnected the device during previous function"); + + reader.Read(sizeOfReturn, 5000, out _); + + //read stack + reader.Read(buffer, 5000, out var lenVal); + return lenVal; + } + + private int SendInternal(byte[] buffer) + { + if (writer == null) + throw new Exception("USB writer is null, you may have disconnected the device during previous function"); + + uint pack = (uint)buffer.Length + 2; + var ec = writer.Write(BitConverter.GetBytes(pack), 2000, out _); + if (ec != ErrorCode.None) + { + Disconnect(); + throw new Exception(UsbDevice.LastErrorString); + } + ec = writer.Write(buffer, 2000, out var l); + if (ec != ErrorCode.None) + { + Disconnect(); + throw new Exception(UsbDevice.LastErrorString); + } + return l; + } + + public int Read(byte[] buffer) + { + lock (_sync) + { + return ReadInternal(buffer); + } + } + + public byte[] ReadBytes(uint offset, int length) + { + lock (_sync) + { + var cmd = SwitchCommand.PeekRaw(offset, length); + SendInternal(cmd); + + // give it time to push data back + Thread.Sleep((length / 256) + 100); + + var buffer = new byte[length]; + var _ = ReadInternal(buffer); + //return Decoder.ConvertHexByteStringToBytes(buffer); + return buffer; + } + } + + public void WriteBytes(byte[] data, uint offset) + { + lock (_sync) + { + SendInternal(SwitchCommand.Poke(offset, data)); + + // give it time to push data back + Thread.Sleep((data.Length / 256) + 100); + } + } + } +} diff --git a/NHSE.Sprites/Item/ItemSprite.cs b/NHSE.Sprites/Item/ItemSprite.cs index cd8b0fc..c351d37 100644 --- a/NHSE.Sprites/Item/ItemSprite.cs +++ b/NHSE.Sprites/Item/ItemSprite.cs @@ -20,6 +20,10 @@ public static void Initialize(string path, string[] itemNames) ItemNames = itemNames; + //create items folder if not exist + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + var files = Directory.EnumerateFiles(path, "*.png", SearchOption.AllDirectories); foreach (var f in files) { diff --git a/NHSE.Sprites/NHSE.Sprites.csproj b/NHSE.Sprites/NHSE.Sprites.csproj index 48068af..b9d5bc0 100644 --- a/NHSE.Sprites/NHSE.Sprites.csproj +++ b/NHSE.Sprites/NHSE.Sprites.csproj @@ -1,4 +1,4 @@ - + net46;netcoreapp3.1 diff --git a/NHSE.WinForms/Subforms/PlayerItemEditor.cs b/NHSE.WinForms/Subforms/PlayerItemEditor.cs index 45e4f42..2d58b86 100644 --- a/NHSE.WinForms/Subforms/PlayerItemEditor.cs +++ b/NHSE.WinForms/Subforms/PlayerItemEditor.cs @@ -111,9 +111,12 @@ static void AfterWrite(InjectionResult r) var sb = new SysBotController(InjectionType.Pouch); var pockInject = new PocketInjector(ItemArray.Items, sb.Bot); var ai = new AutoInjector(pockInject, AfterRead, AfterWrite); + var ub = new USBBotController(); + var pockInjectUSB = new PocketInjector(ItemArray.Items, ub.Bot); + var aiUSB = new AutoInjector(pockInjectUSB, AfterRead, AfterWrite); ItemGrid.ItemChanged = () => ai.Write(); - var sysbot = new SysBotUI(ai, sb); + var sysbot = new SysBotUI(ai, sb, aiUSB, ub); sysbot.Show(); } } diff --git a/NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs b/NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs index f0cd19d..da3287f 100644 --- a/NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs +++ b/NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs @@ -43,7 +43,13 @@ private void InitializeComponent() this.B_ReadCurrent = new System.Windows.Forms.Button(); this.B_WriteCurrent = new System.Windows.Forms.Button(); this.TIM_Interval = new System.Windows.Forms.Timer(this.components); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.ReadUSB = new System.Windows.Forms.Button(); + this.WriteUSB = new System.Windows.Forms.Button(); + this.L_OffsetUSB = new System.Windows.Forms.Label(); + this.RamOffsetUSB = new System.Windows.Forms.TextBox(); this.GB_Inject.SuspendLayout(); + this.groupBox1.SuspendLayout(); this.SuspendLayout(); // // B_Connect @@ -188,11 +194,65 @@ private void InitializeComponent() // this.TIM_Interval.Interval = 5000; // + // groupBox1 + // + this.groupBox1.Controls.Add(this.RamOffsetUSB); + this.groupBox1.Controls.Add(this.L_OffsetUSB); + this.groupBox1.Controls.Add(this.WriteUSB); + this.groupBox1.Controls.Add(this.ReadUSB); + this.groupBox1.Location = new System.Drawing.Point(16, 191); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(149, 75); + this.groupBox1.TabIndex = 14; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "USB"; + // + // ReadUSB + // + this.ReadUSB.Location = new System.Drawing.Point(6, 46); + this.ReadUSB.Name = "ReadUSB"; + this.ReadUSB.Size = new System.Drawing.Size(68, 23); + this.ReadUSB.TabIndex = 0; + this.ReadUSB.Text = "Read USB"; + this.ReadUSB.UseVisualStyleBackColor = true; + this.ReadUSB.Click += new System.EventHandler(this.ReadUSB_Click); + // + // WriteUSB + // + this.WriteUSB.Location = new System.Drawing.Point(74, 46); + this.WriteUSB.Name = "WriteUSB"; + this.WriteUSB.Size = new System.Drawing.Size(69, 23); + this.WriteUSB.TabIndex = 1; + this.WriteUSB.Text = "Write USB"; + this.WriteUSB.UseVisualStyleBackColor = true; + this.WriteUSB.Click += new System.EventHandler(this.WriteUSB_Click); + // + // L_OffsetUSB + // + this.L_OffsetUSB.Location = new System.Drawing.Point(3, 24); + this.L_OffsetUSB.Name = "L_OffsetUSB"; + this.L_OffsetUSB.Size = new System.Drawing.Size(63, 20); + this.L_OffsetUSB.TabIndex = 20; + this.L_OffsetUSB.Text = "Offset:"; + this.L_OffsetUSB.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // RamOffsetUSB + // + this.RamOffsetUSB.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.RamOffsetUSB.Location = new System.Drawing.Point(72, 24); + this.RamOffsetUSB.MaxLength = 8; + this.RamOffsetUSB.Name = "RamOffsetUSB"; + this.RamOffsetUSB.Size = new System.Drawing.Size(63, 20); + this.RamOffsetUSB.TabIndex = 24; + this.RamOffsetUSB.Text = "AC4723D0"; + this.RamOffsetUSB.TextChanged += new System.EventHandler(this.RamOffsetUSB_TextChanged); + // // SysBotUI // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(184, 197); + this.ClientSize = new System.Drawing.Size(184, 278); + this.Controls.Add(this.groupBox1); this.Controls.Add(this.GB_Inject); this.Controls.Add(this.B_Connect); this.Controls.Add(this.L_Port); @@ -209,6 +269,8 @@ private void InitializeComponent() this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysBotUI_FormClosing); this.GB_Inject.ResumeLayout(false); this.GB_Inject.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -230,5 +292,10 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox CHK_AutoRead; private System.Windows.Forms.Timer TIM_Interval; private System.Windows.Forms.CheckBox CHK_Validate; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button ReadUSB; + private System.Windows.Forms.Button WriteUSB; + private System.Windows.Forms.TextBox RamOffsetUSB; + private System.Windows.Forms.Label L_OffsetUSB; } } \ No newline at end of file diff --git a/NHSE.WinForms/Subforms/SysBot/SysBotUI.cs b/NHSE.WinForms/Subforms/SysBot/SysBotUI.cs index 80ed7d3..c4a709c 100644 --- a/NHSE.WinForms/Subforms/SysBot/SysBotUI.cs +++ b/NHSE.WinForms/Subforms/SysBot/SysBotUI.cs @@ -9,13 +9,17 @@ public partial class SysBotUI : Form { private readonly AutoInjector Injector; private readonly SysBotController Bot; + private readonly AutoInjector InjectorUSB; + private readonly USBBotController BotUSB; - public SysBotUI(AutoInjector injector, SysBotController c) + public SysBotUI(AutoInjector injector, SysBotController c, AutoInjector injectorUSB, USBBotController b) { InitializeComponent(); this.TranslateInterface(GameInfo.CurrentLanguage); Bot = c; Injector = injector; + BotUSB = b; + InjectorUSB = injectorUSB; var offset = Bot.GetDefaultOffset(); Injector.SetWriteOffset(offset); @@ -122,5 +126,79 @@ private void RamOffset_TextChanged(object sender, EventArgs e) Injector.SetWriteOffset(offset); } + + private void ReadUSB_Click(object sender, EventArgs e) + { + if (!BotUSB.Connect()) + return; + + var offset = StringUtil.GetHexValue(RamOffsetUSB.Text); + if (offset == 0) + { + WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue); + return; + } + + InjectorUSB.SetWriteOffset(offset); + + try + { + var result = InjectorUSB.Read(true); + if (result == InjectionResult.Success) + return; + WinFormsUtil.Alert(result.ToString()); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + WinFormsUtil.Error(ex.Message); + } + + BotUSB.Disconnect(); + } + + private void WriteUSB_Click(object sender, EventArgs e) + { + if (!BotUSB.Connect()) + return; + + var offset = StringUtil.GetHexValue(RamOffsetUSB.Text); + if (offset == 0) + { + WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue); + return; + } + + InjectorUSB.SetWriteOffset(offset); + + try + { + var result = InjectorUSB.Write(true); + if (result == InjectionResult.Success) + return; + WinFormsUtil.Alert(result.ToString()); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + WinFormsUtil.Error(ex.Message); + } + + BotUSB.Disconnect(); + } + + private void RamOffsetUSB_TextChanged(object sender, EventArgs e) + { + var offset = StringUtil.GetHexValue(RamOffsetUSB.Text); + if (offset == 0) + { + WinFormsUtil.Error(MessageStrings.MsgInvalidHexValue); + return; + } + + Injector.SetWriteOffset(offset); + } } } diff --git a/NHSE.WinForms/Subforms/SysBot/USBBotController.cs b/NHSE.WinForms/Subforms/SysBot/USBBotController.cs new file mode 100644 index 0000000..0c8b2ee --- /dev/null +++ b/NHSE.WinForms/Subforms/SysBot/USBBotController.cs @@ -0,0 +1,53 @@ +using System; +using NHSE.Injection; + +namespace NHSE.WinForms +{ + public class USBBotController + { + public readonly USBBot Bot = new USBBot(); + + public bool Connect() + { + try + { + return Bot.Connect(); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + WinFormsUtil.Error(ex.Message); + return false; + } + } + + public void Disconnect() + { + Bot.Disconnect(); + } + + //todo: this + //public uint GetDefaultOffset() + //{ + // return Settings.Default.SysBotPouchOffset; + //} + + //public void PopPrompt() + //{ + //} + + public void WriteBytes(byte[] data, uint offset) + { + Bot.WriteBytes(data, offset); + //SetOffset(offset); + } + + public byte[] ReadBytes(uint offset, int length) + { + var result = Bot.ReadBytes(offset, length); + //SetOffset(offset); + return result; + } + } +}