mirror of
https://github.com/kwsch/NHSE.git
synced 2026-08-27 21:34:15 -05:00
Add sysbot logic for remote control
This commit is contained in:
42
NHSE.Injection/Decoder.cs
Normal file
42
NHSE.Injection/Decoder.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
namespace NHSE.Injection
|
||||
{
|
||||
public static class Decoder
|
||||
{
|
||||
private static bool IsNum(char c) => (uint)(c - '0') <= 9;
|
||||
private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5;
|
||||
|
||||
public static byte[] ConvertHexByteStringToBytes(byte[] bytes)
|
||||
{
|
||||
var dest = new byte[bytes.Length / 2];
|
||||
for (int i = 0; i < dest.Length; i++)
|
||||
{
|
||||
int ofs = i * 2;
|
||||
var _0 = (char)bytes[ofs + 0];
|
||||
var _1 = (char)bytes[ofs + 1];
|
||||
dest[i] = DecodeTuple(_0, _1);
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
private static byte DecodeTuple(char _0, char _1)
|
||||
{
|
||||
byte result;
|
||||
if (IsNum(_0))
|
||||
result = (byte)((_0 - '0') << 4);
|
||||
else if (IsHexUpper(_0))
|
||||
result = (byte)((_0 - 'A' + 10) << 4);
|
||||
else
|
||||
throw new ArgumentOutOfRangeException(nameof(_0));
|
||||
|
||||
if (IsNum(_1))
|
||||
result |= (byte)(_1 - '0');
|
||||
else if (IsHexUpper(_1))
|
||||
result |= (byte)(_1 - 'A' + 10);
|
||||
else
|
||||
throw new ArgumentOutOfRangeException(nameof(_1));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
NHSE.Injection/NHSE.Injection.csproj
Normal file
9
NHSE.Injection/NHSE.Injection.csproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
|
||||
<LangVersion>8</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
27
NHSE.Injection/SwitchButton.cs
Normal file
27
NHSE.Injection/SwitchButton.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace NHSE.Injection
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller Buttons
|
||||
/// </summary>
|
||||
public enum SwitchButton
|
||||
{
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
RSTICK,
|
||||
LSTICK,
|
||||
L,
|
||||
R,
|
||||
ZL,
|
||||
ZR,
|
||||
PLUS,
|
||||
MINUS,
|
||||
DUP,
|
||||
DDOWN,
|
||||
DLEFT,
|
||||
DRIGHT,
|
||||
HOME,
|
||||
CAPTURE,
|
||||
}
|
||||
}
|
||||
70
NHSE.Injection/SwitchCommand.cs
Normal file
70
NHSE.Injection/SwitchCommand.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NHSE.Injection
|
||||
{
|
||||
/// <summary>
|
||||
/// Encodes commands for a <see cref="SysBot"/> to be sent as a <see cref="byte"/> array.
|
||||
/// </summary>
|
||||
public static class SwitchCommand
|
||||
{
|
||||
private static readonly Encoding Encoder = Encoding.UTF8;
|
||||
private static byte[] Encode(string command) => Encoder.GetBytes(command + "\r\n");
|
||||
|
||||
/// <summary>
|
||||
/// Removes the virtual controller from the bot. Allows physical controllers to control manually.
|
||||
/// </summary>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] DetachController() => Encode("detachController");
|
||||
|
||||
/// <summary>
|
||||
/// Presses and releases a <see cref="SwitchButton"/> for 50ms.
|
||||
/// </summary>
|
||||
/// <param name="button">Button to click.</param>
|
||||
/// <remarks>Press & Release timing is performed by the console automatically.</remarks>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] Click(SwitchButton button) => Encode($"click {button}");
|
||||
|
||||
/// <summary>
|
||||
/// Presses and does NOT release a <see cref="SwitchButton"/>.
|
||||
/// </summary>
|
||||
/// <param name="button">Button to hold.</param>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] Hold(SwitchButton button) => Encode($"press {button}");
|
||||
|
||||
/// <summary>
|
||||
/// Releases the held <see cref="SwitchButton"/>.
|
||||
/// </summary>
|
||||
/// <param name="button">Button to release.</param>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] Release(SwitchButton button) => Encode($"release {button}");
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified <see cref="stick"/> to the desired <see cref="x"/> and <see cref="y"/> positions.
|
||||
/// </summary>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] SetStick(SwitchStick stick, int x, int y) => Encode($"setStick {stick} {x} {y}");
|
||||
|
||||
/// <summary>
|
||||
/// Resets the specified <see cref="stick"/> to (0,0)
|
||||
/// </summary>
|
||||
/// <returns>Encoded command bytes</returns>
|
||||
public static byte[] ResetStick(SwitchStick stick) => SetStick(stick, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// 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[] Peek(uint offset, int count) => Encode($"peek 0x{offset:X8} {count}");
|
||||
|
||||
/// <summary>
|
||||
/// Sends the Bot <see cref="data"/> to be written to <see cref="offset"/>.
|
||||
/// </summary>
|
||||
/// <param name="offset">Address of the data</param>
|
||||
/// <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}"))}");
|
||||
}
|
||||
}
|
||||
11
NHSE.Injection/SwitchStick.cs
Normal file
11
NHSE.Injection/SwitchStick.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace NHSE.Injection
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller Stick differentiation
|
||||
/// </summary>
|
||||
public enum SwitchStick
|
||||
{
|
||||
LEFT,
|
||||
RIGHT,
|
||||
}
|
||||
}
|
||||
83
NHSE.Injection/SysBot.cs
Normal file
83
NHSE.Injection/SysBot.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
|
||||
namespace NHSE.Injection
|
||||
{
|
||||
public class SysBot
|
||||
{
|
||||
public string IP = "192.168.1.65";
|
||||
public int Port = 6000;
|
||||
public Socket Connection = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||
public bool Connected;
|
||||
|
||||
private readonly object _sync = new object();
|
||||
|
||||
public void Connect(string ip, int port)
|
||||
{
|
||||
IP = ip;
|
||||
Port = port;
|
||||
lock (_sync)
|
||||
{
|
||||
Connection = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||
Connection.Connect(IP, Port);
|
||||
Connected = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
Connection.Disconnect(false);
|
||||
Connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
private int ReadInternal(byte[] buffer)
|
||||
{
|
||||
int br = Connection.Receive(buffer, 0, 1, SocketFlags.None);
|
||||
while (buffer[br - 1] != (byte)'\n')
|
||||
br += Connection.Receive(buffer, br, 1, SocketFlags.None);
|
||||
return br;
|
||||
}
|
||||
|
||||
private int SendInternal(byte[] buffer) => Connection.Send(buffer);
|
||||
|
||||
public int Read(byte[] buffer)
|
||||
{
|
||||
lock (_sync)
|
||||
return ReadInternal(buffer);
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(uint offset, int length)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
var cmd = SwitchCommand.Peek(offset, length);
|
||||
SendInternal(cmd);
|
||||
|
||||
// give it time to push data back
|
||||
Thread.Sleep((length / 256) + 100);
|
||||
var buffer = new byte[(length * 2) + 1];
|
||||
var _ = ReadInternal(buffer);
|
||||
return Decoder.ConvertHexByteStringToBytes(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum InjectionType
|
||||
{
|
||||
Pouch,
|
||||
}
|
||||
}
|
||||
6
NHSE.sln
6
NHSE.sln
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHSE.Parsing", "NHSE.Parsin
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHSE.Tests", "NHSE.Tests\NHSE.Tests.csproj", "{AD3412A3-74EA-443D-BB07-B36E39D5166F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NHSE.Injection", "NHSE.Injection\NHSE.Injection.csproj", "{319E810B-A516-480E-88BD-F648222344D3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -39,6 +41,10 @@ Global
|
||||
{AD3412A3-74EA-443D-BB07-B36E39D5166F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AD3412A3-74EA-443D-BB07-B36E39D5166F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AD3412A3-74EA-443D-BB07-B36E39D5166F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{319E810B-A516-480E-88BD-F648222344D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{319E810B-A516-480E-88BD-F648222344D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{319E810B-A516-480E-88BD-F648222344D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{319E810B-A516-480E-88BD-F648222344D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user