commit 7f17f3925a1e9d01632ce42e7aec58ab207845f6 Author: loicbersier Date: Sun Oct 25 16:59:04 2020 +0100 DiscordPlaysSwitch & TwitchPlaysSwitch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..870ada7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +SysBot.Base/ +DiscordPlaySwitch/bin +DiscordPlaySwitch/obj +TwitchPlaySwitch/bin +TwitchPlaySwitch/obj \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3a82ae2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "SysBot.NET"] + path = SysBot.NET + url = https://github.com/kwsch/SysBot.NET.git diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/contentModel.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/contentModel.xml new file mode 100644 index 0000000..dddd123 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/contentModel.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/encodings.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/indexLayout.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/modules.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/modules.xml new file mode 100644 index 0000000..1437290 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/projectSettingsUpdater.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..4bb9f4d --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/projectSettingsUpdater.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/.idea/workspace.xml b/.idea/.idea.DiscordPlaySwitch.dir/.idea/workspace.xml new file mode 100644 index 0000000..390891e --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/.idea/workspace.xml @@ -0,0 +1,71 @@ + + + + DiscordPlaySwitch/DiscordPlaySwitch.csproj + + + + + + + + + + + + + + + + + + + + + + + 1600253557239 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch.dir/riderModule.iml b/.idea/.idea.DiscordPlaySwitch.dir/riderModule.iml new file mode 100644 index 0000000..1a4e0d9 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch.dir/riderModule.iml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.DiscordPlaySwitch/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/contentModel.xml b/.idea/.idea.DiscordPlaySwitch/.idea/contentModel.xml new file mode 100644 index 0000000..e0d6631 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/contentModel.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/discord.xml b/.idea/.idea.DiscordPlaySwitch/.idea/discord.xml new file mode 100644 index 0000000..cd711a0 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/discord.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/encodings.xml b/.idea/.idea.DiscordPlaySwitch/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/indexLayout.xml b/.idea/.idea.DiscordPlaySwitch/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/modules.xml b/.idea/.idea.DiscordPlaySwitch/.idea/modules.xml new file mode 100644 index 0000000..942b898 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/projectSettingsUpdater.xml b/.idea/.idea.DiscordPlaySwitch/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..4bb9f4d --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/projectSettingsUpdater.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/vcs.xml b/.idea/.idea.DiscordPlaySwitch/.idea/vcs.xml new file mode 100644 index 0000000..56806b5 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/.idea/workspace.xml b/.idea/.idea.DiscordPlaySwitch/.idea/workspace.xml new file mode 100644 index 0000000..20ec658 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/.idea/workspace.xml @@ -0,0 +1,485 @@ + + + + DiscordPlaySwitch/DiscordPlaySwitch.csproj + TwitchPlaySwitch/TwitchPlaySwitch.csproj + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1600254011799 + + + 1600443267971 + + + 1601215825516 + + + 1601215939083 + + + 1601216545046 + + + 1601216723277 + + + 1601217111941 + + + 1601217127004 + + + 1601217462310 + + + 1601217472406 + + + 1601217968948 + + + 1601217983168 + + + 1601218188204 + + + 1601330792259 + + + 1601333833895 + + + 1601333842289 + + + 1601333916849 + + + 1601334235482 + + + 1601334240777 + + + 1601334250876 + + + 1601334676770 + + + 1601334686072 + + + 1601928132301 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DiscordPlaySwitch/riderModule.iml b/.idea/.idea.DiscordPlaySwitch/riderModule.iml new file mode 100644 index 0000000..1a4e0d9 --- /dev/null +++ b/.idea/.idea.DiscordPlaySwitch/riderModule.iml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/.name b/.idea/.idea.TwitchPlaySwitch/.idea/.name new file mode 100644 index 0000000..5f06a33 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/.name @@ -0,0 +1 @@ +TwitchPlaySwitch \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/codeStyles/codeStyleConfig.xml b/.idea/.idea.TwitchPlaySwitch/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/contentModel.xml b/.idea/.idea.TwitchPlaySwitch/.idea/contentModel.xml new file mode 100644 index 0000000..e584520 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/contentModel.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/encodings.xml b/.idea/.idea.TwitchPlaySwitch/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/indexLayout.xml b/.idea/.idea.TwitchPlaySwitch/.idea/indexLayout.xml new file mode 100644 index 0000000..27ba142 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/modules.xml b/.idea/.idea.TwitchPlaySwitch/.idea/modules.xml new file mode 100644 index 0000000..deda272 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/projectSettingsUpdater.xml b/.idea/.idea.TwitchPlaySwitch/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..4bb9f4d --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/projectSettingsUpdater.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/.idea/workspace.xml b/.idea/.idea.TwitchPlaySwitch/.idea/workspace.xml new file mode 100644 index 0000000..0c940ef --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/.idea/workspace.xml @@ -0,0 +1,104 @@ + + + + DiscordPlaySwitch/DiscordPlaySwitch.csproj + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1600253629021 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.TwitchPlaySwitch/riderModule.iml b/.idea/.idea.TwitchPlaySwitch/riderModule.iml new file mode 100644 index 0000000..1a4e0d9 --- /dev/null +++ b/.idea/.idea.TwitchPlaySwitch/riderModule.iml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/DiscordPlaySwitch.sln b/DiscordPlaySwitch.sln new file mode 100644 index 0000000..d2a29de --- /dev/null +++ b/DiscordPlaySwitch.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30413.136 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordPlaySwitch", "DiscordPlaySwitch\DiscordPlaySwitch.csproj", "{D1112CE7-7826-4F61-9468-F20FBE186990}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysBot.Base", "SysBot.NET\SysBot.Base\SysBot.Base.csproj", "{8A67E2C6-E320-43AE-B68A-F12B6443C769}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwitchPlaySwitch", "TwitchPlaySwitch\TwitchPlaySwitch.csproj", "{92EB7C14-C59E-4415-B5B0-0831CD432BF7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D1112CE7-7826-4F61-9468-F20FBE186990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1112CE7-7826-4F61-9468-F20FBE186990}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1112CE7-7826-4F61-9468-F20FBE186990}.Debug|x64.ActiveCfg = Debug|x64 + {D1112CE7-7826-4F61-9468-F20FBE186990}.Debug|x64.Build.0 = Debug|x64 + {D1112CE7-7826-4F61-9468-F20FBE186990}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1112CE7-7826-4F61-9468-F20FBE186990}.Release|Any CPU.Build.0 = Release|Any CPU + {D1112CE7-7826-4F61-9468-F20FBE186990}.Release|x64.ActiveCfg = Release|x64 + {D1112CE7-7826-4F61-9468-F20FBE186990}.Release|x64.Build.0 = Release|x64 + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Debug|x64.ActiveCfg = Debug|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Debug|x64.Build.0 = Debug|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Release|Any CPU.Build.0 = Release|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Release|x64.ActiveCfg = Release|Any CPU + {8A67E2C6-E320-43AE-B68A-F12B6443C769}.Release|x64.Build.0 = Release|Any CPU + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Debug|x64.ActiveCfg = Debug|x64 + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Debug|x64.Build.0 = Debug|x64 + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Release|Any CPU.Build.0 = Release|Any CPU + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Release|x64.ActiveCfg = Release|x64 + {92EB7C14-C59E-4415-B5B0-0831CD432BF7}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FD16F689-9F69-4462-A639-C85753141DF0} + EndGlobalSection +EndGlobal diff --git a/DiscordPlaySwitch/DiscordPlaySwitch.csproj b/DiscordPlaySwitch/DiscordPlaySwitch.csproj new file mode 100644 index 0000000..1f87421 --- /dev/null +++ b/DiscordPlaySwitch/DiscordPlaySwitch.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.1 + AnyCPU;x64 + DiscordPlaySwitch + + + + + + + + + + diff --git a/DiscordPlaySwitch/Program.cs b/DiscordPlaySwitch/Program.cs new file mode 100644 index 0000000..9ada1e2 --- /dev/null +++ b/DiscordPlaySwitch/Program.cs @@ -0,0 +1,343 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Discord; +using Discord.WebSocket; +using Newtonsoft.Json.Linq; +using SysBot.Base; + +namespace DiscordPlaySwitch +{ + class Program + { + private DiscordSocketClient _client; + private SwitchConnectionAsync _connection; + + private static readonly JObject Config = JObject.Parse(File.ReadAllText("config.json")); + private readonly JObject _nSwitch = JObject.Parse(Config.GetValue("nSwitch").ToString()); + + private readonly string[] _control = + { + "DLEFT", "DRIGHT", "DUP", "DDOWN", "A", "B", "X", "Y", "+", "-", "ZL", "ZR", "L", "R", "LSP", "RSP", "LSU", + "LSUR", "LSUL", "LSDR", "LSDL", "LSD", "LSL", "LSR", "RSU", "RSD", "RSL", "RSR", "SCREENSHOT" + }; + + private readonly string _prefix = ((string) Config.GetValue("prefix")).ToUpper(); + + public static void Main(string[] args) + => new Program().MainAsync().GetAwaiter().GetResult(); + + private async Task MainAsync() + { + _client = new DiscordSocketClient(); + + _client.Log += Log; + + await _client.LoginAsync(TokenType.Bot, (string) Config.GetValue("token")); + await _client.StartAsync(); + + _client.Ready += () => + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("=================================================================================="); + Console.WriteLine($"Connected to discord as {_client.CurrentUser.Username}#{_client.CurrentUser.DiscriminatorValue} ({_client.CurrentUser.Id})"); + Console.WriteLine($"Discord bot prefix is set as: {_prefix}"); + Console.WriteLine("Attempting to connect to the Nintendo switch"); + try + { + _connection = new SwitchConnectionAsync((string) _nSwitch.GetValue("IP"), + int.Parse((string) _nSwitch.GetValue("sysbotPORT"))); + _connection.Connect(); + } + catch (Exception e) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(e); + Console.ResetColor(); + } + + + if (_connection.Connected) + { + Console.WriteLine($"Connected to nintendo switch on {_connection.IP}:{_connection.Port}!"); + Console.WriteLine($"Say \"{_prefix}exit\" in discord to quit the application!"); + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Failed to connect to the console!"); + Console.WriteLine("Press any key to exit the app."); + Console.ResetColor(); + Console.ReadKey(); + Environment.Exit(1); + } + + Console.WriteLine("=================================================================================="); + Console.ResetColor(); + return Task.CompletedTask; + }; + + _client.MessageReceived += async message => + { + if (message.Author.IsBot) return; + if (message.Author.Id == 595703186816499772) return; + + if (_connection.Connected) + if (message.Content.Length > _prefix.Length) + await HandleInput(message); + }; + + await Task.Delay(-1); + } + + private async Task HandleInput(SocketMessage message) + { + string msg = message.Content; + string args = msg.ToUpper().Substring(_prefix.Length, msg.Length - _prefix.Length); + string[] words = args.Split(' '); + + if (msg.ToUpper().StartsWith(_prefix)) + { + switch (args) + { + case "HELP": + await message.Channel.SendMessageAsync( + $"You can input one of those command and they will execute on my nintendo switch ( please don't destroy it ):\n{string.Join(" ", _control)}"); + break; + case "EXIT GAME": + { + break; + + if (message.Author.Id == 267065637183029248) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.HOME), + cancellationToken.Token); + cancellationToken.Cancel(); + Thread.Sleep(500); + cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.X), + cancellationToken.Token); + cancellationToken.Cancel(); + Thread.Sleep(500); + cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.A), + cancellationToken.Token); + cancellationToken.Cancel(); + + Console.WriteLine("Game exited"); + await message.Channel.SendMessageAsync("Game exited"); + } + else + { + await message.Channel.SendMessageAsync("Only for supositware"); + } + break; + } + case "EXIT": + { + break; + + if (message.Author.Id == 267065637183029248) + { + _connection.Disconnect(); + Console.WriteLine("Bye bye!"); + await message.Channel.SendMessageAsync("Bye bye!"); + Environment.Exit(1); + } + else + { + await message.Channel.SendMessageAsync("Only for supositware"); + } + break; + } + case "SCREENSHOT": + SendScreenshot(message); + break; + } + + + if (_control.Any(args.Contains)) + { + short speed = short.MaxValue; + + if (args.Contains("SLOWER")) + { + speed = 8000; + //i++; + } + else if (args.Contains("SLOW")) + { + speed = 10000; + //i++; + } + else if (args.Contains("MEDIUM")) + { + speed = 16382; + //i++; + } + + foreach (var word in words) + { + if (Array.Exists(_control, e => e == word)) + { + switch (word) + { + case "DLEFT": + PressButton(SwitchButton.DLEFT); + break; + case "DRIGHT": + PressButton(SwitchButton.DRIGHT); + break; + case "DUP": + PressButton(SwitchButton.DUP); + break; + case "DDOWN": + PressButton(SwitchButton.DDOWN); + break; + case "A": + PressButton(SwitchButton.A); + break; + case "B": + PressButton(SwitchButton.B); + break; + case "X": + PressButton(SwitchButton.X); + break; + case "Y": + PressButton(SwitchButton.Y); + break; + case "+": + PressButton(SwitchButton.PLUS); + break; + case "-": + PressButton(SwitchButton.MINUS); + break; + case "ZL": + PressButton(SwitchButton.ZL); + break; + case "ZR": + PressButton(SwitchButton.ZR); + break; + case "L": + PressButton(SwitchButton.L); + break; + case "R": + PressButton(SwitchButton.R); + break; + case "LSP": + PressButton(SwitchButton.LSTICK); + break; + case "RSP": + PressButton(SwitchButton.RSTICK); + break; + case "LSU": + MoveStick(SwitchStick.LEFT, 0, speed); + break; + case "LSUL": + MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), speed); + break; + case "LSUR": + MoveStick(SwitchStick.LEFT, speed, speed); + break; + case "LSD": + MoveStick(SwitchStick.LEFT, 0, short.Parse((speed * -1).ToString())); + break; + case "LSDL": + MoveStick(SwitchStick.LEFT, speed, short.Parse((speed * -1).ToString())); + break; + case "LSDR": + MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), short.Parse((speed * -1).ToString())); + break; + case "LSL": + MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), 0); + break; + case "LSR": + MoveStick(SwitchStick.LEFT, speed, 0); + break; + case "RSU": + MoveStick(SwitchStick.RIGHT, 0, speed); + break; + case "RSD": + MoveStick(SwitchStick.RIGHT, 0, short.Parse((speed * -1).ToString())); + break; + case "RSL": + MoveStick(SwitchStick.RIGHT, short.Parse((speed * -1).ToString()), 0); + break; + case "RSR": + MoveStick(SwitchStick.RIGHT, speed, 0); + break; + } + + SendScreenshot(message); + } + } + } + } + } + + private Task Log(LogMessage msg) + { + Console.WriteLine(msg.ToString()); + return Task.CompletedTask; + } + + private async void PressButton(SwitchButton button) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + + if (button == SwitchButton.ZL || button == SwitchButton.ZR) + { + await _connection.SendAsync(SwitchCommand.Hold(button), cancellationToken.Token); + Thread.Sleep(2000); + //SendScreenshot(message); + await _connection.SendAsync(SwitchCommand.Release(button), cancellationToken.Token); + } + else + { + await _connection.SendAsync(SwitchCommand.Click(button), cancellationToken.Token); + //SendScreenshot(message); + } + + + cancellationToken.Cancel(); + } + + + private async void MoveStick(SwitchStick stick, short x, short y) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + + await _connection.SendAsync(SwitchCommand.SetStick(stick, x, y), cancellationToken.Token); + + Thread.Sleep(stick == SwitchStick.RIGHT ? 500 : 1000); + + await _connection.SendAsync(SwitchCommand.ResetStick(stick), cancellationToken.Token); + //SendScreenshot(message); + + cancellationToken.Cancel(); + } + + private void SendScreenshot(SocketMessage message) + { + using (Process pProcess = new Process()) + { + pProcess.StartInfo.FileName = "ffmpeg"; + pProcess.StartInfo.Arguments = + $"-hide_banner -loglevel panic -y -i rtsp://{(string) _nSwitch.GetValue("IP")}:{(string) _nSwitch.GetValue("sysDVRPORT")} -vframes 1 NintendoSwitch.jpg"; //argument + //pProcess.StartInfo.Arguments = $"-hide_banner -loglevel panic -y -i rtsp://127.0.0.1:6666 -vframes 1 NintendoSwitch.jpg"; //argument + pProcess.StartInfo.UseShellExecute = false; + pProcess.StartInfo.RedirectStandardOutput = true; + pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; + pProcess.StartInfo.CreateNoWindow = true; //not diplay a windows + pProcess.Start(); + pProcess.WaitForExit(); + } + + message.Channel.SendFileAsync("NintendoSwitch.jpg"); + } + } +} \ No newline at end of file diff --git a/SwitchPlaysLayout.png b/SwitchPlaysLayout.png new file mode 100644 index 0000000..64429eb Binary files /dev/null and b/SwitchPlaysLayout.png differ diff --git a/SwitchPlaysLayout.xcf b/SwitchPlaysLayout.xcf new file mode 100644 index 0000000..a267e4e Binary files /dev/null and b/SwitchPlaysLayout.xcf differ diff --git a/SysBot.NET b/SysBot.NET new file mode 160000 index 0000000..5ea3cb4 --- /dev/null +++ b/SysBot.NET @@ -0,0 +1 @@ +Subproject commit 5ea3cb47cf64d5a4420337c94d59219c9f1187b5 diff --git a/TwitchPlaySwitch/Program.cs b/TwitchPlaySwitch/Program.cs new file mode 100644 index 0000000..1438c07 --- /dev/null +++ b/TwitchPlaySwitch/Program.cs @@ -0,0 +1,668 @@ +using System; +using System.Collections; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using TwitchLib.Client; +using TwitchLib.Client.Events; +using TwitchLib.Client.Models; +using TwitchLib.Communication.Clients; +using TwitchLib.Communication.Models; + +using Newtonsoft.Json.Linq; +using SysBot.Base; +using TwitchLib.Api; +using User = TwitchLib.Api.V5.Models.Users.User; + +namespace TwitchPlaySwitch +{ + class Program + { + private static SwitchConnectionAsync _connection; + + private static readonly Queue StickQueue = new Queue(); + private static readonly Queue ButtonQueue = new Queue(); + + private static bool _broadcasterOnly = false; + + private class StickMovement + { + public SwitchStick Stick; + public short X = -1; + public short Y = -1; + public int Hold = 1000; + } + + private static readonly JObject Config = JObject.Parse(File.ReadAllText("config.json")); + private static readonly JObject NSwitch = JObject.Parse(Config.GetValue("nSwitch").ToString()); + + private static readonly string[] Stick = + { + "LSU", "LSUR", "LSUL", "LSDR", "LSDL", "LSD", "LSL", "LSR", "RSU", "RSD", "RSL", "RSR" + }; + + private static readonly string[] Button = + { + "DLEFT", "DRIGHT", "DUP", "DDOWN", "A", "B", "X", "Y", "+", "-", "ZL", "ZR", "L", "R", "LSP", "RSP" + }; + + private static void Log(string msg, ConsoleColor color = default) + { + string log = $"{DateTime.Now}: {msg}"; + + if (!Directory.Exists("logs")) + { + Directory.CreateDirectory("logs"); + } + + File.AppendAllText($"logs/{Convert.ToDateTime(DateTime.Today).ToString("dd.MM.yy")}.txt", + log + Environment.NewLine); + + Console.ForegroundColor = color; + Console.WriteLine(log); + Console.ResetColor(); + } + + private class WebhookContent + { + public string username = "Twitch Chat"; + public string content; + public string avatar_url = "https://brand.twitch.tv/assets/logos/svg/glitch/purple.svg"; + } + + private static async Task SendWebhook(WebhookContent content) + { + if (_broadcasterOnly) return; + + string json = JsonConvert.SerializeObject(content); + StringContent data = new StringContent(json, Encoding.UTF8, "application/json"); + + var url = (string) Config.GetValue("DiscordWebhook"); + var client = new HttpClient(); + + await client.PostAsync(url, data); + client.Dispose(); + } + + private static void ConnectSwitch(string ip, int port = 6000) + { + _connection = new SwitchConnectionAsync(ip, port); + _connection.Connect(); + + if (_connection.Connected) + { + Log($"Connected to nintendo switch on {_connection.IP}:{_connection.Port}!", ConsoleColor.Green); + Log($"Say \"exit\" in twitch or press any key to quit the application!", ConsoleColor.Green); + } + } + + public static void Main() + { + Log( + $@"{Environment.NewLine} _____ _ _ _ ____ _ ____ _ _ _ +|_ ___ _(_| |_ ___| |__ | _ \| | __ _ _ _ ___/ _____ _(_| |_ ___| |__ + | | \ \ /\ / | | __/ __| '_ \| |_) | |/ _` | | | / __\___ \ \ /\ / | | __/ __| '_ \ + | | \ V V /| | || (__| | | | __/| | (_| | |_| \__ \___) \ V V /| | || (__| | | | + |_| \_/\_/ |_|\__\___|_| |_|_| |_|\__,_|\__, |___|____/ \_/\_/ |_|\__\___|_| |_| + |___/", ConsoleColor.Green); + + ConnectSwitch((string) NSwitch.GetValue("IP")); + + Bot bot = new Bot(); + Console.ReadLine(); + } + + class Bot + { + TwitchClient _client; + TwitchAPI api; + + + public Bot() + { + api = new TwitchAPI(); + + api.Settings.ClientId = (string) Config.GetValue("ClientID"); + api.Settings.AccessToken = (string) Config.GetValue("AccessToken"); + + ConnectionCredentials credentials = + new ConnectionCredentials((string) Config.GetValue("username"), (string) Config.GetValue("OAuth")); + var clientOptions = new ClientOptions + { + MessagesAllowedInPeriod = 750, + ThrottlingPeriod = TimeSpan.FromSeconds(30) + }; + WebSocketClient customClient = new WebSocketClient(clientOptions); + + _client = new TwitchClient(customClient); + _client.Initialize(credentials, (string) Config.GetValue("username")); + + _client.OnLog += Client_OnLog; + _client.OnMessageReceived += Client_OnMessageReceived; + _client.OnConnected += Client_OnConnected; + + _client.Connect(); + } + + private void Client_OnLog(object sender, OnLogArgs e) + { + Log($"{e.BotUsername} - {e.Data}"); + } + + private void Client_OnConnected(object sender, OnConnectedArgs e) + { + Log($"Connected to {e.AutoJoinChannel}", ConsoleColor.Green); + } + + private async void Client_OnMessageReceived(object sender, OnMessageReceivedArgs e) + { + User user = await api.V5.Users.GetUserByIDAsync(e.ChatMessage.UserId); + WebhookContent webhookContent = new WebhookContent(); + + if (user.CreatedAt > DateTime.Now.AddDays(-7)) + { + Log($"User {e.ChatMessage.DisplayName} account is too new: {user.CreatedAt}", ConsoleColor.DarkRed); + _client.SendMessage(e.ChatMessage.Channel, "Your account is too new... Wait a little more..."); + + webhookContent.username = "!WARNING!"; + webhookContent.avatar_url = "https://upload.wikimedia.org/wikipedia/en/thumb/1/15/Ambox_warning_pn.svg/1178px-Ambox_warning_pn.svg.png"; + webhookContent.content = $"User `{e.ChatMessage.DisplayName}` account is too new... Created at: `{user.CreatedAt}`"; + + + SendWebhook(webhookContent); + } + else if (_broadcasterOnly && !e.ChatMessage.IsBroadcaster) + _client.SendMessage(e.ChatMessage.Channel, "Bot is in Broadcaster only mode."); + else + HandleInput(e, _client); + + webhookContent.username = e.ChatMessage.DisplayName; + webhookContent.avatar_url = user.Logo; + webhookContent.content = e.ChatMessage.Message; + + SendWebhook(webhookContent); + } + } + + private static async Task HandleInput(OnMessageReceivedArgs message, TwitchClient client) + { + string msg = message.ChatMessage.Message; + string args = msg.ToUpper(); + string[] words = args.Split(' '); + + switch (args) + { + case "HELP": + client.SendMessage(message.ChatMessage.Channel, "You get to control the Nintendo Switch!"); + client.SendMessage(message.ChatMessage.Channel, "You can say any of the following and they will execute on the console! They can also be chained together"); + client.SendMessage(message.ChatMessage.Channel, $"{string.Join(" ", Button)} {string.Join(" ", Stick)}"); + client.SendMessage(message.ChatMessage.Channel, "You can specify \"slower\", \"slow\" or \"medium\" to control the speed of the joystick"); + client.SendMessage(message.ChatMessage.Channel, "You can also add \"short\" or \"long\" to control the duration of how long the joystick is held"); + return; + case "EXIT GAME": + { + if (message.ChatMessage.IsBroadcaster) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.HOME), + cancellationToken.Token); + cancellationToken.Cancel(); + Thread.Sleep(500); + cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.X), + cancellationToken.Token); + cancellationToken.Cancel(); + Thread.Sleep(500); + cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.A), + cancellationToken.Token); + cancellationToken.Cancel(); + + Log("Game exited", ConsoleColor.Red); + client.SendMessage(message.ChatMessage.Channel, "Game exited"); + } + else + { + client.SendMessage(message.ChatMessage.Channel, + "Command only available for the broadcaster."); + } + + break; + } + case "EXIT": + { + if (message.ChatMessage.IsBroadcaster) + { + _connection.Disconnect(); + Log("Bye bye!", ConsoleColor.Red); + client.SendMessage(message.ChatMessage.Channel, "Bye bye!"); + Environment.Exit(1); + } + else + { + client.SendMessage(message.ChatMessage.Channel, + "Command only available for the broadcaster."); + } + + break; + } + case "RESTART": + { + if (message.ChatMessage.IsBroadcaster) + { + _connection.Disconnect(); + Log("Restarting!!!", ConsoleColor.DarkRed); + client.SendMessage(message.ChatMessage.Channel, "Restarting"); + + ConnectSwitch((string) NSwitch.GetValue("IP")); + } + else + { + client.SendMessage(message.ChatMessage.Channel, + "Command only available for the broadcaster."); + } + + break; + } + case "HOME": + { + if (message.ChatMessage.IsBroadcaster) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + await _connection.SendAsync(SwitchCommand.Click(SwitchButton.HOME), + cancellationToken.Token); + cancellationToken.Cancel(); + } + else + { + client.SendMessage(message.ChatMessage.Channel, + "Command only available for the broadcaster."); + } + + break; + } + case "BROADCASTERONLY": + if (message.ChatMessage.IsBroadcaster) + { + if (_broadcasterOnly) + { + _broadcasterOnly = false; + Log($"BroadcasterOnly mode turned off: {_broadcasterOnly}", ConsoleColor.Green); + client.SendMessage(message.ChatMessage.Channel, + "Bot is no longer in Broadcaster only mode."); + } + else + { + _broadcasterOnly = true; + Log($"BroadcasterOnly mode turned on: {_broadcasterOnly}", ConsoleColor.Red); + client.SendMessage(message.ChatMessage.Channel, "Bot is now in Broadcaster only mode."); + } + } + else + { + client.SendMessage(message.ChatMessage.Channel, + "Command only available for the broadcaster."); + } + + break; + } + + if (Stick.Any(args.Contains)) + { + short speed = short.MaxValue; + int hold = 1000; + + if (args.Contains("SLOWER")) + { + speed = 8000; + //speed = 10000; + } + else if (args.Contains("SLOW")) + { + speed = 10000; + //speed = 16382; + } + else if (args.Contains("MEDIUM")) + { + speed = 16382; + //speed = 20000; + } + + if (args.Contains("SHORT")) + { + hold = 500; + } + else if (args.Contains("LONG")) + { + hold = 5000; + } + + foreach (var word in words) + { + if (Array.Exists(Stick, e => e == word)) + { + short x = 0; + short y = 0; + + SwitchStick stick; + StickMovement stickMovement = new StickMovement {Hold = hold}; + + Log($"{message.ChatMessage.DisplayName} moved stick {word}", ConsoleColor.Green); + + switch (word) + { + case "LSU": + stick = SwitchStick.LEFT; + x = 0; + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, 0, speed); + break; + case "LSUL": + stick = SwitchStick.LEFT; + x = short.Parse((speed * -1).ToString()); + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), speed); + break; + case "LSUR": + stick = SwitchStick.LEFT; + x = speed; + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, speed, speed); + break; + case "LSD": + stick = SwitchStick.LEFT; + x = 0; + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, 0, short.Parse((speed * -1).ToString())); + break; + case "LSDL": + stick = SwitchStick.LEFT; + x = short.Parse((speed * -1).ToString()); + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), short.Parse((speed * -1).ToString())); + break; + case "LSDR": + stick = SwitchStick.LEFT; + x = speed; + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, speed, short.Parse((speed * -1).ToString())); + break; + case "LSL": + stick = SwitchStick.LEFT; + x = short.Parse((speed * -1).ToString()); + y = 0; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, short.Parse((speed * -1).ToString()), 0); + break; + case "LSR": + stick = SwitchStick.LEFT; + x = speed; + y = 0; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.LEFT, speed, 0); + break; + case "RSU": + stick = SwitchStick.RIGHT; + x = 0; + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, 0, speed); + break; + case "RSD": + stick = SwitchStick.RIGHT; + x = 0; + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, 0, short.Parse((speed * -1).ToString())); + break; + case "RSL": + stick = SwitchStick.RIGHT; + x = short.Parse((speed * -1).ToString()); + y = 0; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, short.Parse((speed * -1).ToString()), 0); + break; + case "RSR": + stick = SwitchStick.RIGHT; + x = speed; + y = 0; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, speed, 0); + break; + case "RSUL": + stick = SwitchStick.RIGHT; + x = short.Parse((speed * -1).ToString()); + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, short.Parse((speed * -1).ToString()), speed); + break; + case "RSUR": + stick = SwitchStick.RIGHT; + x = speed; + y = speed; + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, speed, speed); + break; + case "RSDL": + stick = SwitchStick.RIGHT; + x = short.Parse((speed * -1).ToString()); + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, short.Parse((speed * -1).ToString()), short.Parse((speed * -1).ToString())); + break; + case "RSDR": + stick = SwitchStick.RIGHT; + x = speed; + y = short.Parse((speed * -1).ToString()); + + stickMovement.Stick = stick; + stickMovement.X = x; + stickMovement.Y = y; + //MoveStick(SwitchStick.RIGHT, speed, short.Parse((speed * -1).ToString())); + break; + } + + Log("QUEUED", ConsoleColor.Yellow); + StickQueue.Enqueue(stickMovement); + } + } + + + foreach (StickMovement stick in StickQueue) + { + Log($"Moving {stick.Stick} stick x: {stick.X} y: {stick.Y} hold: {stick.Hold}", ConsoleColor.Red); + await MoveStick(stick.Stick, stick.X, stick.Y, stick.Hold); + } + + StickQueue.Clear(); + } + + if (Button.Any(args.Contains)) + { + foreach (var word in words) + { + if (Array.Exists(Button, e => e == word)) + { + SwitchButton button = SwitchButton.CAPTURE; // Capture button is never used, let's use it as a "null" value + + Log($"{message.ChatMessage.DisplayName} Pressed button {word}", ConsoleColor.Green); + + switch (word) + { + case "DLEFT": + button = SwitchButton.DLEFT; + //PressButton(SwitchButton.DLEFT); + break; + case "DRIGHT": + button = SwitchButton.DRIGHT; + //PressButton(SwitchButton.DRIGHT); + break; + case "DUP": + button = SwitchButton.DUP; + //PressButton(SwitchButton.DUP); + break; + case "DDOWN": + button = SwitchButton.DDOWN; + //PressButton(SwitchButton.DDOWN); + break; + case "A": + button = SwitchButton.A; + //PressButton(SwitchButton.A); + break; + case "B": + button = SwitchButton.B; + //PressButton(SwitchButton.B); + break; + case "X": + button = SwitchButton.X; + //PressButton(SwitchButton.X); + break; + case "Y": + button = SwitchButton.Y; + //PressButton(SwitchButton.Y); + break; + case "+": + button = SwitchButton.PLUS; + //PressButton(SwitchButton.PLUS); + break; + case "-": + button = SwitchButton.MINUS; + //PressButton(SwitchButton.MINUS); + break; + case "ZL": + button = SwitchButton.ZL; + //PressButton(SwitchButton.ZL); + break; + case "ZR": + button = SwitchButton.ZR; + //PressButton(SwitchButton.ZR); + break; + case "L": + button = SwitchButton.L; + //PressButton(SwitchButton.L); + break; + case "R": + button = SwitchButton.R; + //PressButton(SwitchButton.R); + break; + case "LSP": + button = SwitchButton.LSTICK; + //PressButton(SwitchButton.LSTICK); + break; + case "RSP": + button = SwitchButton.RSTICK; + //PressButton(SwitchButton.RSTICK); + break; + } + + Log("QUEUED", ConsoleColor.Yellow); + + if (button != SwitchButton.CAPTURE + ) // Capture button is never used, let's use it as a "null" value + ButtonQueue.Enqueue(button); + } + } + + foreach (SwitchButton button in ButtonQueue) + { + Log($"Pressed {button}", ConsoleColor.Red); + await PressButton(button); + } + + ButtonQueue.Clear(); + } + } + + private static async Task PressButton(SwitchButton button) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + + if (button == SwitchButton.ZL || button == SwitchButton.ZR) + { + await _connection.SendAsync(SwitchCommand.Hold(button), cancellationToken.Token); + Thread.Sleep(2000); + await _connection.SendAsync(SwitchCommand.Release(button), cancellationToken.Token); + } + else + { + await _connection.SendAsync(SwitchCommand.Click(button), cancellationToken.Token); + } + + Thread.Sleep(500); + + + cancellationToken.Cancel(); + //StickQueue.Clear(); + } + + private static async Task MoveStick(SwitchStick stick, short x, short y, int hold) + { + CancellationTokenSource cancellationToken = new CancellationTokenSource(); + + await _connection.SendAsync(SwitchCommand.SetStick(stick, x, y), cancellationToken.Token); + + //.Sleep(stick == SwitchStick.RIGHT ? 500 : 1000); + Thread.Sleep(hold); + + await _connection.SendAsync(SwitchCommand.ResetStick(stick), cancellationToken.Token); + + cancellationToken.Cancel(); + //ButtonQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/TwitchPlaySwitch/TwitchPlaySwitch.csproj b/TwitchPlaySwitch/TwitchPlaySwitch.csproj new file mode 100644 index 0000000..545bf78 --- /dev/null +++ b/TwitchPlaySwitch/TwitchPlaySwitch.csproj @@ -0,0 +1,18 @@ + + + + Exe + netcoreapp3.1 + AnyCPU;x64 + TwitchPlaySwitch + + + + + + + + + + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..5beefd0 --- /dev/null +++ b/readme.md @@ -0,0 +1,61 @@ +# DiscordPlaysSwitch/TwitchPlaysSwitch + +My attempt at making TwitchPlays type of thing with homebrew on my nintendo switch. + +I'm not responsible for any ban that may happen to your account or console! + +NOTE: I learned C# as i was doing this, therefore the code might not be of high quality + +## Thing required + +* [A non-ipatched switch](https://gbatemp.net/threads/switch-informations-by-serial-number-read-the-first-post-before-asking-questions.481215/) with [Atmosphere cfw](https://github.com/Atmosphere-NX/Atmosphere/) and [sys-botbase](https://github.com/olliz0r/sys-botbase) +* [SysBot.NET](https://github.com/kwsch/SysBot.NET) ( Included as a submodule in this repo ) +* [SysDVR](https://github.com/exelix11/SysDVR/) ( Only for DiscordPlaysSwitch ) +* [ffmpeg](https://ffmpeg.org/) ( Only for DiscordPlaysSwitch ) +* [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) ( If playing a game that use local play like pokémon sword/shield ) + +**Don't forget to clone the submodule too!** + +## DiscordPlaysSwitch + +Currently DiscordPlaysSwitch also require SysDVR but it could be easily modified to use something else like a capture card. + +This version might not be up-to-date compared to TwitchPlaysSwitch. + +### config.json example + +```json +{ + "token": "Discord bot token", + "prefix": "Discord bot prefix ", + "nSwitch": { + "IP": "Nintendo switch IP", + "sysbotPORT": "6000", + "sysDVRPORT": "6666" + } +} +``` + +## TwitchPlaysSwitch + +The capture is obviously done via another software so no change needed whether you use a capture card or sys-DVR. + +### config.json example + +```json +{ + "username": "Twitch username", + "OAuth": "Twitch OAuth token", + "ClientID": "Twitch Client ID", + "AccessToken": "Twitch Access Token", + "DiscordWebhook": "Discord webhook to send messages to", + "nSwitch": { + "IP": "Nintendo Switch IP", + "sysbotPORT": "6000" + } +} +``` + +Thanks to [Jetbrains](https://www.jetbrains.com/?from=Hahayesdiscordbot) for providing their IDE free of charges! + +