From 9795b96e8f6383853d6e4e0f27d22f417f443797 Mon Sep 17 00:00:00 2001 From: str1k3r <115313679+S1l3ntStr1ke87@users.noreply.github.com> Date: Wed, 27 May 2026 08:21:56 -0400 Subject: [PATCH] Feat: Allow Launching from launchers --- .../Windows64/Network/WinsockNetLayer.cpp | 94 +++++++++++++--- .../Windows64/Windows64_Minecraft.cpp | 100 ++++++++++++++---- .../Windows64/Windows64_Minecraft.h | 18 ++++ 3 files changed, 180 insertions(+), 32 deletions(-) create mode 100644 Minecraft.Client/Windows64/Windows64_Minecraft.h diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp index 2e07f4ff..7f2c80f2 100644 --- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp +++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp @@ -16,6 +16,7 @@ #include "./../../Minecraft.Server/Windows64/ServerAuth.h" #else #include "../Windows64_Launcher.h" +#include "../Windows64_Minecraft.h" #endif #include "../../../Minecraft.World/DisconnectPacket.h" @@ -93,7 +94,7 @@ char g_Win64RelayServerIP[256] = "relay.mclegacyedition.xyz"; wchar_t g_Win64RelayServerIP_Wide[256] = L"relay.mclegacyedition.xyz"; wchar_t g_Win64AuthIP[256] = L"auth.mclegacyedition.xyz"; int g_Win64RelayServerPort = 2052; -char g_GameVersion[9] = "TU19"; +char g_GameVersion[] = "TU19"; bool WinsockNetLayer::Initialize() { @@ -243,7 +244,12 @@ bool WinsockNetLayer::HostGame(int port, const char* bindIp) { #if defined(MINECRAFT_SERVER_BUILD) #else - if (Windows64Launcher::IsInOfflineMode()) return true; + if (Windows64Minecraft::IsExternalLauncher()) { + if (Windows64Minecraft::IsOfflineMode()) return true; + } + else { + if (Windows64Launcher::IsInOfflineMode()) return true; + } #endif if (!s_initialized && !Initialize()) return false; @@ -303,7 +309,13 @@ bool WinsockNetLayer::HostGame(int port, const char* bindIp) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string isDedicatedServer = (g_Win64DedicatedServer ? "1" : "0"); std::string req = "HOST " + authToken + " " + isDedicatedServer + "\n"; @@ -322,7 +334,12 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port) { #if defined(MINECRAFT_SERVER_BUILD) #else - if (Windows64Launcher::IsInOfflineMode()) return true; + if (Windows64Minecraft::IsExternalLauncher()) { + if (Windows64Minecraft::IsOfflineMode()) return true; + } + else { + if (Windows64Launcher::IsInOfflineMode()) return true; + } #endif if (!s_initialized && !Initialize()) return false; @@ -388,7 +405,13 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string hostname(ip); std::string req = "JOIN " + authToken + " 0 " + hostname + " 0\n"; @@ -441,7 +464,12 @@ bool WinsockNetLayer::BeginJoinGame(const char* ip, int port) { #if defined(MINECRAFT_SERVER_BUILD) #else - if (Windows64Launcher::IsInOfflineMode()) return true; + if (Windows64Minecraft::IsExternalLauncher()) { + if (Windows64Minecraft::IsOfflineMode()) return true; + } + else { + if (Windows64Launcher::IsInOfflineMode()) return true; + } #endif if (!s_initialized && !Initialize()) return false; @@ -548,7 +576,13 @@ DWORD WINAPI WinsockNetLayer::JoinThreadProc(LPVOID param) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string hostname(s_joinIP); std::string req = "JOIN " + authToken + " 0 " + hostname + " 0\n"; @@ -847,7 +881,13 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string isDedicatedServer = (g_Win64DedicatedServer ? "1" : "0"); std::string acc = "ACCEPT " + authToken + " " + isDedicatedServer + " " + clientId + "\n"; @@ -1207,7 +1247,13 @@ bool WinsockNetLayer::JoinSplitScreen(int padIndex, BYTE* outSmallId) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string hostname(g_Win64MultiplayerIP); std::string req = "JOIN " + authToken + " 0 " + hostname + " 1\n"; @@ -1364,7 +1410,12 @@ bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t* hostName, un { #if defined(MINECRAFT_SERVER_BUILD) #else - if (Windows64Launcher::IsInOfflineMode()) return true; + if (Windows64Minecraft::IsExternalLauncher()) { + if (Windows64Minecraft::IsOfflineMode()) return true; + } + else { + if (Windows64Launcher::IsInOfflineMode()) return true; + } #endif if (s_advertising) return true; if (!s_initialized) return false; @@ -1477,7 +1528,13 @@ DWORD WINAPI WinsockNetLayer::AdvertiseThreadProc(LPVOID param) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string isDedicatedServer = (g_Win64DedicatedServer ? "1" : "0"); std::string req = "ADVERTISE " + authToken + " " + isDedicatedServer; @@ -1504,7 +1561,12 @@ bool WinsockNetLayer::StartDiscovery() { #if defined(MINECRAFT_SERVER_BUILD) #else - if (Windows64Launcher::IsInOfflineMode()) return true; + if (Windows64Minecraft::IsExternalLauncher()) { + if (Windows64Minecraft::IsOfflineMode()) return true; + } + else { + if (Windows64Launcher::IsInOfflineMode()) return true; + } #endif if (s_discovering) return true; if (!s_initialized) return false; @@ -1591,7 +1653,13 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param) #if defined(MINECRAFT_SERVER_BUILD) std::string authToken = ServerAuth::GetAuthenticationToken(); #else - std::string authToken = Windows64Launcher::GetAuthenticationToken(); + std::string authToken; + if (Windows64Minecraft::IsExternalLauncher()) { + authToken = Windows64Minecraft::GetAuthenticationTicket(); + } + else { + authToken = Windows64Launcher::GetAuthenticationToken(); + } #endif std::string req = "LIST " + authToken + " 0 dedicated " + g_GameVersion + "\n"; send(sock, req.c_str(), (int)req.length(), 0); diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index 8dfb9658..3b52b1f0 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -57,6 +57,7 @@ extern Renderer InternalRenderManager; #include "Xbox/Resource.h" +#include "Windows64_Minecraft.h" #include "Windows64_Launcher.h" // request use of dedicated GPU from AMD and Nvidia drivers @@ -125,16 +126,50 @@ static bool g_bResizeReady = false; char g_Win64Username[17] = { 0 }; wchar_t g_Win64UsernameW[17] = { 0 }; +char g_Win64SessionTicket[256]; + +bool s_externalLauncher = false; + +bool isOfflineMode = false; + +bool Windows64Minecraft::IsOfflineMode() { + return isOfflineMode; +} + +bool Windows64Minecraft::IsExternalLauncher() { + return s_externalLauncher; +} + +std::string Windows64Minecraft::GetAuthenticationTicket() { + return g_Win64SessionTicket; +} + +static bool FetchSessionInfo() { + std::vector headers; + headers.push_back(L"Content-Type: text/plain"); + + HttpResponse response = WinsockNetLayer::DoWinHttpRequest(L"/getAccountInfo", L"POST", Windows64Minecraft::GetAuthenticationTicket(), headers); + + if (response.status == 0) return false; + + if (response.status != 200) return false; + + if (response.body.empty() || response.body[0] != '-') return false; + std::string payload = response.body.substr(1); + //std::vector splitData = split(payload, '|'); + + strncpy_s(g_Win64Username, sizeof(g_Win64Username), payload.c_str(), _TRUNCATE); + MultiByteToWideChar(CP_UTF8, 0, g_Win64Username, -1, g_Win64UsernameW, sizeof(g_Win64UsernameW) / sizeof(wchar_t)); + + //WideCharToMultiByte(CP_ACP, 0, g_Win64UsernameW, -1, g_Win64Username, static_cast(sizeof(g_Win64Username)), nullptr, nullptr); + + return true; +} + // Fullscreen toggle state static bool g_isFullscreen = false; static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) }; -struct Win64LaunchOptions -{ - int screenMode; - bool fullscreen; -}; - static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize) { if (destSize == 0) @@ -213,14 +248,13 @@ static void ApplyScreenMode(int screenMode) } } +using Win64LaunchOptions = Windows64Minecraft::Win64LaunchOptions; + static Win64LaunchOptions ParseLaunchOptions() { Win64LaunchOptions options = {}; options.screenMode = 0; - g_Win64MultiplayerJoin = false; - g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT; - int argc = 0; LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == nullptr) @@ -238,6 +272,21 @@ static Win64LaunchOptions ParseLaunchOptions() options.fullscreen = true; } + for (int i = 1; i < argc; ++i) + { + if (_wcsicmp(argv[i], L"-username") == 0 && (i + 1) < argc) { + CopyWideArgToAnsi(argv[++i], g_Win64Username, sizeof(g_Win64Username)); + options.username = true; + } + else if (_wcsicmp(argv[i], L"-token") == 0 && (i + 1) < argc) { + CopyWideArgToAnsi(argv[++i], g_Win64SessionTicket, sizeof(g_Win64SessionTicket)); + options.token = true; + } + else if (_wcsicmp(argv[i], L"-offline") == 0) { + isOfflineMode = true; + } + } + LocalFree(argv); return options; } @@ -1289,10 +1338,7 @@ static Minecraft* InitialiseMinecraftRuntime() void StartGame(Win64LaunchOptions launchOptions, int nCmdShow); -int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPTSTR lpCmdLine, - _In_ int nCmdShow) +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); @@ -1300,29 +1346,45 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, // 4J-Win64: set CWD to exe dir so asset paths resolve correctly { char szExeDir[MAX_PATH] = {}; - GetModuleFileNameA(NULL, szExeDir, MAX_PATH); - char *pSlash = strrchr(szExeDir, '\\'); + GetModuleFileNameA(nullptr, szExeDir, MAX_PATH); + char* pSlash = strrchr(szExeDir, '\\'); if (pSlash) { *(pSlash + 1) = '\0'; SetCurrentDirectoryA(szExeDir); } } - // Declare DPI awareness so GetSystemMetrics returns physical pixels SetProcessDPIAware(); g_iScreenWidth = GetSystemMetrics(SM_CXSCREEN); g_iScreenHeight = GetSystemMetrics(SM_CYSCREEN); + g_rScreenWidth = g_iScreenWidth; + g_rScreenHeight = g_iScreenHeight; - // Load stuff from launch options, including username Win64LaunchOptions launchOptions = ParseLaunchOptions(); ApplyScreenMode(launchOptions.screenMode); hMyInst = hInstance; + // If -token was passed by an external launcher then skip the internal launcher + // or if -offline was passed then skip auth + if (launchOptions.token) + { + // External launcher path: resolve session info and go straight to game + s_externalLauncher = true; + MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17); + FetchSessionInfo(); + StartGame(launchOptions, nCmdShow); + } + else if (Windows64Minecraft::IsOfflineMode()) { + MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17); + StartGame(launchOptions, nCmdShow); + } + else + { Windows64Launcher::CreateLauncherWindow(hInstance, [launchOptions, nCmdShow]() { const char* username = Windows64Launcher::GetUsername().c_str(); strncpy_s(g_Win64Username, sizeof(g_Win64Username), username, _TRUNCATE); MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17); - StartGame(launchOptions, nCmdShow); - }); + }); + } return 0; } diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.h b/Minecraft.Client/Windows64/Windows64_Minecraft.h new file mode 100644 index 00000000..d70c2dac --- /dev/null +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class Windows64Minecraft { +public: + static bool IsOfflineMode(); + static std::string GetAuthenticationTicket(); + static bool IsExternalLauncher(); + + struct Win64LaunchOptions + { + int screenMode; + bool fullscreen; + bool username; + bool token; + }; +}; \ No newline at end of file