diff --git a/App.config b/App.config
deleted file mode 100644
index 3ba592f..0000000
--- a/App.config
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Discord/DiscordBot.cs b/Discord/DiscordBot.cs
index 67e31b3..3ceee60 100644
--- a/Discord/DiscordBot.cs
+++ b/Discord/DiscordBot.cs
@@ -8,16 +8,16 @@ namespace SysbotMacro.Discord
{
internal class DiscordBot
{
- string _token;
- public Action LogAction { get; set; }
+ private readonly string _token;
+ public Action? LogAction { get; set; }
- private DiscordSocketClient _client;
+ private DiscordSocketClient? _client;
private readonly List _sudoUserIds;
private readonly List _channelIds;
private readonly List> _ipDict;
private readonly List> _macroDict;
- private MessageHandler _messageHandler;
+ private readonly MessageHandler _messageHandler;
public DiscordBot(string token, List sudos, List channelids, List> ipDict, List> macroDict)
{
@@ -40,6 +40,8 @@ public DiscordBot(string token, List sudos, List channelids, List<
public async Task MainAsync()
{
+ if (_client == null) return;
+
_client.Log += LogAsync;
_client.MessageReceived += MessageReceivedAsync;
@@ -84,8 +86,11 @@ await _messageHandler.HandleMessage(message, async (response) =>
//call to stop the bot
public async Task StopAsync()
{
- await _client.LogoutAsync();
- await _client.StopAsync();
+ if (_client != null)
+ {
+ await _client.LogoutAsync();
+ await _client.StopAsync();
+ }
}
}
}
diff --git a/Discord/MessageHandler.cs b/Discord/MessageHandler.cs
index 0b9184e..4c07425 100644
--- a/Discord/MessageHandler.cs
+++ b/Discord/MessageHandler.cs
@@ -12,7 +12,6 @@
using System.Text;
using System.Net;
using Newtonsoft.Json.Linq;
-using static LibUsbDotNet.Main.UsbTransferQueue;
using System.Runtime.InteropServices;
using System.IO;
@@ -21,6 +20,10 @@ namespace SysbotMacro.Discord
{
internal class MessageHandler
{
+ private const int DEFAULT_SWITCH_PORT = 6000;
+ private const int PING_TIMEOUT_MS = 2000;
+ private const string COMMAND_PREFIX = "!";
+
private readonly List> _ipDict;
private readonly List> _macroDict;
@@ -41,8 +44,8 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
var firstPart = parts.FirstOrDefault();
- // Check if the first word starts with '!'
- if (firstPart != null && firstPart.StartsWith("!")) //edit the prefix here. Maybe i should add it to the form.
+ // Check if the first word starts with the command prefix
+ if (firstPart != null && firstPart.StartsWith(COMMAND_PREFIX))
{
var command = firstPart.Substring(1); // Remove prefix
@@ -64,7 +67,7 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
var embed = new EmbedBuilder
{
Title = "Macro and Switch IP Data",
- Color = Color.Blue
+ Color = global::Discord.Color.Blue
};
string macroField = "";
@@ -117,35 +120,44 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
return;
}
- Ping pingSender = new Ping();
-
- // Ping the IP addres.
- PingReply reply = await pingSender.SendPingAsync(switchIp, 2000); // 2000 ms timeout
-
- // Check the status and if down, exit to prevent hanging
- if (reply.Status != IPStatus.Success)
+ using (var pingSender = new Ping())
{
- await sendResponse($"Switch IP {switchIp} is not reachable");
- return;
- }
+ // Ping the IP address
+ PingReply reply = await pingSender.SendPingAsync(switchIp, PING_TIMEOUT_MS);
+ // Check the status and if down, exit to prevent hanging
+ if (reply.Status != IPStatus.Success)
+ {
+ await sendResponse($"Switch IP {switchIp} is not reachable");
+ return;
+ }
+ }
// Execute
await sendResponse($"Executing macro {command} on Switch {switchKey}");
var config = new SwitchConnectionConfig
{
IP = switchIp,
- Port = 6000,
+ Port = DEFAULT_SWITCH_PORT,
Protocol = SwitchProtocol.WiFi
};
var bot = new Bot(config);
- bot.Connect();
- var cancellationToken = new CancellationToken(); // not tied to anything yet...
- await bot.ExecuteCommands(macro, () => false, cancellationToken); // not tied to anything yet... Should i?
- bot.Disconnect();
-
- await sendResponse($"Executed macro {command} on Switch {switchKey}");
+ try
+ {
+ bot.Connect();
+ var cancellationToken = new CancellationToken();
+ await bot.ExecuteCommands(macro, () => false, cancellationToken);
+ await sendResponse($"Executed macro {command} on Switch {switchKey}");
+ }
+ catch (Exception ex)
+ {
+ await sendResponse($"Error executing macro: {ex.Message}");
+ }
+ finally
+ {
+ try { bot.Disconnect(); } catch { }
+ }
}
// command: to check the status of all switches
else if (command == "status")
@@ -159,14 +171,19 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
var ipAddress = switchDict.ContainsKey("IPAddress") ? switchDict["IPAddress"].ToString() : "Unknown";
// Initialize a new instance of the Ping class.
- Ping pingSender = new Ping();
-
- PingReply reply = await pingSender.SendPingAsync(ipAddress, 2000); // 2000 ms timeout
-
- // Check the status.
- string status = reply.Status == IPStatus.Success ? "Up" : "Down";
-
- embedDescription.AppendLine($"Name: {switchName}, IP: {ipAddress}, Status: {status}");
+ using (var pingSender = new Ping())
+ {
+ try
+ {
+ PingReply reply = await pingSender.SendPingAsync(ipAddress, PING_TIMEOUT_MS);
+ string status = reply.Status == IPStatus.Success ? "Up" : "Down";
+ embedDescription.AppendLine($"Name: {switchName}, IP: {ipAddress}, Status: {status}");
+ }
+ catch (Exception ex)
+ {
+ embedDescription.AppendLine($"Name: {switchName}, IP: {ipAddress}, Status: Error - {ex.Message}");
+ }
+ }
}
// Create embed message with Discord.Net's EmbedBuilder.
@@ -174,7 +191,7 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
{
Title = "Switch Status Check",
Description = embedDescription.ToString(),
- Color = Color.Green // You can change the color based on your preferences.
+ Color = global::Discord.Color.Green // You can change the color based on your preferences.
};
// Send the embed.
@@ -206,39 +223,52 @@ public async Task HandleMessage(SocketMessage message, Func sendRe
var config = new SwitchConnectionConfig
{
IP = switchIp,
- Port = 6000,
+ Port = DEFAULT_SWITCH_PORT,
Protocol = SwitchProtocol.WiFi
};
var bot = new Bot(config);
- bot.Connect();
- byte[] imageBytes = bot.PixelPeek();
- System.IO.File.WriteAllBytes("test.jpg", imageBytes);
- string hexString = Encoding.UTF8.GetString(imageBytes);
+ try
+ {
+ bot.Connect();
+ byte[]? imageBytes = bot.PixelPeek();
+
+ if (imageBytes == null || imageBytes.Length == 0)
+ {
+ await sendResponse("Failed to capture the screen - no data received.");
+ return;
+ }
- // Convert the hexadecimal string back to a byte array
- byte[] actualImageBytes = Enumerable.Range(0, hexString.Length)
- .Where(x => x % 2 == 0)
- .Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
- .ToArray();
+ string hexString = Encoding.UTF8.GetString(imageBytes);
- // Write the byte array to a .jpg file
- System.IO.File.WriteAllBytes("test.jpg", actualImageBytes);
+ // Convert the hexadecimal string back to a byte array
+ byte[] actualImageBytes = Enumerable.Range(0, hexString.Length)
+ .Where(x => x % 2 == 0)
+ .Select(x => Convert.ToByte(hexString.Substring(x, 2), 16))
+ .ToArray();
- // Send the image as an attachment in Discord
- if (actualImageBytes != null && actualImageBytes.Length > 0)
- {
- using (var stream = new MemoryStream(actualImageBytes))
+ // Send the image as an attachment in Discord
+ if (actualImageBytes.Length > 0)
+ {
+ using (var stream = new MemoryStream(actualImageBytes))
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ var embed = new EmbedBuilder();
+ embed.ImageUrl = "attachment://screenshot.jpg";
+ await ((ISocketMessageChannel)message.Channel).SendFileAsync(stream, "screenshot.jpg", $"Here's the screenshot of {switchKey}", embed: embed.Build());
+ }
+ }
+ else
{
- stream.Seek(0, SeekOrigin.Begin);
- var embed = new EmbedBuilder();
- embed.ImageUrl = "attachment://screenshot.jpg";
- Console.WriteLine($"Received {actualImageBytes.Length} bytes. First bytes: {actualImageBytes[0]} {actualImageBytes[1]} ...");
- await ((ISocketMessageChannel)message.Channel).SendFileAsync(stream, "screenshot.jpg", $"Here's the screenshot of {switchKey}", embed: embed.Build());
+ await sendResponse("Failed to process screen capture data.");
}
}
- else
+ catch (Exception ex)
+ {
+ await sendResponse($"Error capturing screenshot: {ex.Message}");
+ }
+ finally
{
- await sendResponse("Failed to capture the screen.");
+ try { bot.Disconnect(); } catch { }
}
diff --git a/Form1.cs b/Form1.cs
index 86fe419..4de065d 100644
--- a/Form1.cs
+++ b/Form1.cs
@@ -24,6 +24,12 @@ namespace SysbotMacro
{
public partial class Form1 : Form
{
+ private const int DEFAULT_SWITCH_PORT = 6000;
+ private const int DEFAULT_BUTTON_DELAY = 100;
+ private const int PING_TIMEOUT_MS = 2000;
+ private const int MAX_SWITCH_NAME_LENGTH = 50;
+ private const int DISCORD_BOT_DELAY = -1;
+
private bool canSaveData = false;
// Declare the bots list that will be looped through when commands are sent.
@@ -35,10 +41,8 @@ public partial class Form1 : Form
private List> ipDict = new List>();
private List> macroDict = new List>();
-
-
-
- private DiscordBot _bot;
+ private DiscordBot? _bot;
+ private CancellationTokenSource? cancellationTokenSource;
@@ -91,9 +95,6 @@ private void SaveData()
File.WriteAllText("macroListView.json", JsonConvert.SerializeObject(macroDict));
- //save discordTokenTB.text to a file
- File.WriteAllText("discordTokenTB.json", JsonConvert.SerializeObject(discordTokenTB.Text));
-
// Save userIDLV to a JSON file
var userIDListViewData = new List>();
foreach (ListViewItem item in userIDLV.Items)
@@ -213,15 +214,6 @@ private void LoadData()
}
}
- // Load discordTokenTB.text from a file
- if (File.Exists("discordTokenTB.json"))
- {
- var discordTokenTBDataJson = File.ReadAllText("discordTokenTB.json");
- var discordTokenTBData = JsonConvert.DeserializeObject(discordTokenTBDataJson);
-
- discordTokenTB.Text = discordTokenTBData;
- }
-
canSaveData = true;
}
@@ -249,7 +241,7 @@ private void InitializeBots()
var config = new SwitchConnectionConfig
{
IP = ip,
- Port = 6000,
+ Port = DEFAULT_SWITCH_PORT,
Protocol = SwitchProtocol.WiFi
};
@@ -581,54 +573,84 @@ private void delayButton_Click(object sender, EventArgs e)
private void addIpButton_Click(object sender, EventArgs e)
{
- string ipText = ipTextField.Text;
- string switchName = switchNameTB.Text;
+ string ipText = ipTextField.Text?.Trim();
+ string switchName = switchNameTB.Text?.Trim();
- if (string.IsNullOrEmpty(switchName))
+ if (string.IsNullOrWhiteSpace(switchName))
{
- UpdateLogger("Add a name for the switch");
+ UpdateLogger("Switch name cannot be empty");
return;
}
- if (!string.IsNullOrEmpty(ipText))
+ if (string.IsNullOrWhiteSpace(ipText))
{
- if (IPAddress.TryParse(ipText, out IPAddress address))
- {
- ListViewItem existingItem = null;
- foreach (ListViewItem item in ipListView.Items)
- {
- if (item.SubItems[1].Text == switchName && item.SubItems[2].Text == ipText)
- {
- existingItem = item;
- break;
- }
- }
+ UpdateLogger("IP address cannot be empty");
+ return;
+ }
- if (existingItem != null)
- {
- existingItem.SubItems[1].Text = switchName;
- existingItem.SubItems[2].Text = ipText;
- }
- else
- {
- ListViewItem newItem = new ListViewItem(""); // New ListViewItem for the first column checkbox nonsense
- newItem.SubItems.Add(switchName);
- newItem.SubItems.Add(ipText);
- ipListView.Items.Add(newItem);
- ipListView.Invalidate();
- }
+ if (!IsValidIPAddress(ipText))
+ {
+ UpdateLogger("Invalid IP address format. Please enter a valid IPv4 address.");
+ return;
+ }
+
+ if (switchName.Length > MAX_SWITCH_NAME_LENGTH)
+ {
+ UpdateLogger($"Switch name is too long (max {MAX_SWITCH_NAME_LENGTH} characters)");
+ return;
+ }
- ipTextField.Clear();
- switchNameTB.Clear();
- SaveData();
+ ListViewItem existingItem = null;
+ foreach (ListViewItem item in ipListView.Items)
+ {
+ if (item.SubItems[1].Text.Equals(switchName, StringComparison.OrdinalIgnoreCase))
+ {
+ existingItem = item;
+ break;
+ }
+ }
+
+ try
+ {
+ if (existingItem != null)
+ {
+ existingItem.SubItems[1].Text = switchName;
+ existingItem.SubItems[2].Text = ipText;
+ UpdateLogger($"Updated switch '{switchName}' with IP {ipText}");
}
else
{
- UpdateLogger("Invalid IP address format.");
+ ListViewItem newItem = new ListViewItem("");
+ newItem.SubItems.Add(switchName);
+ newItem.SubItems.Add(ipText);
+ ipListView.Items.Add(newItem);
+ ipListView.Invalidate();
+ UpdateLogger($"Added switch '{switchName}' with IP {ipText}");
}
+
+ ipTextField.Clear();
+ switchNameTB.Clear();
+ SaveData();
+ }
+ catch (Exception ex)
+ {
+ UpdateLogger($"Error adding switch: {ex.Message}");
}
}
+ private bool IsValidIPAddress(string ipAddress)
+ {
+ if (!IPAddress.TryParse(ipAddress, out IPAddress address))
+ return false;
+
+ if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
+ return false;
+
+ string[] parts = ipAddress.Split('.');
+ return parts.Length == 4 && parts.All(part =>
+ int.TryParse(part, out int value) && value >= 0 && value <= 255);
+ }
+
private void deleteIpButton_Click(object sender, EventArgs e)
{
if (ipListView.SelectedItems.Count > 0) // Make sure an item is selected
@@ -652,46 +674,60 @@ private void deleteButton_Click(object sender, EventArgs e)
}
}
- private CancellationTokenSource cancellationTokenSource;
private async void playbButton_Click(object sender, EventArgs e)
{
- bots.Clear();
- //this was the best time to initialize bots.
- InitializeBots();
- if (textBox1.Text == "")
- {
- UpdateLogger("No macro entered");
- return;
- }
- if (loopCheckbox.Checked == true)
+ try
{
- stopbButton.Enabled = true;
- stopbButton.BackColor = Color.Aqua;
- playbButton.Enabled = false;
- UpdateLogger("Starting Macro Loop");
-
- }
-
- cancellationTokenSource = new CancellationTokenSource(); // Create a new CancellationTokenSource that you call in the stop button code
-
- string commands = textBox1.Text;
- Func loopFunc = () => loopCheckbox.Checked;
+ bots.Clear();
+ InitializeBots();
+
+ if (string.IsNullOrWhiteSpace(textBox1.Text))
+ {
+ UpdateLogger("No macro entered");
+ return;
+ }
- foreach (var bot in bots)
- try
+ if (bots.Count == 0)
{
- bot.Connect();
- await bot.ExecuteCommands(commands, loopFunc, cancellationTokenSource.Token);
- bot.Disconnect();
+ UpdateLogger("No switches selected");
+ return;
}
- catch (Exception ex)
+
+ if (loopCheckbox.Checked)
{
-
- UpdateLogger(ex.Message);
+ stopbButton.Enabled = true;
+ stopbButton.BackColor = Color.Aqua;
+ playbButton.Enabled = false;
+ UpdateLogger("Starting Macro Loop");
}
+ cancellationTokenSource = new CancellationTokenSource();
+ string commands = textBox1.Text;
+ Func loopFunc = () => loopCheckbox.Checked;
+ foreach (var bot in bots)
+ {
+ try
+ {
+ bot.Connect();
+ await bot.ExecuteCommands(commands, loopFunc, cancellationTokenSource.Token);
+ bot.Disconnect();
+ }
+ catch (Exception ex)
+ {
+ UpdateLogger($"Error executing commands on bot: {ex.Message}");
+ try { bot.Disconnect(); } catch { }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ UpdateLogger($"Error in macro execution: {ex.Message}");
+ playbButton.Enabled = true;
+ stopbButton.Enabled = false;
+ stopbButton.BackColor = Color.White;
+ }
}
//stop button terminates the macro loop
@@ -745,84 +781,96 @@ private void livebButton_Click(object sender, EventArgs e)
UpdateLogger(msg);
}
- //Use to send any button to the list of selected IPs
private async Task SendLiveButtonPress(string button)
{
- InitializeBots();
- foreach (var bot in bots)
+ try
{
- try
+ InitializeBots();
+
+ if (bots.Count == 0)
{
- bot.Connect();
- switch (button)
- {
- case "A":
- await bot.PressAButton();
- break;
- case "B":
- await bot.PressBButton();
- break;
- case "X":
- await bot.PressXButton();
- break;
- case "Y":
- await bot.PressYButton();
- break;
- case "L":
- await bot.PressLButton();
- break;
- case "R":
- await bot.PressRButton();
- break;
- case "ZL":
- await bot.PressZLButton();
- break;
- case "ZR":
- await bot.PressZRButton();
- break;
- case "Up":
- await bot.PressDPadUp();
- break;
- case "Down":
- await bot.PressDPadDown();
- break;
- case "Left":
- await bot.PressDPadLeft();
- break;
- case "Right":
- await bot.PressDPadRight();
- break;
- case "Plus":
- await bot.PressPlusButton();
- break;
- case "Minus":
- await bot.PressMinusButton();
- break;
- case "Home":
- await bot.PressHomeButton();
- break;
- case "Capture":
- await bot.PressCaptureButton();
- break;
- case "LStick":
- await bot.PressLeftStickButton();
- break;
- case "RStick":
- await bot.PressRightStickButton();
- break;
-
-
- // Add cases for the other buttons as needed...
- default:
- throw new ArgumentException("Invalid button string.");
- }
- bot.Disconnect();
+ UpdateLogger("No switches selected for live button press");
+ return;
}
- catch (Exception ex)
+
+ foreach (var bot in bots)
{
- UpdateLogger(ex.Message);
+ try
+ {
+ bot.Connect();
+ switch (button)
+ {
+ case "A":
+ await bot.PressAButton();
+ break;
+ case "B":
+ await bot.PressBButton();
+ break;
+ case "X":
+ await bot.PressXButton();
+ break;
+ case "Y":
+ await bot.PressYButton();
+ break;
+ case "L":
+ await bot.PressLButton();
+ break;
+ case "R":
+ await bot.PressRButton();
+ break;
+ case "ZL":
+ await bot.PressZLButton();
+ break;
+ case "ZR":
+ await bot.PressZRButton();
+ break;
+ case "Up":
+ await bot.PressDPadUp();
+ break;
+ case "Down":
+ await bot.PressDPadDown();
+ break;
+ case "Left":
+ await bot.PressDPadLeft();
+ break;
+ case "Right":
+ await bot.PressDPadRight();
+ break;
+ case "Plus":
+ await bot.PressPlusButton();
+ break;
+ case "Minus":
+ await bot.PressMinusButton();
+ break;
+ case "Home":
+ await bot.PressHomeButton();
+ break;
+ case "Capture":
+ await bot.PressCaptureButton();
+ break;
+ case "LStick":
+ await bot.PressLeftStickButton();
+ break;
+ case "RStick":
+ await bot.PressRightStickButton();
+ break;
+ default:
+ UpdateLogger($"Unknown button: {button}");
+ return;
+ }
+ bot.Disconnect();
+ }
+ catch (Exception ex)
+ {
+ UpdateLogger($"Error pressing {button} on bot: {ex.Message}");
+ try { bot.Disconnect(); } catch { }
+ }
}
}
+ catch (Exception ex)
+ {
+ UpdateLogger($"Error in live button press: {ex.Message}");
+ }
}
private async void botStartBButton_Click(object sender, EventArgs e)
diff --git a/LoadingScreen.cs b/LoadingScreen.cs
new file mode 100644
index 0000000..263800e
--- /dev/null
+++ b/LoadingScreen.cs
@@ -0,0 +1,359 @@
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Drawing.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace SysbotMacro
+{
+ public partial class LoadingScreen : Form
+ {
+ private System.Windows.Forms.Timer animationTimer;
+ private System.Windows.Forms.Timer glitchTimer;
+ private System.Windows.Forms.Timer progressTimer;
+ private int animationFrame = 0;
+ private int glitchFrame = 0;
+ private int progressValue = 0;
+ private Random random = new Random();
+ private bool glitchActive = false;
+ private Color neonBlue = Color.FromArgb(0, 255, 255);
+ private Color neonPink = Color.FromArgb(255, 20, 147);
+ private Color neonGreen = Color.FromArgb(57, 255, 20);
+ private Color switchRed = Color.FromArgb(230, 45, 75);
+ private Color switchBlue = Color.FromArgb(0, 174, 239);
+
+ public LoadingScreen()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+
+ this.AutoScaleDimensions = new SizeF(6F, 13F);
+ this.AutoScaleMode = AutoScaleMode.Font;
+ this.BackColor = Color.Black;
+ this.ClientSize = new Size(800, 600);
+ this.ControlBox = false;
+ this.FormBorderStyle = FormBorderStyle.None;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "LoadingScreen";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = FormStartPosition.CenterScreen;
+ this.Text = "Loading";
+ this.TopMost = true;
+ this.WindowState = FormWindowState.Normal;
+
+ this.SetStyle(ControlStyles.AllPaintingInWmPaint |
+ ControlStyles.UserPaint |
+ ControlStyles.DoubleBuffer |
+ ControlStyles.ResizeRedraw, true);
+
+ this.Paint += LoadingScreen_Paint;
+ this.Load += LoadingScreen_Load;
+
+ this.ResumeLayout(false);
+ }
+
+ private void LoadingScreen_Load(object sender, EventArgs e)
+ {
+ animationTimer = new System.Windows.Forms.Timer();
+ animationTimer.Interval = 50;
+ animationTimer.Tick += AnimationTimer_Tick;
+ animationTimer.Start();
+
+ glitchTimer = new System.Windows.Forms.Timer();
+ glitchTimer.Interval = 200;
+ glitchTimer.Tick += GlitchTimer_Tick;
+ glitchTimer.Start();
+
+ progressTimer = new System.Windows.Forms.Timer();
+ progressTimer.Interval = 100;
+ progressTimer.Tick += ProgressTimer_Tick;
+ progressTimer.Start();
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(3500);
+ if (this.InvokeRequired)
+ {
+ this.Invoke(new Action(() => this.Close()));
+ }
+ else
+ {
+ this.Close();
+ }
+ });
+ }
+
+ private void AnimationTimer_Tick(object sender, EventArgs e)
+ {
+ animationFrame++;
+ if (animationFrame > 360) animationFrame = 0;
+ this.Invalidate();
+ }
+
+ private void GlitchTimer_Tick(object sender, EventArgs e)
+ {
+ glitchFrame++;
+ glitchActive = random.Next(0, 10) < 3;
+ this.Invalidate();
+ }
+
+ private void ProgressTimer_Tick(object sender, EventArgs e)
+ {
+ if (progressValue < 100)
+ {
+ progressValue += random.Next(1, 5);
+ if (progressValue > 100) progressValue = 100;
+ }
+ }
+
+ private void LoadingScreen_Paint(object sender, PaintEventArgs e)
+ {
+ Graphics g = e.Graphics;
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.TextRenderingHint = TextRenderingHint.AntiAlias;
+
+ DrawBackground(g);
+ DrawTitle(g);
+ DrawProgressBar(g);
+ DrawLoadingText(g);
+ DrawNeonEffects(g);
+ DrawSwitchLogo(g);
+ }
+
+ private void DrawBackground(Graphics g)
+ {
+ Rectangle rect = this.ClientRectangle;
+
+ using (LinearGradientBrush brush = new LinearGradientBrush(
+ rect, Color.FromArgb(10, 10, 30), Color.FromArgb(5, 5, 15), LinearGradientMode.Vertical))
+ {
+ g.FillRectangle(brush, rect);
+ }
+
+ for (int i = 0; i < 50; i++)
+ {
+ int x = (int)((animationFrame * 2 + i * 20) % (Width + 100));
+ int y = i * 12;
+ int alpha = (int)(50 * Math.Sin((animationFrame + i) * 0.1));
+ if (alpha < 0) alpha = -alpha;
+
+ using (Pen pen = new Pen(Color.FromArgb(alpha, neonBlue), 1))
+ {
+ g.DrawLine(pen, x - 50, y, x, y);
+ }
+ }
+
+ if (glitchActive)
+ {
+ using (SolidBrush glitchBrush = new SolidBrush(Color.FromArgb(20, neonPink)))
+ {
+ for (int i = 0; i < 5; i++)
+ {
+ Rectangle glitchRect = new Rectangle(
+ random.Next(0, Width),
+ random.Next(0, Height),
+ random.Next(50, 200),
+ random.Next(2, 10)
+ );
+ g.FillRectangle(glitchBrush, glitchRect);
+ }
+ }
+ }
+ }
+
+ private void DrawTitle(Graphics g)
+ {
+ string title = "NINTENDO SWITCH";
+ string subtitle = "SYSBOT REMOTE";
+
+ using (Font titleFont = new Font("Consolas", 42, FontStyle.Bold))
+ using (Font subtitleFont = new Font("Consolas", 28, FontStyle.Bold))
+ {
+ SizeF titleSize = g.MeasureString(title, titleFont);
+ SizeF subtitleSize = g.MeasureString(subtitle, subtitleFont);
+
+ float titleX = (Width - titleSize.Width) / 2;
+ float titleY = Height / 2 - 100;
+ float subtitleX = (Width - subtitleSize.Width) / 2;
+ float subtitleY = titleY + titleSize.Height + 10;
+
+ if (glitchActive && glitchFrame % 3 == 0)
+ {
+ titleX += random.Next(-5, 6);
+ subtitleX += random.Next(-3, 4);
+ }
+
+ using (GraphicsPath titlePath = new GraphicsPath())
+ using (GraphicsPath subtitlePath = new GraphicsPath())
+ {
+ titlePath.AddString(title, titleFont.FontFamily, (int)titleFont.Style, titleFont.Size, new PointF(titleX, titleY), StringFormat.GenericDefault);
+ subtitlePath.AddString(subtitle, subtitleFont.FontFamily, (int)subtitleFont.Style, subtitleFont.Size, new PointF(subtitleX, subtitleY), StringFormat.GenericDefault);
+
+ using (Pen glowPen = new Pen(switchRed, 8))
+ using (SolidBrush textBrush = new SolidBrush(Color.White))
+ {
+ glowPen.LineJoin = LineJoin.Round;
+ g.DrawPath(glowPen, titlePath);
+ g.FillPath(textBrush, titlePath);
+ }
+
+ using (Pen glowPen = new Pen(switchBlue, 6))
+ using (SolidBrush textBrush = new SolidBrush(Color.White))
+ {
+ glowPen.LineJoin = LineJoin.Round;
+ g.DrawPath(glowPen, subtitlePath);
+ g.FillPath(textBrush, subtitlePath);
+ }
+ }
+ }
+ }
+
+ private void DrawProgressBar(Graphics g)
+ {
+ Rectangle progressRect = new Rectangle(Width / 2 - 200, Height - 150, 400, 20);
+ Rectangle fillRect = new Rectangle(progressRect.X, progressRect.Y,
+ (int)(progressRect.Width * progressValue / 100.0), progressRect.Height);
+
+ using (Pen borderPen = new Pen(neonBlue, 2))
+ {
+ g.DrawRectangle(borderPen, progressRect);
+ }
+
+ if (fillRect.Width > 0)
+ {
+ using (LinearGradientBrush fillBrush = new LinearGradientBrush(
+ fillRect, neonGreen, neonBlue, LinearGradientMode.Horizontal))
+ {
+ g.FillRectangle(fillBrush, fillRect);
+ }
+
+ using (Pen glowPen = new Pen(Color.FromArgb(100, neonGreen), 6))
+ {
+ g.DrawRectangle(glowPen, fillRect);
+ }
+ }
+
+ string progressText = $"{progressValue}%";
+ using (Font font = new Font("Consolas", 12, FontStyle.Bold))
+ using (SolidBrush brush = new SolidBrush(Color.White))
+ {
+ SizeF textSize = g.MeasureString(progressText, font);
+ g.DrawString(progressText, font, brush,
+ progressRect.X + progressRect.Width / 2 - textSize.Width / 2,
+ progressRect.Y + progressRect.Height + 10);
+ }
+ }
+
+ private void DrawLoadingText(Graphics g)
+ {
+ string[] loadingMessages = {
+ "INITIALIZING SYSBOT REMOTE INTERFACE...",
+ "LOADING SYSBOT REMOTE INTERFACE...",
+ "READY FOR OPERATION"
+ };
+
+ int messageIndex = Math.Min((progressValue / 34), loadingMessages.Length - 1);
+ string message = loadingMessages[messageIndex];
+
+ if (glitchActive && random.Next(0, 10) < 3)
+ {
+ char[] chars = message.ToCharArray();
+ for (int i = 0; i < chars.Length; i++)
+ {
+ if (random.Next(0, 10) < 2)
+ {
+ chars[i] = (char)random.Next(33, 127);
+ }
+ }
+ message = new string(chars);
+ }
+
+ using (Font font = new Font("Consolas", 14, FontStyle.Regular))
+ using (SolidBrush brush = new SolidBrush(neonGreen))
+ {
+ SizeF textSize = g.MeasureString(message, font);
+ float x = (Width - textSize.Width) / 2;
+ float y = Height - 100;
+
+ using (SolidBrush glowBrush = new SolidBrush(Color.FromArgb(50, neonGreen)))
+ {
+ g.DrawString(message, font, glowBrush, x + 1, y + 1);
+ g.DrawString(message, font, glowBrush, x - 1, y - 1);
+ }
+ g.DrawString(message, font, brush, x, y);
+ }
+ }
+
+ private void DrawNeonEffects(Graphics g)
+ {
+ float pulse = (float)(0.5 + 0.5 * Math.Sin(animationFrame * 0.1));
+
+ using (Pen neonPen = new Pen(Color.FromArgb((int)(100 * pulse), neonPink), 3))
+ {
+ g.DrawRectangle(neonPen, 20, 20, Width - 40, Height - 40);
+ }
+
+ for (int i = 0; i < 8; i++)
+ {
+ float angle = (animationFrame + i * 45) * (float)Math.PI / 180;
+ int centerX = Width / 2;
+ int centerY = Height / 2 - 50;
+ int radius = 150 + (int)(30 * Math.Sin(animationFrame * 0.05 + i));
+
+ int x = centerX + (int)(radius * Math.Cos(angle));
+ int y = centerY + (int)(radius * Math.Sin(angle));
+
+ using (SolidBrush dotBrush = new SolidBrush(Color.FromArgb((int)(150 * pulse), neonBlue)))
+ {
+ g.FillEllipse(dotBrush, x - 3, y - 3, 6, 6);
+ }
+ }
+ }
+
+ private void DrawSwitchLogo(Graphics g)
+ {
+ int logoSize = 60;
+ int logoX = Width - logoSize - 30;
+ int logoY = 30;
+
+ using (SolidBrush redBrush = new SolidBrush(switchRed))
+ using (SolidBrush blueBrush = new SolidBrush(switchBlue))
+ using (SolidBrush grayBrush = new SolidBrush(Color.FromArgb(80, 80, 80)))
+ {
+ Rectangle leftJoycon = new Rectangle(logoX, logoY, logoSize / 3, logoSize);
+ Rectangle rightJoycon = new Rectangle(logoX + logoSize * 2 / 3, logoY, logoSize / 3, logoSize);
+ Rectangle screen = new Rectangle(logoX + logoSize / 3, logoY + logoSize / 4, logoSize / 3, logoSize / 2);
+
+ g.FillRectangle(blueBrush, leftJoycon);
+ g.FillRectangle(redBrush, rightJoycon);
+ g.FillRectangle(grayBrush, screen);
+
+ using (Pen glowPen = new Pen(Color.FromArgb(100, Color.White), 2))
+ {
+ g.DrawRectangle(glowPen, new Rectangle(logoX - 2, logoY - 2, logoSize + 4, logoSize + 4));
+ }
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ animationTimer?.Stop();
+ animationTimer?.Dispose();
+ glitchTimer?.Stop();
+ glitchTimer?.Dispose();
+ progressTimer?.Stop();
+ progressTimer?.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
index 9b6ae36..f39c524 100644
--- a/Program.cs
+++ b/Program.cs
@@ -13,6 +13,12 @@ static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
+
+ using (LoadingScreen loadingScreen = new LoadingScreen())
+ {
+ loadingScreen.ShowDialog();
+ }
+
Application.Run(new Form1());
}
}
diff --git a/README.md b/README.md
index da08036..53b8491 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+
+


diff --git a/RjControlsButton.cs b/RjControlsButton.cs
index 51f55f8..445195b 100644
--- a/RjControlsButton.cs
+++ b/RjControlsButton.cs
@@ -20,6 +20,7 @@ public class RJButton : Button
//Properties
[Category("RJ Code Advance")]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int BorderSize
{
get { return borderSize; }
@@ -31,6 +32,7 @@ public int BorderSize
}
[Category("RJ Code Advance")]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int BorderRadius
{
get { return borderRadius; }
@@ -42,6 +44,7 @@ public int BorderRadius
}
[Category("RJ Code Advance")]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color BorderColor
{
get { return borderColor; }
@@ -53,6 +56,7 @@ public Color BorderColor
}
[Category("RJ Code Advance")]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color BackgroundColor
{
get { return this.BackColor; }
@@ -60,6 +64,7 @@ public Color BackgroundColor
}
[Category("RJ Code Advance")]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color TextColor
{
get { return this.ForeColor; }
diff --git a/SysBot.cs b/SysBot.cs
index 4abe9c4..9d3eaff 100644
--- a/SysBot.cs
+++ b/SysBot.cs
@@ -144,7 +144,7 @@ public async Task PressDPadRight()
await Connection.SendAsync(new ArraySegment(command), SocketFlags.None);
}
- public byte[] PixelPeek()
+ public byte[]? PixelPeek()
{
// Original data in hexadecimal format
byte[] hexData = SwitchCommand.PixelPeek();
@@ -195,36 +195,51 @@ public byte[] PixelPeek()
public async Task ExecuteCommands(string commands, Func loopFunc, CancellationToken cancellationToken)
{
- var splitCommands = commands.TrimEnd().Split(' ');
+ if (string.IsNullOrWhiteSpace(commands))
+ return;
- int defaultDelay = 100; // Default delay after each command
+ var splitCommands = commands.TrimEnd().Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ const int defaultDelay = 100;
+ int currentDelay = defaultDelay;
- for (int i = 0; i < splitCommands.Length; i++)
+ try
{
- if (cancellationToken.IsCancellationRequested)
+ for (int i = 0; i < splitCommands.Length; i++)
{
- break;
+ if (cancellationToken.IsCancellationRequested)
+ break;
+
+ var command = splitCommands[i];
+
+ if (i < splitCommands.Length - 1 &&
+ splitCommands[i + 1].StartsWith("d") &&
+ int.TryParse(splitCommands[i + 1].Substring(1), out var delay) &&
+ delay > 0)
+ {
+ await PressButton(command);
+ await Task.Delay(delay, cancellationToken);
+ currentDelay = delay;
+ i++;
+ }
+ else
+ {
+ await PressButton(command);
+ await Task.Delay(currentDelay, cancellationToken);
+ }
}
- var command = splitCommands[i];
- // If the command is followed by a "d" and a number, interpret it as a delay
- if (i < splitCommands.Length - 2 && splitCommands[i + 1].StartsWith("d") && int.TryParse(splitCommands[i + 1].Substring(1), out var delay))
- {
- await PressButton(command);
- await Task.Delay(delay);
- defaultDelay = delay; // Update the default delay
- i++; // Skip the next item in the loop, since we've already processed it
- }
- else
+ if (loopFunc() && !cancellationToken.IsCancellationRequested)
{
- await PressButton(command);
- await Task.Delay(defaultDelay); // Wait for the default delay
+ await ExecuteCommands(commands, loopFunc, cancellationToken);
}
}
-
- if (loopFunc() && !cancellationToken.IsCancellationRequested)
+ catch (OperationCanceledException)
+ {
+ // Expected when cancellation is requested
+ }
+ catch (Exception ex)
{
- await ExecuteCommands(commands, loopFunc, cancellationToken);
+ throw new InvalidOperationException($"Error executing commands: {ex.Message}", ex);
}
}
diff --git a/SysBotRemote.csproj b/SysBotRemote.csproj
index e744345..c549878 100644
--- a/SysBotRemote.csproj
+++ b/SysBotRemote.csproj
@@ -1,211 +1,57 @@
-
-
-
+
+
- Debug
- AnyCPU
- {0C2C7A73-4626-47C5-A540-2ADD8ADE42B1}
WinExe
+ net9.0-windows
+ true
SysbotMacro
SysBotRemote
- v4.7.2
- 512
- true
- true
- false
- publish\
- true
- Disk
- false
- Foreground
- 7
- Days
- false
- false
- true
- 3
- 1.0.0.%2a
- false
- true
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
nintendo_switch_icon_136357.ico
+ enable
+ enable
+ true
+ false
-
- D9FB87FA2C4C586691921D9EC938EEBD447369E1
-
-
- SysbotMacro_TemporaryKey.pfx
-
-
- true
-
-
- false
-
+
-
- packages\Discord.Net.Commands.3.12.0\lib\net461\Discord.Net.Commands.dll
-
-
- packages\Discord.Net.Core.3.12.0\lib\net461\Discord.Net.Core.dll
-
-
- packages\Discord.Net.Interactions.3.12.0\lib\net461\Discord.Net.Interactions.dll
-
-
- packages\Discord.Net.Rest.3.12.0\lib\net461\Discord.Net.Rest.dll
-
-
- packages\Discord.Net.Webhook.3.12.0\lib\netstandard2.0\Discord.Net.Webhook.dll
-
-
- packages\Discord.Net.WebSocket.3.12.0\lib\net461\Discord.Net.WebSocket.dll
-
-
- packages\LibUsbDotNet.2.2.29\lib\net45\LibUsbDotNet.LibUsbDotNet.dll
-
-
- packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
-
-
- packages\Microsoft.Extensions.DependencyInjection.Abstractions.5.0.0\lib\net461\Microsoft.Extensions.DependencyInjection.Abstractions.dll
-
-
- packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
-
-
- packages\NLog.5.1.3\lib\net46\NLog.dll
-
-
- packages\SysBot.Base.1.0.8\lib\netstandard2.0\SysBot.Base.dll
-
-
-
- packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
-
-
- packages\System.Collections.Immutable.5.0.0\lib\net461\System.Collections.Immutable.dll
-
-
-
-
- packages\System.Interactive.Async.5.0.0\lib\net461\System.Interactive.Async.dll
-
-
-
- packages\System.Linq.Async.5.0.0\lib\net461\System.Linq.Async.dll
-
-
- packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
-
-
-
- packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
-
-
- packages\System.Reactive.5.0.0\lib\net472\System.Reactive.dll
-
-
- packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
-
-
- packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
-
-
- packages\System.ValueTuple.4.4.0\lib\net47\System.ValueTuple.dll
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
- Component
-
-
- Form
-
-
- Form1.cs
-
-
-
-
- Form1.cs
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
- Designer
-
-
+
+
+
+
+
+
+
+
True
Resources.resx
True
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
+
True
Settings.settings
True
-
-
-
-
+
-
-
-
-
-
-
- False
- Microsoft .NET Framework 4.7.2 %28x86 and x64%29
- true
-
-
- False
- .NET Framework 3.5 SP1
- false
-
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
-
+
\ No newline at end of file
diff --git a/packages.config b/packages.config
deleted file mode 100644
index a547795..0000000
--- a/packages.config
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file