diff --git a/Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.cpp b/Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.cpp index 33be0fdf..c5731705 100644 --- a/Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.cpp @@ -15,6 +15,8 @@ // Windows64 DLC store stuff blahhhh - whisper #ifdef _WINDOWS64 #include "Windows64_DLCOffers.h" +#include "..\..\User.h" +#include "Windows64_Minecraft.h" #include static std::unordered_map s_offerIndexToListPos; #endif @@ -166,10 +168,12 @@ void UIScene_DLCOffersMenu::handleInput(int iPad, int key, bool repeat, bool pre int iIndex = getControlChildFocus(); if (iIndex >= 0 && iIndex < Windows64_DLCOffers::Get().GetOfferCount()) { + Minecraft *pMinecraft = Minecraft::GetInstance(); + Windows64_DLCOffers::Get().InstallOffer(iIndex, [](const wchar_t* id, bool ok, void*) { wprintf(L"[DLC] Install %ls: %ls\n", id, ok ? L"OK" : L"FAILED"); - }, nullptr); + }, nullptr, pMinecraft->user->name.c_str()); } } #endif @@ -249,9 +253,9 @@ void UIScene_DLCOffersMenu::handlePress(F64 controlId, F64 childId) iIndex < Windows64_DLCOffers::Get().GetOfferCount()) { Windows64_DLCOffers::Get().InstallOffer(iIndex, - [](const wchar_t* id, bool ok, void*) { - wprintf(L"[DLC] Install %ls: %ls\n", id, ok ? L"OK" : L"FAILED"); - }, nullptr); + [](const wchar_t* id, bool ok, void*) { + wprintf(L"[DLC] Install %ls: %ls\n", id, ok ? L"OK" : L"FAILED"); + }, nullptr, Minecraft::GetInstance()->user->name.c_str()); } #else diff --git a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp index f03ca9c3..0876586e 100644 --- a/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MainMenu.cpp @@ -116,6 +116,8 @@ UIScene_MainMenu::UIScene_MainMenu(int iPad, void *initData, UILayer *parentLaye // Fix for #45154 - Frontend: DLC: Content can only be downloaded from the frontend if you have not joined/exited multiplayer XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); #endif + + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); } UIScene_MainMenu::~UIScene_MainMenu() diff --git a/Minecraft.Client/Windows64_DLCOffers.cpp b/Minecraft.Client/Windows64_DLCOffers.cpp index 386fbefa..93477e8b 100644 --- a/Minecraft.Client/Windows64_DLCOffers.cpp +++ b/Minecraft.Client/Windows64_DLCOffers.cpp @@ -4,456 +4,482 @@ #include #pragma comment(lib, "winhttp.lib") #include +#include "../Windows64_Minecraft.h" +#include "../User.h" static bool ParseUrl(const wchar_t* url, - std::wstring& host, INTERNET_PORT& port, - std::wstring& path) + std::wstring& host, INTERNET_PORT& port, + std::wstring& path) { - URL_COMPONENTS uc = {}; - uc.dwStructSize = sizeof(uc); - uc.dwHostNameLength = (DWORD)-1; - uc.dwUrlPathLength = (DWORD)-1; - uc.dwExtraInfoLength = (DWORD)-1; - if (!WinHttpCrackUrl(url, 0, 0, &uc)) return false; - host.assign(uc.lpszHostName, uc.dwHostNameLength); - path.assign(uc.lpszUrlPath, uc.dwUrlPathLength); - if (uc.lpszExtraInfo && uc.dwExtraInfoLength) - path.append(uc.lpszExtraInfo, uc.dwExtraInfoLength); - port = uc.nPort; - return true; + URL_COMPONENTS uc = {}; + uc.dwStructSize = sizeof(uc); + uc.dwHostNameLength = (DWORD)-1; + uc.dwUrlPathLength = (DWORD)-1; + uc.dwExtraInfoLength = (DWORD)-1; + if (!WinHttpCrackUrl(url, 0, 0, &uc)) return false; + host.assign(uc.lpszHostName, uc.dwHostNameLength); + path.assign(uc.lpszUrlPath, uc.dwUrlPathLength); + if (uc.lpszExtraInfo && uc.dwExtraInfoLength) + path.append(uc.lpszExtraInfo, uc.dwExtraInfoLength); + port = uc.nPort; + return true; } bool Windows64_DLCOffers::FetchBytesFromUrl(const wchar_t* url, - PBYTE* ppData, DWORD* pdwSize) + PBYTE* ppData, DWORD* pdwSize) { - *ppData = nullptr; - *pdwSize = 0; + *ppData = nullptr; + *pdwSize = 0; - printf("[DLC] FetchBytesFromUrl: '%ls'\n", url); + printf("[DLC] FetchBytesFromUrl: '%ls'\n", url); - std::wstring host, path; - INTERNET_PORT port = 80; - if (!ParseUrl(url, host, port, path)) - { - printf("[DLC] FetchBytesFromUrl: ParseUrl FAILED (err=%u)\n", GetLastError()); - return false; - } + std::wstring host, path; + INTERNET_PORT port = 80; + if (!ParseUrl(url, host, port, path)) + { + printf("[DLC] FetchBytesFromUrl: ParseUrl FAILED (err=%u)\n", GetLastError()); + return false; + } - printf("[DLC] FetchBytesFromUrl: host='%ls' port=%u path='%ls'\n", - host.c_str(), (unsigned)port, path.c_str()); + printf("[DLC] FetchBytesFromUrl: host='%ls' port=%u path='%ls'\n", + host.c_str(), (unsigned)port, path.c_str()); - HINTERNET hSession = WinHttpOpen(L"W64DLC/1.0", - WINHTTP_ACCESS_TYPE_NO_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, 0); - if (!hSession) - { - printf("[DLC] FetchBytesFromUrl: WinHttpOpen FAILED (err=%u)\n", GetLastError()); - return false; - } + HINTERNET hSession = WinHttpOpen(L"W64DLC/1.0", + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, 0); + if (!hSession) + { + printf("[DLC] FetchBytesFromUrl: WinHttpOpen FAILED (err=%u)\n", GetLastError()); + return false; + } - HINTERNET hConn = WinHttpConnect(hSession, host.c_str(), port, 0); - if (!hConn) - { - printf("[DLC] FetchBytesFromUrl: WinHttpConnect FAILED (err=%u)\n", GetLastError()); - WinHttpCloseHandle(hSession); - return false; - } + HINTERNET hConn = WinHttpConnect(hSession, host.c_str(), port, 0); + if (!hConn) + { + printf("[DLC] FetchBytesFromUrl: WinHttpConnect FAILED (err=%u)\n", GetLastError()); + WinHttpCloseHandle(hSession); + return false; + } - HINTERNET hReq = WinHttpOpenRequest(hConn, L"GET", path.c_str(), - nullptr, WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, 0); - if (!hReq) - { - printf("[DLC] FetchBytesFromUrl: WinHttpOpenRequest FAILED (err=%u)\n", GetLastError()); - WinHttpCloseHandle(hConn); - WinHttpCloseHandle(hSession); - return false; - } + HINTERNET hReq = WinHttpOpenRequest(hConn, L"GET", path.c_str(), + nullptr, WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (!hReq) + { + printf("[DLC] FetchBytesFromUrl: WinHttpOpenRequest FAILED (err=%u)\n", GetLastError()); + WinHttpCloseHandle(hConn); + WinHttpCloseHandle(hSession); + return false; + } - if (!WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) - { - printf("[DLC] FetchBytesFromUrl: WinHttpSendRequest FAILED (err=%u)\n", GetLastError()); - WinHttpCloseHandle(hReq); - WinHttpCloseHandle(hConn); - WinHttpCloseHandle(hSession); - return false; - } + if (!WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) + { + printf("[DLC] FetchBytesFromUrl: WinHttpSendRequest FAILED (err=%u)\n", GetLastError()); + WinHttpCloseHandle(hReq); + WinHttpCloseHandle(hConn); + WinHttpCloseHandle(hSession); + return false; + } - if (!WinHttpReceiveResponse(hReq, nullptr)) - { - printf("[DLC] FetchBytesFromUrl: WinHttpReceiveResponse FAILED (err=%u)\n", GetLastError()); - WinHttpCloseHandle(hReq); - WinHttpCloseHandle(hConn); - WinHttpCloseHandle(hSession); - return false; - } + if (!WinHttpReceiveResponse(hReq, nullptr)) + { + printf("[DLC] FetchBytesFromUrl: WinHttpReceiveResponse FAILED (err=%u)\n", GetLastError()); + WinHttpCloseHandle(hReq); + WinHttpCloseHandle(hConn); + WinHttpCloseHandle(hSession); + return false; + } - DWORD dwStatusCode = 0; - DWORD dwStatusSize = sizeof(dwStatusCode); - WinHttpQueryHeaders(hReq, - WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &dwStatusCode, &dwStatusSize, - WINHTTP_NO_HEADER_INDEX); - printf("[DLC] FetchBytesFromUrl: HTTP status = %u\n", dwStatusCode); + DWORD dwStatusCode = 0; + DWORD dwStatusSize = sizeof(dwStatusCode); + WinHttpQueryHeaders(hReq, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &dwStatusCode, &dwStatusSize, + WINHTTP_NO_HEADER_INDEX); + printf("[DLC] FetchBytesFromUrl: HTTP status = %u\n", dwStatusCode); - if (dwStatusCode != 200) - { - printf("[DLC] FetchBytesFromUrl: non-200 response, aborting\n"); - WinHttpCloseHandle(hReq); - WinHttpCloseHandle(hConn); - WinHttpCloseHandle(hSession); - return false; - } + if (dwStatusCode != 200) + { + printf("[DLC] FetchBytesFromUrl: non-200 response, aborting\n"); + WinHttpCloseHandle(hReq); + WinHttpCloseHandle(hConn); + WinHttpCloseHandle(hSession); + return false; + } - std::vector buf; - DWORD dwRead = 0; - BYTE chunk[8192]; - while (WinHttpReadData(hReq, chunk, sizeof(chunk), &dwRead) && dwRead) - buf.insert(buf.end(), chunk, chunk + dwRead); + std::vector buf; + DWORD dwRead = 0; + BYTE chunk[8192]; + while (WinHttpReadData(hReq, chunk, sizeof(chunk), &dwRead) && dwRead) + buf.insert(buf.end(), chunk, chunk + dwRead); - printf("[DLC] FetchBytesFromUrl: read %zu bytes\n", buf.size()); + printf("[DLC] FetchBytesFromUrl: read %zu bytes\n", buf.size()); - bool bOk = false; - if (!buf.empty()) - { - *ppData = new BYTE[buf.size()]; - *pdwSize = (DWORD)buf.size(); - memcpy(*ppData, buf.data(), buf.size()); - bOk = true; - } - else - { - printf("[DLC] FetchBytesFromUrl: response body was empty\n"); - } + bool bOk = false; + if (!buf.empty()) + { + *ppData = new BYTE[buf.size()]; + *pdwSize = (DWORD)buf.size(); + memcpy(*ppData, buf.data(), buf.size()); + bOk = true; + } + else + { + printf("[DLC] FetchBytesFromUrl: response body was empty\n"); + } - WinHttpCloseHandle(hReq); - WinHttpCloseHandle(hConn); - WinHttpCloseHandle(hSession); - return bOk; + WinHttpCloseHandle(hReq); + WinHttpCloseHandle(hConn); + WinHttpCloseHandle(hSession); + return bOk; } static bool WinHttpGetUrl(const wchar_t* fullUrl, PBYTE* ppData, DWORD* pdwSize) { - *ppData = nullptr; - *pdwSize = 0; + *ppData = nullptr; + *pdwSize = 0; - URL_COMPONENTS uc; - ZeroMemory(&uc, sizeof(uc)); - uc.dwStructSize = sizeof(uc); + URL_COMPONENTS uc; + ZeroMemory(&uc, sizeof(uc)); + uc.dwStructSize = sizeof(uc); - wchar_t szHostName[256] = {}; - wchar_t szUrlPath[1024] = {}; - uc.lpszHostName = szHostName; - uc.dwHostNameLength = _countof(szHostName); - uc.lpszUrlPath = szUrlPath; - uc.dwUrlPathLength = _countof(szUrlPath); + wchar_t szHostName[256] = {}; + wchar_t szUrlPath[1024] = {}; + uc.lpszHostName = szHostName; + uc.dwHostNameLength = _countof(szHostName); + uc.lpszUrlPath = szUrlPath; + uc.dwUrlPathLength = _countof(szUrlPath); - if (!WinHttpCrackUrl(fullUrl, 0, 0, &uc)) - { - printf("[DLC] WinHttpGetUrl: WinHttpCrackUrl failed for '%ls': %u\n", fullUrl, GetLastError()); - return false; - } + if (!WinHttpCrackUrl(fullUrl, 0, 0, &uc)) + { + printf("[DLC] WinHttpGetUrl: WinHttpCrackUrl failed for '%ls': %u\n", fullUrl, GetLastError()); + return false; + } - HINTERNET hSession = WinHttpOpen(L"MC/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - if (!hSession) return false; + HINTERNET hSession = WinHttpOpen(L"MC/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + if (!hSession) return false; - HINTERNET hConnect = WinHttpConnect(hSession, szHostName, uc.nPort, 0); - if (!hConnect) { WinHttpCloseHandle(hSession); return false; } + HINTERNET hConnect = WinHttpConnect(hSession, szHostName, uc.nPort, 0); + if (!hConnect) { WinHttpCloseHandle(hSession); return false; } - HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", szUrlPath, - NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); - if (!hRequest) - { - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); - return false; - } + HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", szUrlPath, + NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (!hRequest) + { + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return false; + } - if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || - !WinHttpReceiveResponse(hRequest, NULL)) - { - WinHttpCloseHandle(hRequest); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); - return false; - } + if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || + !WinHttpReceiveResponse(hRequest, NULL)) + { + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return false; + } - std::string body; - DWORD dwSize = 0; - do { - DWORD dwDownloaded = 0; - if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize == 0) break; - char* buf = new char[dwSize]; - if (WinHttpReadData(hRequest, buf, dwSize, &dwDownloaded)) - body.append(buf, dwDownloaded); - delete[] buf; - } while (dwSize > 0); + std::string body; + DWORD dwSize = 0; + do { + DWORD dwDownloaded = 0; + if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize == 0) break; + char* buf = new char[dwSize]; + if (WinHttpReadData(hRequest, buf, dwSize, &dwDownloaded)) + body.append(buf, dwDownloaded); + delete[] buf; + } while (dwSize > 0); - WinHttpCloseHandle(hRequest); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); - if (body.empty()) return false; + if (body.empty()) return false; - *pdwSize = (DWORD)body.size(); - *ppData = new BYTE[*pdwSize]; - memcpy(*ppData, body.data(), *pdwSize); - return true; + *pdwSize = (DWORD)body.size(); + *ppData = new BYTE[*pdwSize]; + memcpy(*ppData, body.data(), *pdwSize); + return true; } bool Windows64_DLCOffers::FetchImageFromUrl(const wchar_t* url, PBYTE* ppData, DWORD* pdwSize) { - return WinHttpGetUrl(url, ppData, pdwSize); + return WinHttpGetUrl(url, ppData, pdwSize); } void Windows64_DLCOffers::InstallOffer(int iIndex, - W64_INSTALL_CALLBACK pfnCallback, - void* pUserData) + W64_INSTALL_CALLBACK pfnCallback, + void* pUserData, wstring username) { - if (iIndex < 0 || iIndex >= (int)m_offers.size()) return; + if (iIndex < 0 || iIndex >= (int)m_offers.size()) return; - InstallCtx* ctx = new InstallCtx(); - ctx->offer = m_offers[iIndex]; - ctx->offerIndex = iIndex; - ctx->pfnCallback = pfnCallback; - ctx->pUserData = pUserData; + InstallCtx* ctx = new InstallCtx(); + ctx->offer = m_offers[iIndex]; + ctx->offerIndex = iIndex; + ctx->pfnCallback = pfnCallback; + ctx->pUserData = pUserData; + ctx->username = username; - HANDLE hThread = CreateThread(nullptr, 0, InstallThreadProc, ctx, 0, nullptr); - if (hThread) CloseHandle(hThread); - else delete ctx; + HANDLE hThread = CreateThread(nullptr, 0, InstallThreadProc, ctx, 0, nullptr); + if (hThread) CloseHandle(hThread); + else delete ctx; } DWORD WINAPI Windows64_DLCOffers::InstallThreadProc(LPVOID lpParam) { - InstallCtx* ctx = reinterpret_cast(lpParam); - bool bSuccess = false; + InstallCtx* ctx = reinterpret_cast(lpParam); + bool bSuccess = false; - // \Windows64Media\DLC\\folder.pck - wchar_t wszExeDir[MAX_PATH] = {}; - GetModuleFileNameW(nullptr, wszExeDir, MAX_PATH); - wchar_t* pLastSlash = wcsrchr(wszExeDir, L'\\'); - if (pLastSlash) *(pLastSlash + 1) = L'\0'; + // \Windows64Media\DLC\\folder.pck + wchar_t wszExeDir[MAX_PATH] = {}; + GetModuleFileNameW(nullptr, wszExeDir, MAX_PATH); + wchar_t* pLastSlash = wcsrchr(wszExeDir, L'\\'); + if (pLastSlash) *(pLastSlash + 1) = L'\0'; - wchar_t wszInstallDir[MAX_PATH]; - _snwprintf_s(wszInstallDir, _countof(wszInstallDir), _TRUNCATE, - L"%lsWindows64Media\\DLC\\%ls", - wszExeDir, ctx->offer.wszProductID); + wchar_t wszInstallDir[MAX_PATH]; + _snwprintf_s(wszInstallDir, _countof(wszInstallDir), _TRUNCATE, + L"%lsWindows64Media\\DLC\\%ls", + wszExeDir, ctx->offer.wszProductID); - CreateDirectoryW(wszInstallDir, nullptr); + CreateDirectoryW(wszInstallDir, nullptr); - wchar_t wszFilePath[MAX_PATH]; - _snwprintf_s(wszFilePath, _countof(wszFilePath), _TRUNCATE, - L"%ls\\folder.pck", wszInstallDir); + wchar_t wszFilePath[MAX_PATH]; + _snwprintf_s(wszFilePath, _countof(wszFilePath), _TRUNCATE, + L"%ls\\folder.pck", wszInstallDir); - wchar_t wszDownloadUrl[512]; - _snwprintf_s(wszDownloadUrl, _countof(wszDownloadUrl), _TRUNCATE, - L"http://127.0.0.1:3000/download/%ls", ctx->offer.wszProductID); + wchar_t wszDownloadUrl[512]; + _snwprintf_s(wszDownloadUrl, _countof(wszDownloadUrl), _TRUNCATE, + L"http://127.0.0.1:3000/download/%ls", ctx->offer.wszProductID); - PBYTE pData = nullptr; - DWORD dwBytes = 0; + PBYTE pData = nullptr; + DWORD dwBytes = 0; - if (FetchBytesFromUrl(wszDownloadUrl, &pData, &dwBytes) && pData) - { - HANDLE hFile = CreateFileW(wszFilePath, GENERIC_WRITE, 0, nullptr, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile != INVALID_HANDLE_VALUE) - { - DWORD dwWritten = 0; - WriteFile(hFile, pData, dwBytes, &dwWritten, nullptr); - CloseHandle(hFile); - bSuccess = (dwWritten == dwBytes); - } - delete[] pData; - } + if (FetchBytesFromUrl(wszDownloadUrl, &pData, &dwBytes) && pData) + { + HANDLE hFile = CreateFileW(wszFilePath, GENERIC_WRITE, 0, nullptr, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwWritten = 0; + WriteFile(hFile, pData, dwBytes, &dwWritten, nullptr); + CloseHandle(hFile); + bSuccess = (dwWritten == dwBytes); + } + delete[] pData; + } - if (bSuccess) - { - // Mark the offer as owned. - Windows64_DLCOffers::Get().SetPurchased(ctx->offerIndex); + if (bSuccess) + { + Windows64_DLCOffers::Get().SetPurchased(ctx->offerIndex); + Windows64_DLCOffers::Get().SetPendingLoadPath(ctx->offerIndex, wszFilePath); + InterlockedExchange(&Windows64_DLCOffers::Get().m_iLastInstalled, (LONG)ctx->offerIndex); - // Must be set BEFORE m_iLastInstalled is updated so the game thread always - Windows64_DLCOffers::Get().SetPendingLoadPath(ctx->offerIndex, wszFilePath); - InterlockedExchange(&Windows64_DLCOffers::Get().m_iLastInstalled, - (LONG)ctx->offerIndex); + // notify server so purchase persists across sessions + wchar_t wszPath[256]; + _snwprintf_s(wszPath, _countof(wszPath), _TRUNCATE, + L"/purchase/%ls?user=%ls", + ctx->offer.wszProductID, ctx->username.c_str()); - printf("[DLC] Installed '%ls' -> %ls\n", - ctx->offer.wszProductID, wszFilePath); - } - else - { - printf("[DLC] Install FAILED for '%ls'\n", ctx->offer.wszProductID); - } + HINTERNET hSession = WinHttpOpen(L"W64DLC/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, nullptr, nullptr, 0); + if (hSession) + { + HINTERNET hConn = WinHttpConnect(hSession, L"127.0.0.1", 3000, 0); + if (hConn) + { + HINTERNET hReq = WinHttpOpenRequest(hConn, L"POST", wszPath, nullptr, + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (hReq) + { + WinHttpSendRequest(hReq, WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + WinHttpReceiveResponse(hReq, nullptr); + WinHttpCloseHandle(hReq); + } + WinHttpCloseHandle(hConn); + } + WinHttpCloseHandle(hSession); + } + } + else + { + printf("[DLC] Install FAILED for '%ls'\n", ctx->offer.wszProductID); + } - if (ctx->pfnCallback) - ctx->pfnCallback(ctx->offer.wszProductID, bSuccess, ctx->pUserData); + if (ctx->pfnCallback) + ctx->pfnCallback(ctx->offer.wszProductID, bSuccess, ctx->pUserData); - delete ctx; - return 0; + delete ctx; + return 0; } void Windows64_DLCOffers::FetchFromServer() { - printf("[DLC] FetchFromServer called\n"); - m_offers.clear(); - m_bReady = false; + printf("[DLC] FetchFromServer called\n"); + m_offers.clear(); + m_bReady = false; - HINTERNET hSession = WinHttpOpen(L"MC/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); - if (!hSession) return; + HINTERNET hSession = WinHttpOpen(L"MC/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0); + if (!hSession) return; - HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", 3000, 0); - if (!hConnect) { WinHttpCloseHandle(hSession); return; } + HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", 3000, 0); + if (!hConnect) { WinHttpCloseHandle(hSession); return; } - HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/dlc", - NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); - if (!hRequest) - { - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); - return; - } + wchar_t wszDlcPath[128]; + _snwprintf_s(wszDlcPath, _countof(wszDlcPath), _TRUNCATE, L"/dlc?user=%ls", Minecraft::GetInstance()->user->name.c_str()); - if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, - WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || - !WinHttpReceiveResponse(hRequest, NULL)) - { - WinHttpCloseHandle(hRequest); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); - return; - } +HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", wszDlcPath, + NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); + if (!hRequest) + { + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return; + } - std::string body; - DWORD dwSize = 0; - do { - DWORD dwDownloaded = 0; - if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize == 0) break; - char* buf = new char[dwSize + 1]; - ZeroMemory(buf, dwSize + 1); - if (WinHttpReadData(hRequest, buf, dwSize, &dwDownloaded)) - body.append(buf, dwDownloaded); - delete[] buf; - } while (dwSize > 0); + if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, + WINHTTP_NO_REQUEST_DATA, 0, 0, 0) || + !WinHttpReceiveResponse(hRequest, NULL)) + { + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); + return; + } - WinHttpCloseHandle(hRequest); - WinHttpCloseHandle(hConnect); - WinHttpCloseHandle(hSession); + std::string body; + DWORD dwSize = 0; + do { + DWORD dwDownloaded = 0; + if (!WinHttpQueryDataAvailable(hRequest, &dwSize) || dwSize == 0) break; + char* buf = new char[dwSize + 1]; + ZeroMemory(buf, dwSize + 1); + if (WinHttpReadData(hRequest, buf, dwSize, &dwDownloaded)) + body.append(buf, dwDownloaded); + delete[] buf; + } while (dwSize > 0); - if (body.empty()) { printf("[DLC] Empty /dlc response\n"); return; } + WinHttpCloseHandle(hRequest); + WinHttpCloseHandle(hConnect); + WinHttpCloseHandle(hSession); - printf("[DLC] /dlc response (%d bytes): %s\n", (int)body.size(), body.c_str()); + if (body.empty()) { printf("[DLC] Empty /dlc response\n"); return; } - auto toWide = [](const std::string& s, wchar_t* dst, int maxChars) { - MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, dst, maxChars); - }; + printf("[DLC] /dlc response (%d bytes): %s\n", (int)body.size(), body.c_str()); - size_t pos = 0; - while ((pos = body.find('{', pos)) != std::string::npos) - { - W64_OFFER_INFO offer; - ZeroMemory(&offer, sizeof(offer)); + auto toWide = [](const std::string& s, wchar_t* dst, int maxChars) { + MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, dst, maxChars); + }; - auto readField = [&](const char* key) -> std::string { - std::string search = std::string("\"") + key + "\""; - size_t k = body.find(search, pos); - if (k == std::string::npos) return ""; - size_t colon = body.find(':', k); - if (colon == std::string::npos) return ""; - size_t q1 = body.find('"', colon); - if (q1 == std::string::npos) return ""; - size_t q2 = body.find('"', q1 + 1); - if (q2 == std::string::npos) return ""; - return body.substr(q1 + 1, q2 - q1 - 1); - }; + size_t pos = 0; + while ((pos = body.find('{', pos)) != std::string::npos) + { + W64_OFFER_INFO offer; + ZeroMemory(&offer, sizeof(offer)); - auto readInt = [&](const char* key) -> int { - std::string search = std::string("\"") + key + "\""; - size_t k = body.find(search, pos); - if (k == std::string::npos) return 0; - size_t colon = body.find(':', k); - if (colon == std::string::npos) return 0; - size_t n = colon + 1; - while (n < body.size() && (body[n] == ' ' || body[n] == '\t')) n++; - return atoi(&body[n]); - }; + auto readField = [&](const char* key) -> std::string { + std::string search = std::string("\"") + key + "\""; + size_t k = body.find(search, pos); + if (k == std::string::npos) return ""; + size_t colon = body.find(':', k); + if (colon == std::string::npos) return ""; + size_t q1 = body.find('"', colon); + if (q1 == std::string::npos) return ""; + size_t q2 = body.find('"', q1 + 1); + if (q2 == std::string::npos) return ""; + return body.substr(q1 + 1, q2 - q1 - 1); + }; - toWide(readField("id"), offer.wszProductID, 64); - toWide(readField("name"), offer.wszOfferName, 128); - toWide(readField("description"), offer.wszSellText, 512); - toWide(readField("price"), offer.wszCurrencyPrice, 32); - toWide(readField("type"), offer.wszType, 32); - toWide(readField("bannerUrl"), offer.wszBannerUrl, 256); - offer.fUserHasPurchased = readInt("purchased"); - offer.pbBannerData = nullptr; - offer.dwBannerBytes = 0; + auto readInt = [&](const char* key) -> int { + std::string search = std::string("\"") + key + "\""; + size_t k = body.find(search, pos); + if (k == std::string::npos) return 0; + size_t colon = body.find(':', k); + if (colon == std::string::npos) return 0; + size_t n = colon + 1; + while (n < body.size() && (body[n] == ' ' || body[n] == '\t')) n++; + return atoi(&body[n]); + }; - if (offer.wszProductID[0] != L'\0') - { - printf("[DLC] Parsed: id='%ls' type='%ls' bannerUrl='%ls'\n", - offer.wszProductID, offer.wszType, offer.wszBannerUrl); - m_offers.push_back(offer); - } + toWide(readField("id"), offer.wszProductID, 64); + toWide(readField("name"), offer.wszOfferName, 128); + toWide(readField("description"), offer.wszSellText, 512); + toWide(readField("price"), offer.wszCurrencyPrice, 32); + toWide(readField("type"), offer.wszType, 32); + toWide(readField("bannerUrl"), offer.wszBannerUrl, 256); + offer.fUserHasPurchased = readInt("purchased"); + offer.pbBannerData = nullptr; + offer.dwBannerBytes = 0; - pos = body.find('}', pos); - if (pos == std::string::npos) break; - pos++; - } + if (offer.wszProductID[0] != L'\0') + { + printf("[DLC] Parsed: id='%ls' type='%ls' bannerUrl='%ls'\n", + offer.wszProductID, offer.wszType, offer.wszBannerUrl); + m_offers.push_back(offer); + } - printf("[DLC] FetchFromServer complete - %d offers\n", (int)m_offers.size()); - m_bReady = true; + pos = body.find('}', pos); + if (pos == std::string::npos) break; + pos++; + } + + printf("[DLC] FetchFromServer complete - %d offers\n", (int)m_offers.size()); + m_bReady = true; } void Windows64_DLCOffers::FetchBanners() { - for (int i = 0; i < (int)m_offers.size(); i++) - { - W64_OFFER_INFO& offer = m_offers[i]; - if (offer.wszBannerUrl[0] == L'\0') continue; - if (offer.pbBannerData != nullptr) continue; + for (int i = 0; i < (int)m_offers.size(); i++) + { + W64_OFFER_INFO& offer = m_offers[i]; + if (offer.wszBannerUrl[0] == L'\0') continue; + if (offer.pbBannerData != nullptr) continue; - PBYTE pbData = nullptr; - DWORD dwBytes = 0; + PBYTE pbData = nullptr; + DWORD dwBytes = 0; - if (FetchImageFromUrl(offer.wszBannerUrl, &pbData, &dwBytes)) - { - offer.pbBannerData = pbData; - offer.dwBannerBytes = dwBytes; - printf("[DLC] Banner fetched for '%ls' - %u bytes\n", - offer.wszProductID, dwBytes); - } - else - { - printf("[DLC] Banner fetch FAILED for '%ls' url='%ls'\n", - offer.wszProductID, offer.wszBannerUrl); - } - } + if (FetchImageFromUrl(offer.wszBannerUrl, &pbData, &dwBytes)) + { + offer.pbBannerData = pbData; + offer.dwBannerBytes = dwBytes; + printf("[DLC] Banner fetched for '%ls' - %u bytes\n", + offer.wszProductID, dwBytes); + } + else + { + printf("[DLC] Banner fetch FAILED for '%ls' url='%ls'\n", + offer.wszProductID, offer.wszBannerUrl); + } + } - // Register all offers with the app now that banners are populated. - for (int i = 0; i < (int)m_offers.size(); i++) - { - const W64_OFFER_INFO& offer = m_offers[i]; + // Register all offers with the app now that banners are populated. + for (int i = 0; i < (int)m_offers.size(); i++) + { + const W64_OFFER_INFO& offer = m_offers[i]; - eDLCContentType eType = e_DLC_SkinPack; - if (wcscmp(offer.wszType, L"MashUp") == 0) eType = e_DLC_MashupPacks; - else if (wcscmp(offer.wszType, L"TexturePack") == 0) eType = e_DLC_TexturePacks; - else if (wcscmp(offer.wszType, L"SkinPack") == 0) eType = e_DLC_SkinPack; + eDLCContentType eType = e_DLC_SkinPack; + if (wcscmp(offer.wszType, L"MashUp") == 0) eType = e_DLC_MashupPacks; + else if (wcscmp(offer.wszType, L"TexturePack") == 0) eType = e_DLC_TexturePacks; + else if (wcscmp(offer.wszType, L"SkinPack") == 0) eType = e_DLC_SkinPack; - printf("[DLC] Registering W64 DLC: '%ls' type=%d\n", - offer.wszProductID, (int)eType); + printf("[DLC] Registering W64 DLC: '%ls' type=%d\n", + offer.wszProductID, (int)eType); - app.RegisterW64DLC( - eType, - offer.wszProductID, // key AND banner texture name - offer.wszProductID, // banner texture name (used as lookup key in UpdateDisplay) - 0, // iConfig - (unsigned int)i, // uiSortIndex - offer.pbBannerData, - offer.dwBannerBytes - ); - } + app.RegisterW64DLC( + eType, + offer.wszProductID, // key AND banner texture name + offer.wszProductID, // banner texture name (used as lookup key in UpdateDisplay) + 0, // iConfig + (unsigned int)i, // uiSortIndex + offer.pbBannerData, + offer.dwBannerBytes + ); + } } #endif \ No newline at end of file diff --git a/Minecraft.Client/Windows64_DLCOffers.h b/Minecraft.Client/Windows64_DLCOffers.h index aa45bc06..0f0464cb 100644 --- a/Minecraft.Client/Windows64_DLCOffers.h +++ b/Minecraft.Client/Windows64_DLCOffers.h @@ -67,7 +67,7 @@ public: void InstallOffer(int iIndex, W64_INSTALL_CALLBACK pfnCallback = nullptr, - void* pUserData = nullptr); + void* pUserData = nullptr, wstring username = L""); static bool FetchImageFromUrl(const wchar_t* url, PBYTE* ppData, DWORD* pdwSize); static bool FetchBytesFromUrl(const wchar_t* url, PBYTE* ppData, DWORD* pdwSize); @@ -95,6 +95,7 @@ private: int offerIndex; W64_INSTALL_CALLBACK pfnCallback; void* pUserData; + wstring username; }; static DWORD WINAPI InstallThreadProc(LPVOID lpParam);