mirror of
https://github.com/kwsch/NHSE.git
synced 2026-08-27 21:34:15 -05:00
Added support for USB-botbase (#299)
Only for player item injection at this time; no sync / toggle between modes
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibUsbDotNet" Version="2.2.29" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NHSE.Core\NHSE.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the virtual controller from the bot. Allows physical controllers to control manually.
|
||||
@@ -66,5 +66,13 @@ public static class SwitchCommand
|
||||
/// <param name="data">Data to write</param>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] Poke(uint offset, byte[] data) => Encode($"poke 0x{offset:X8} 0x{string.Concat(data.Select(z => $"{z:X2}"))}");
|
||||
|
||||
/// <summary>
|
||||
/// (Without return) Requests the Bot to send <see cref="count"/> bytes from <see cref="offset"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset">Address of the data</param>
|
||||
/// <param name="count">Amount of bytes</param>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] PeekRaw(uint offset, int count) => Encode($"peek 0x{offset:X8} {count}", false);
|
||||
}
|
||||
}
|
||||
164
NHSE.Injection/SysBot/USBBot.cs
Normal file
164
NHSE.Injection/SysBot/USBBot.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net46;netcoreapp3.1</TargetFrameworks>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
69
NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs
generated
69
NHSE.WinForms/Subforms/SysBot/SysBotUI.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
53
NHSE.WinForms/Subforms/SysBot/USBBotController.cs
Normal file
53
NHSE.WinForms/Subforms/SysBot/USBBotController.cs
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user