Files
MCLEClient/Minecraft.Client/Windows64/Windows64_Launcher.cpp
T
2026-06-06 13:20:49 -04:00

748 lines
22 KiB
C++

#include "stdafx.h"
#include "Windows64_Launcher.h"
#include "Xbox/resource.h"
#include "../Minecraft.World/Dimension.h"
#include "../Minecraft.h"
#include "../MultiplayerLocalPlayer.h"
#include "Network/WinsockNetLayer.h"
#include <shlobj.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <regex>
#include <windows.h>
#include <shellapi.h>
#include <winhttp.h>
#include <commdlg.h>
#include "./ExtraLibs/discordsdk/discord.h"
float g_sleepPercentage = 100;
int g_autosaveInterval = 120;
std::string g_discordUserId = "";
bool g_doBoatBreak = true;
discord::Core* g_discordCore = nullptr;
DWORD WINAPI DiscordCallbackThreadFunc(LPVOID lpParam) {
auto result = discord::Core::Create(1424889204110004316LL, DiscordCreateFlags_NoRequireDiscord, &g_discordCore);
if (result != discord::Result::Ok || !g_discordCore) {
return 1;
}
while (true) {
g_discordCore->RunCallbacks();
Sleep(100);
}
return 0;
}
DWORD WINAPI DiscordRPCThreadFunc(LPVOID lpParam) {
while (!g_discordCore) {
Sleep(100);
}
discord::Activity activity{};
activity.GetTimestamps().SetStart(time(0));
static std::string detailsStr = "Playing as " + Windows64Launcher::GetUsername();
activity.SetDetails(detailsStr.c_str());
activity.GetAssets().SetLargeImage("MCLE");
activity.GetAssets().SetLargeText("MCLE");
g_discordCore->ActivityManager().UpdateActivity(activity, [](discord::Result r) {});
while (true) {
Minecraft* minecraft = Minecraft::GetInstance();
if (minecraft && minecraft->player) {
discord::Activity updatedActivity{};
updatedActivity.SetDetails(detailsStr.c_str());
switch (minecraft->player->dimension) {
case -1:
updatedActivity.GetAssets().SetSmallImage("nether");
updatedActivity.GetAssets().SetSmallText("In The Nether");
break;
case 0:
updatedActivity.GetAssets().SetSmallImage("overworld");
updatedActivity.GetAssets().SetSmallText("In The Overworld");
break;
case 1:
updatedActivity.GetAssets().SetSmallImage("end");
updatedActivity.GetAssets().SetSmallText("In The End");
break;
}
g_discordCore->ActivityManager().UpdateActivity(updatedActivity, [](discord::Result r) {});
}
Sleep(2000);
}
return 0;
}
static ATOM RegisterLauncherClass(HINSTANCE hInstance);
static BOOL InitWindow(HINSTANCE hInstance);
HWND launcher_HWND = NULL;
bool shouldContinue = true;
HWND hBottomBar;
HWND hStatusText;
HWND hBtnOffline;
HWND hBtnLaunch;
HWND hBtnLogout;
HWND hBtnDiscord;
HWND hBtnDiscordLogin;
HWND hBtnRegister;
HWND hBtnLogin;
HWND hUsernameLabel;
HWND hUsernameEdit;
HWND hPasswordLabel;
HWND hPasswordEdit;
HWND hLoginUsernameLabel;
std::string username = "";
std::string authenticationToken = "";
bool startedCallbackThread = false;
bool startedRPCThread = false;
bool offlinemode = false;
bool Windows64Launcher::IsInOfflineMode() { return offlinemode; }
void onSuccessfulLogin();
void onAccountLogout();
void onLoginFailed();
void AttemptFullLoginFlow();
const std::string& Windows64Launcher::GetAuthenticationToken() {
return authenticationToken;
}
const std::string& Windows64Launcher::GetUsername() {
return username;
}
void Windows64Launcher::CreateLauncherWindow(HINSTANCE hInstance, std::function<void()> onLaunch) {
RegisterLauncherClass(hInstance);
InitWindow(hInstance);
onLoginFailed(); //call this to disable login element during socket connection
AttemptFullLoginFlow();
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Now launcher is closed -> continue
if (shouldContinue == false && onLaunch)
onLaunch();
}
void AttemptFullLoginFlow() {
if (Windows64Launcher::GetAuthenticationData(authenticationToken, username)) {
int responseState = Windows64Launcher::API_GetAccountInfo(authenticationToken);
if (responseState == 0) {
onSuccessfulLogin();
}
else {
onLoginFailed();
MessageBoxW(launcher_HWND, L"Unable To Connect To Saved Account", L"Login Failed", MB_OK);
}
}
else {
onLoginFailed();
}
}
void onSuccessfulLogin() {
SetWindowText(hPasswordEdit, "");
SetWindowText(hLoginUsernameLabel, std::string("Welcome: " + username).c_str());
ShowWindow(hBtnLaunch, SW_SHOW);
ShowWindow(hBtnOffline, SW_SHOW);
ShowWindow(hBtnLogout, SW_SHOW);
ShowWindow(hLoginUsernameLabel, SW_SHOW);
ShowWindow(hUsernameLabel, SW_HIDE);
ShowWindow(hUsernameEdit, SW_HIDE);
ShowWindow(hPasswordLabel, SW_HIDE);
ShowWindow(hPasswordEdit, SW_HIDE);
ShowWindow(hBtnRegister, SW_HIDE);
ShowWindow(hBtnLogin, SW_HIDE);
ShowWindow(hBtnDiscordLogin, SW_HIDE);
if (!startedRPCThread) {
HANDLE hThread = CreateThread(NULL, 0, DiscordRPCThreadFunc, NULL, 0, NULL);
CloseHandle(hThread);
startedRPCThread = true;
}
}
void onAccountLogout() {
Windows64Launcher::SaveAuthenticationData("", username);
ShowWindow(hBtnLaunch, SW_HIDE);
ShowWindow(hBtnOffline, SW_HIDE);
ShowWindow(hBtnLogout, SW_HIDE);
ShowWindow(hLoginUsernameLabel, SW_HIDE);
ShowWindow(hUsernameLabel, SW_SHOW);
ShowWindow(hUsernameEdit, SW_SHOW);
ShowWindow(hPasswordLabel, SW_SHOW);
ShowWindow(hPasswordEdit, SW_SHOW);
ShowWindow(hBtnRegister, SW_SHOW);
ShowWindow(hBtnLogin, SW_SHOW);
ShowWindow(hBtnDiscordLogin, SW_SHOW);
}
void onLoginFailed() {
ShowWindow(hBtnLaunch, SW_HIDE);
ShowWindow(hBtnOffline, SW_HIDE);
ShowWindow(hBtnLogout, SW_HIDE);
ShowWindow(hLoginUsernameLabel, SW_HIDE);
ShowWindow(hUsernameLabel, SW_SHOW);
ShowWindow(hUsernameEdit, SW_SHOW);
ShowWindow(hPasswordLabel, SW_SHOW);
ShowWindow(hPasswordEdit, SW_SHOW);
ShowWindow(hBtnRegister, SW_SHOW);
ShowWindow(hBtnLogin, SW_SHOW);
}
LRESULT OnWindowCreation(HWND hWnd) {
if (!startedCallbackThread) {
HANDLE hThread = CreateThread(NULL, 0, DiscordCallbackThreadFunc, NULL, 0, NULL);
CloseHandle(hThread);
startedCallbackThread = true;
}
hBottomBar = CreateWindowW(L"STATIC", nullptr, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, nullptr, nullptr, nullptr);
hStatusText = CreateWindowW(L"STATIC", L"Version: " L"" LAUNCHER_VERSION, WS_CHILD | WS_VISIBLE, 10, 10, 200, 20, hBottomBar, nullptr, nullptr, nullptr);
hBtnLaunch = CreateWindowW(L"BUTTON", L"Launch", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 80, 25, hWnd, (HMENU)1, nullptr, nullptr);
hBtnOffline = CreateWindowW(L"BUTTON", L"Play Offline", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)2, nullptr, nullptr);
hBtnRegister = CreateWindowW(L"BUTTON", L"Register", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 80, 25, hWnd, (HMENU)3, nullptr, nullptr);
hBtnLogin = CreateWindowW(L"BUTTON", L"Login", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)4, nullptr, nullptr);
hBtnLogout = CreateWindowW(L"BUTTON", L"Logout", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)5, nullptr, nullptr);
hBtnDiscord = CreateWindowW(L"BUTTON", L"Discord", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)6, nullptr, nullptr);
hBtnDiscordLogin = CreateWindowW(L"BUTTON", L"Discord Login", WS_CHILD | WS_VISIBLE, 0, 0, 80, 25, hWnd, (HMENU)7, nullptr, nullptr);
hUsernameLabel = CreateWindowW(L"STATIC", L"Username:", WS_CHILD | WS_VISIBLE, 0, 0, 80, 20, hWnd, nullptr, nullptr, nullptr);
hUsernameEdit = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 0, 0, 180, 25, hWnd, nullptr, nullptr, nullptr);
hPasswordLabel = CreateWindowW(L"STATIC", L"Password:", WS_CHILD | WS_VISIBLE, 0, 0, 80, 20, hWnd, nullptr, nullptr, nullptr);
hPasswordEdit = CreateWindowW(L"EDIT", L"", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_PASSWORD, 0, 0, 180, 25, hWnd, nullptr, nullptr, nullptr);
hLoginUsernameLabel = CreateWindowW(L"STATIC", L"Welcome: Placeholder", WS_CHILD | WS_VISIBLE, 0, 0, 300, 20, hWnd, nullptr, nullptr, nullptr);
return 0;
}
LRESULT OnWindowSize(int width, int height) {
int inputWidth = 180;
int inputHeight = 25;
int labelWidth = 80;
int centerX = width / 2 - inputWidth / 2;
int startY = 40;
MoveWindow(hLoginUsernameLabel, 0, 0, 300, 20, TRUE);
MoveWindow(hBtnLogout, 0, 30, labelWidth, 20, TRUE);
MoveWindow(hBtnDiscord, centerX, 125, labelWidth, 20, TRUE);
MoveWindow(hBtnDiscord, centerX - 5, 125, 75, 20, TRUE);
MoveWindow(hBtnDiscordLogin, centerX + 75, 125, 95, 20, TRUE);
// Username
MoveWindow(hUsernameLabel, centerX - labelWidth + 50, startY - 5, labelWidth, 20, TRUE);
MoveWindow(hUsernameEdit, centerX + 50, startY - 8, inputWidth, inputHeight, TRUE);
// Password
MoveWindow(hPasswordLabel, centerX - labelWidth + 50, startY + 40, labelWidth, 20, TRUE);
MoveWindow(hPasswordEdit, centerX + 50, startY + 37, inputWidth, inputHeight, TRUE);
int barHeight = 50;
// Position bottom bar
MoveWindow(hBottomBar, 0, height - barHeight, width, barHeight, TRUE);
int padding = 10;
int buttonWidth = 80;
int buttonHeight = 25;
int barTop = height - barHeight;
int buttonY = barTop + (barHeight - buttonHeight) / 2;
MoveWindow(hBtnLaunch, width - padding - buttonWidth, buttonY, buttonWidth, buttonHeight, TRUE);
MoveWindow(hBtnLogin, width - padding - buttonWidth, buttonY, buttonWidth, buttonHeight, TRUE);
MoveWindow(hBtnRegister, width - padding * 2 - buttonWidth * 2, buttonY, buttonWidth, buttonHeight, TRUE);
MoveWindow(hBtnOffline, width - padding * 2 - buttonWidth * 2, buttonY, buttonWidth, buttonHeight, TRUE);
MoveWindow(hStatusText, padding, (barHeight - 20) / 2, 300, 20, TRUE);
return 0;
}
bool isValidUsername(const std::string& str) {
std::regex pattern("^[A-Za-z0-9]+$");
return std::regex_match(str, pattern);
}
bool IsValidPassword(const std::string& password) {
std::regex pattern("^[A-Za-z0-9%$#@&]+$");
return std::regex_match(password, pattern);
}
LRESULT OnAccountRegister() {
char username_buf[16];
char password_buf[32];
GetWindowText(hUsernameEdit, username_buf, 16);
GetWindowText(hPasswordEdit, password_buf, 32);
if (!isValidUsername(username_buf)) {
MessageBoxW(launcher_HWND, L"A Username Can Only Consist Of Letters And Numbers", L"Registration Failed", MB_OK);
return 0;
}
if (!IsValidPassword(password_buf)) {
MessageBoxW(launcher_HWND, L"A Password Can Only Consist Of Letters And Numbers And %$#@&", L"Registration Failed", MB_OK);
return 0;
}
int registerResponse = Windows64Launcher::API_AttemptAccountRegister(username_buf, password_buf, authenticationToken);
if (registerResponse == 0) { //success
Windows64Launcher::SaveAuthenticationData(authenticationToken, username);
AttemptFullLoginFlow();
}
else if (registerResponse == 20000) {
MessageBoxW(launcher_HWND, L"Failed to Connect To Server", L"Registration Failed", MB_OK);
}
else if (registerResponse == 20500) {
MessageBoxW(launcher_HWND, L"Failed to Connect To Server", L"Registration Failed", MB_OK);
}
else if (registerResponse == 2222) {
MessageBoxW(launcher_HWND, L"Invalid Username Characters", L"Registration Failed", MB_OK);
}
else if (registerResponse == 2233) {
MessageBoxW(launcher_HWND, L"Invalid Password Characters", L"Registration Failed", MB_OK);
}
else if (registerResponse == 3333) {
MessageBoxW(launcher_HWND, L"Username Taken", L"Registration Failed", MB_OK);
}
else if (registerResponse == 5555) {
MessageBoxW(launcher_HWND, L"VPN's Are Not Allowed", L"Registration Failed", MB_OK);
}
else if (registerResponse == 6666) {
MessageBoxW(launcher_HWND, L"Too many accounts from this IP", L"Registration Failed", MB_OK);
}
else if (registerResponse == 7777) {
MessageBoxW(launcher_HWND, L"Username Contains Banned Word", L"Registration Failed", MB_OK);
}
else if (registerResponse == 8888) {
MessageBoxW(launcher_HWND, L"Username Is Banned", L"Registration Failed", MB_OK);
}
else { //unknown error, we will setup internal codes and have them logged here
MessageBoxW(launcher_HWND, std::wstring(L"Unknown Error: " + std::to_wstring(registerResponse)).c_str(), L"Registration Failed", MB_OK);
}
return 0;
}
LRESULT OnAccountLogin() {
char username_buf[16];
char password_buf[32];
GetWindowText(hUsernameEdit, username_buf, 16);
GetWindowText(hPasswordEdit, password_buf, 32);
if (!isValidUsername(username_buf)) {
MessageBoxW(launcher_HWND, L"A Username Can Only Consist Of Letters And Numbers", L"Login Failed", MB_OK);
return 0;
}
if (!IsValidPassword(password_buf)) {
MessageBoxW(launcher_HWND, L"A Password Can Only Consist Of Letters And Numbers And %$#@&", L"Login Failed", MB_OK);
return 0;
}
int registerResponse = Windows64Launcher::API_AttemptAccountLogin(username_buf, password_buf, authenticationToken);
if (registerResponse == 0) { //success
Windows64Launcher::SaveAuthenticationData(authenticationToken, username);
AttemptFullLoginFlow();
}
else if (registerResponse == 1111 || registerResponse == 2222) { //invalid details
MessageBoxW(launcher_HWND, L"Invalid Username / Password", L"Login Failed", MB_OK);
}
else if (registerResponse == 2) { //Banned
MessageBoxW(launcher_HWND, L"You Have Been Banned", L"Login Failed", MB_OK);
}
else { //unknown error, we will setup internal codes and have them logged here
//MessageBoxW(launcher_HWND, std::wstring(L"Unknown Error: " + std::to_wstring(registerResponse)).c_str(), L"Registration Failed", MB_OK);
MessageBoxW(launcher_HWND, (L"Failed to Connect To Server: " + std::to_wstring(registerResponse)).c_str(), L"Login Failed", MB_OK);
}
return 0;
}
LRESULT OnDiscordLogin() {
if (!g_discordCore) {
MessageBoxW(launcher_HWND, L"Discord is not running.", L"Discord Login", MB_OK);
return 0;
}
g_discordCore->ApplicationManager().GetOAuth2Token([](discord::Result res, discord::OAuth2Token const& token) {
if (res != discord::Result::Ok) {
PostMessageA(launcher_HWND, WM_APP + 2, 0, 0);
return;
}
std::string t = token.GetAccessToken();
PostMessageA(launcher_HWND, WM_APP + 1, 0, (LPARAM)new std::string(t));
});
return 0;
}
LRESULT OnCommandReceived(HWND hWnd, int type) {
switch (type) {
case 1: // Launch
shouldContinue = false;
offlinemode = false;
DestroyWindow(hWnd);
break;
case 2: // Offline
shouldContinue = false;
offlinemode = true;
DestroyWindow(hWnd);
break;
case 3: // Register
OnAccountRegister();
break;
case 4: // Login
OnAccountLogin();
break;
case 5: //Logout
onAccountLogout();
break;
case 6: //Discord
ShellExecute(0, 0, "https://discord.gg/xjc9JW4Bfp", 0, 0, SW_SHOW);
break;
case 7: //Discord Login
OnDiscordLogin();
break;
}
return 0;
}
LRESULT CALLBACK WndProc_Launcher(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_APP + 1: { // Discord token received — on main thread
std::string* token = reinterpret_cast<std::string*>(lParam);
int response = Windows64Launcher::API_AttemptDiscordLogin(*token, authenticationToken);
delete token;
if (response == 0) {
Windows64Launcher::SaveAuthenticationData(authenticationToken, username);
AttemptFullLoginFlow();
}
else if (response == 1111) {
MessageBoxW(launcher_HWND, L"Invalid Username / Password", L"Login Failed", MB_OK);
}
else if (response == 2222) {
MessageBoxW(launcher_HWND, L"You Have Been Banned", L"Login Failed", MB_OK);
}
else if (response == 3333) {
MessageBoxW(launcher_HWND, L"Invalid OAuth token", L"Discord Login", MB_OK);
}
else if (response == 4444) {
MessageBoxW(launcher_HWND, L"Discord isnt linked to any account", L"Discord Login", MB_OK);
}
else {
MessageBoxW(launcher_HWND, std::wstring(L"Unknown Error: " + std::to_wstring(response)).c_str(), L"Discord Login", MB_OK);
}
return 0;
}
case WM_APP + 2:
MessageBoxW(hWnd, L"Failed to get Discord token.\nMake sure Discord is open.", L"Discord Login", MB_OK);
return 0;
case WM_COMMAND:
return OnCommandReceived(hWnd, LOWORD(wParam));
case WM_SIZE:
return OnWindowSize(LOWORD(lParam), HIWORD(lParam));
case WM_CREATE:
return OnWindowCreation(hWnd);
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
static ATOM RegisterLauncherClass(HINSTANCE hInstance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc_Launcher;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, "Minecraft");
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = "Legacy Launcher";
wcex.lpszClassName = "LCELauncherClass";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MINECRAFTWINDOWS));
return RegisterClassEx(&wcex);
}
static BOOL InitWindow(HINSTANCE hInstance) {
RECT wr = { 0, 0, 300, 200 }; // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
launcher_HWND = CreateWindow("LCELauncherClass",
"Legacy Launcher",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
wr.right - wr.left, // width of the window
wr.bottom - wr.top, // height of the window
NULL,
NULL,
hInstance,
NULL);
if (!launcher_HWND) {
return FALSE;
}
ShowWindow(launcher_HWND, true);
UpdateWindow(launcher_HWND);
return TRUE;
}
std::string GetOrCreateLauncherFolder() {
char path[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path);
std::string folder = path;
folder += "\\LegacyLauncher";
CreateDirectoryA(folder.c_str(), NULL);
return folder;
}
bool loadedDedicated = false;
void Windows64Launcher::SaveAuthenticationData(const std::string& token, const std::string& username) {
if (loadedDedicated) return;
std::string folder = GetOrCreateLauncherFolder();
std::string file = folder + "\\AccountToken_DoNotShare.dat";
std::string data = token + "\n" + username;
std::ofstream out(file, std::ios::trunc);
out << data;
out.close();
}
bool Windows64Launcher::GetAuthenticationData(std::string& tokenOut, std::string& usernameOut, bool dedicated)
{
std::ifstream in;
if (dedicated) {
wchar_t exePath[MAX_PATH] = {};
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
if (lastSlash)
*(lastSlash + 1) = L'\0';
wchar_t filePath[MAX_PATH] = {};
_snwprintf_s(filePath, MAX_PATH, _TRUNCATE, L"%sWindows64\\AccountToken_DoNotShare.dat", exePath);
in.open(filePath);
loadedDedicated = true;
}
if (!in.is_open()) {
std::string folder = GetOrCreateLauncherFolder();
std::string file = folder + "\\AccountToken_DoNotShare.dat";
in.open(file);
}
if (!in.is_open())
return false;
std::getline(in, tokenOut);
std::getline(in, usernameOut);
in.close();
if (tokenOut.empty())
return false;
return true;
}
bool Windows64Launcher::GetAuthenticationDataAndLoad(bool dedicated) {
return Windows64Launcher::GetAuthenticationData(authenticationToken, username, dedicated);
}
std::vector<std::string> split(const std::string& str, char delimiter) {
std::vector<std::string> result;
size_t start = 0;
size_t end = 0;
while ((end = str.find(delimiter, start)) != std::string::npos) {
result.push_back(str.substr(start, end - start));
start = end + 1;
}
// Add the last substring
result.push_back(str.substr(start));
return result;
}
int Windows64Launcher::API_GetAccountInfo(const std::string token) {
std::vector<std::wstring> headers;
headers.push_back(L"Content-Type: text/plain");
HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/accountinfo", L"POST", token, headers);
if (response.status == 0) return -1;
if (response.status != 200) return (20000 + response.status);
if (response.body.find('-') == std::string::npos) return stoi(response.body);
username = response.body.erase(0, 1);
return 0;
}
int Windows64Launcher::API_AttemptAccountRegister(const std::string _username, const std::string password, std::string& tokenOut) {
std::vector<std::wstring> headers;
headers.push_back(L"Content-Type: text/plain");
std::string data = _username + ":" + password;
HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/register", L"POST", data, headers);
if (response.status != 200) return (20000 + response.status);
if (response.body.find('-') == std::string::npos) return stoi(response.body);
std::vector<std::string> splitData = split(response.body.erase(0, 1), ':');
username = splitData[0];
authenticationToken = splitData[1];
return 0;
}
int Windows64Launcher::API_AttemptAccountLogin(const std::string _username, const std::string password, std::string& tokenOut)
{
std::vector<std::wstring> headers;
headers.push_back(L"Content-Type: text/plain");
std::string data = _username + ":" + password;
HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/login", L"POST", data, headers);
if (response.status != 200) return (20000 + response.status);
if (response.body.find('-') == std::string::npos) return stoi(response.body);
std::vector<std::string> splitData = split(response.body.erase(0, 1), ':');
username = splitData[0];
authenticationToken = splitData[1];
return 0;
}
int Windows64Launcher::API_AttemptDiscordLogin(const std::string& ticket, std::string& tokenOut) {
std::vector<std::wstring> headers;
headers.push_back(L"Content-Type: text/plain");
HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/discordlogin", L"POST", ticket, headers);
if (response.status == 0) return -1;
if (response.status != 200) return (20000 + response.status);
if (response.body.find('-') == std::string::npos) return stoi(response.body);
std::string body = response.body.erase(0, 1);
size_t colonPos = body.find(':');
if (colonPos == std::string::npos) return -2;
username = body.substr(0, colonPos);
authenticationToken = body.substr(colonPos + 1);
tokenOut = authenticationToken;
return 0;
}
static std::string ExtractJsonString(const std::string& json, const std::string& key) {
std::string search = "\"" + key + "\"";
size_t pos = json.find(search);
if (pos == std::string::npos) return "";
pos = json.find("\"", pos + search.length() + 1);
if (pos == std::string::npos) return "";
pos++;
size_t end = json.find("\"", pos);
if (end == std::string::npos) return "";
return json.substr(pos, end - pos);
}
extern Minecraft* minecraft;