From 189d784c57d2a1c64c5b0cda8c08a0bee0ca4eff Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 14 May 2024 17:46:06 +0200 Subject: [PATCH] Download all bots from the CRF Well, not from the first page in this state --- .gitignore | 3 + RC2BotArchiver.sln | 16 +++++ RC2BotArchiver/Program.cs | 97 ++++++++++++++++++++++++++++ RC2BotArchiver/RC2BotArchiver.csproj | 10 +++ 4 files changed, 126 insertions(+) create mode 100644 .gitignore create mode 100644 RC2BotArchiver.sln create mode 100644 RC2BotArchiver/Program.cs create mode 100644 RC2BotArchiver/RC2BotArchiver.csproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d6a29d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +bin +obj diff --git a/RC2BotArchiver.sln b/RC2BotArchiver.sln new file mode 100644 index 0000000..e390297 --- /dev/null +++ b/RC2BotArchiver.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RC2BotArchiver", "RC2BotArchiver\RC2BotArchiver.csproj", "{A13CAF43-53C0-4496-8C5B-CAF9E33A043E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A13CAF43-53C0-4496-8C5B-CAF9E33A043E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A13CAF43-53C0-4496-8C5B-CAF9E33A043E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A13CAF43-53C0-4496-8C5B-CAF9E33A043E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A13CAF43-53C0-4496-8C5B-CAF9E33A043E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/RC2BotArchiver/Program.cs b/RC2BotArchiver/Program.cs new file mode 100644 index 0000000..3c21374 --- /dev/null +++ b/RC2BotArchiver/Program.cs @@ -0,0 +1,97 @@ +// See https://aka.ms/new-console-template for more information + +using System.Diagnostics; +using System.Dynamic; +using System.Net; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Text.Json; + +Console.WriteLine("Hello, World!"); + +var client = new HttpClient(); + +async Task GetResponse(HttpResponseMessage result, string url) +{ + if (result.StatusCode == HttpStatusCode.OK) + { + dynamic? responseJson = await result.Content.ReadFromJsonAsync(typeof(JsonElement)); + if (responseJson is null) throw new Exception("Unexpected null response for url " + url); + return responseJson; + } + + Console.WriteLine("Status: " + result.StatusCode); + return null; +} + +async Task Post(string url, dynamic request) +{ + var result = await client.PostAsync(url, JsonContent.Create(request as object)); + return await GetResponse(result, url); +} + +async Task Get(string url) +{ + var result = await client.GetAsync(url); + return await GetResponse(result, url); +} + +dynamic payload = new ExpandoObject(); +payload.Target = "Techblox"; +JsonElement? responseJson = await Post("https://account.freejamgames.com/api/authenticate/portal/start", payload); +if (!responseJson.HasValue) throw new Exception("Failed to start authentication"); +var token = responseJson.Value.GetProperty("Token").GetString(); + +var url = $"https://account.freejamgames.com/login?theme=rc2&redirect_url=portal?theme=rc2%26portalToken={token}"; +Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); +Console.WriteLine($"Go to {url} and log in please."); + +while (true) +{ + Thread.Sleep(1000); + Console.WriteLine("Checking response..."); + payload = new ExpandoObject(); + payload.Token = token; + responseJson = await Post("https://account.freejamgames.com/api/authenticate/portal/check", payload); + if (responseJson.HasValue) + break; +} + +Console.WriteLine("Authentication successful."); +var jwt = responseJson.Value.GetProperty("Token"); + +payload = new ExpandoObject(); +payload.Token = responseJson.Value.GetProperty("Token"); +payload.ClientVersion = "100.0"; +responseJson = await Post("https://progression.production.robocraft2.com/login/fj", payload); +var progressToken = responseJson.Value.GetProperty("token").GetString(); + +client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", progressToken); + +const string factoryUrl = "https://factory.production.robocraft2.com"; + +int page = 408; +while (true) +{ + Console.WriteLine($"Getting page {page}"); + responseJson = await Get(factoryUrl + $"/v1/foundry/search?page={page++}&count=10"); + if (!responseJson.HasValue) throw new Exception("Failed to get robots!"); + var results = responseJson.Value.GetProperty("results"); + if (results.GetArrayLength() == 0) break; + foreach (var result in results.EnumerateArray()) + { + var robot = result.GetProperty("robot"); + var dirPath = Path.Combine("robots", robot.GetProperty("id").GetString()!); + Directory.CreateDirectory(dirPath); + File.WriteAllText(Path.Combine(dirPath, "metadata.json"), robot.GetRawText()); + responseJson = await Get(factoryUrl + "/v1/foundry/vehicles/" + robot.GetProperty("id")); + if (!responseJson.HasValue) throw new Exception($"Could not get bot {robot.GetProperty("name")}"); + File.WriteAllText(Path.Combine(dirPath, "robotData.json"), responseJson.Value.GetRawText()); + Console.WriteLine($"Saved {robot.GetProperty("name")} by {robot.GetProperty("creatorName")}"); + Thread.Sleep(100); + } + Thread.Sleep(1000); +} + +// TODO: Get local saves +// TODO: Save robot images diff --git a/RC2BotArchiver/RC2BotArchiver.csproj b/RC2BotArchiver/RC2BotArchiver.csproj new file mode 100644 index 0000000..2f4fc77 --- /dev/null +++ b/RC2BotArchiver/RC2BotArchiver.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + +