Finish downloading of game and sdk files

Moved entire logic to dedicated wrappers.
This commit is contained in:
Kawe Mazidjatari 2023-07-28 14:50:46 +02:00
parent 79ecc735a9
commit 41ebc431b2
8 changed files with 436 additions and 8 deletions

View File

@ -10,10 +10,14 @@ add_sources( SOURCE_GROUP "Core"
)
add_sources( SOURCE_GROUP "GUI"
"basepanel.cpp"
"basepanel.h"
"advanced_surface.cpp"
"advanced_surface.h"
"base_surface.cpp"
"base_surface.h"
"download_surface.cpp"
"download_surface.h"
)
add_sources( SOURCE_GROUP "Resource"
@ -38,8 +42,14 @@ target_precompile_headers( ${PROJECT_NAME} PRIVATE
)
target_link_libraries( ${PROJECT_NAME} PRIVATE
"tier0"
"tier1"
"tier2"
"libdetours"
"libcppkore"
"libspdlog"
"libcurl"
"crypt32.lib"
"ws2_32.lib"
"wldap32.lib"
"Rpcrt4.lib"
)

View File

@ -5,8 +5,17 @@
//=============================================================================//
#include "base_surface.h"
#include "advanced_surface.h"
#include "download_surface.h"
#include "tier1/xorstr.h"
#include "tier2/curlutils.h"
// Gigabytes.
// TODO: obtain these from the repo...
#define MIN_REQUIRED_DISK_SPACE 20
#define MIN_REQUIRED_DISK_SPACE_OPT 55 // Optional textures
#define DEFAULT_DEPOT_DOWNLOAD_DIR "platform\\depot\\"
CBaseSurface::CBaseSurface()
{
const INT WindowX = 400;
@ -41,7 +50,7 @@ CBaseSurface::CBaseSurface()
this->m_ManageButton->SetTabIndex(9);
this->m_ManageButton->SetText(isInstalled ? XorStr("Launch Apex") : XorStr("Install Apex"));
this->m_ManageButton->SetAnchor(Forms::AnchorStyles::Bottom | Forms::AnchorStyles::Left);
this->m_ManageButton->Click += isInstalled ? &OnAdvancedClick : &OnAdvancedClick;
this->m_ManageButton->Click += isInstalled ? &OnAdvancedClick : &OnInstallClick;
m_BaseGroup->AddControl(this->m_ManageButton);
this->m_RepairButton = new UIX::UIXButton();
@ -81,6 +90,224 @@ CBaseSurface::CBaseSurface()
this->m_AdvancedButton->SetAnchor(Forms::AnchorStyles::Bottom | Forms::AnchorStyles::Left);
this->m_AdvancedButton->Click += &OnAdvancedClick;
m_BaseGroup->AddControl(this->m_AdvancedButton);
// TODO: Use a toggle item instead; remove this field.
m_bPartialInstall = false;
}
bool QueryServer(const char* url, string& outResponse, string& outMessage, CURLINFO& outStatus)
{
curl_slist* sList = nullptr;
CURLParams params;
params.writeFunction = CURLWriteStringCallback;
params.timeout = 15;
params.verifyPeer = true;
params.verbose = false;
CURL* curl = CURLInitRequest(url, nullptr, outResponse, sList, params);
if (!curl)
{
return false;
}
CURLcode res = CURLSubmitRequest(curl, sList);
if (!CURLHandleError(curl, res, outMessage, true))
{
return false;
}
outStatus = CURLRetrieveInfo(curl);
return true;
}
int DownloadStatusCallback(CURLProgress* progessData, double dltotal, double dlnow, double ultotal, double ulnow)
{
CDownloadProgress* pDownloadSurface = (CDownloadProgress*)progessData->cust;
if (pDownloadSurface->IsCanceled())
return -1;
double downloaded;
curl_easy_getinfo(progessData->curl, CURLINFO_SIZE_DOWNLOAD, &downloaded);
size_t percentage = ((size_t)downloaded * 100) / progessData->size;
pDownloadSurface->UpdateProgress((uint32_t)percentage, false);
return 0;
}
void DownloadAsset(CDownloadProgress* pProgress, const char* url, const char* path,
const char* fileName, const size_t fileSize, const char* options)
{
CreateDirectoryA(path, NULL);
CURLParams params;
params.writeFunction = CURLWriteFileCallback;
params.statusFunction = DownloadStatusCallback;
CURLDownloadFile(url, path, fileName, options, fileSize, pProgress, params);
}
void DownloadAssetList(CDownloadProgress* pProgress, nlohmann::json& assetList, std::set<string>& blackList, const char* pPath)
{
int i = 1;
for (auto& asset : assetList)
{
if (pProgress->IsCanceled())
{
pProgress->Close();
break;
}
if (!asset.contains("browser_download_url") ||
!asset.contains("name") ||
!asset.contains("size"))
{
Assert(0);
return;
}
const string fileName = asset["name"];
// Asset is filtered, don't download.
if (blackList.find(fileName) != blackList.end())
continue;
const string downloadLink = asset["browser_download_url"];
const size_t fileSize = asset["size"];
pProgress->SetExportLabel(Format("File %s (%i of %i)", fileName.c_str(), i, assetList.size()).c_str());
DownloadAsset(pProgress, downloadLink.c_str(), pPath, fileName.c_str(), fileSize, "wb+");
i++;
}
}
bool DownloadLatestGitHubReleaseManifest(const char* url, string& responseMessage, nlohmann::json& outManifest, const bool preRelease)
{
string responseBody;
CURLINFO status;
if (!QueryServer(url, responseBody, responseMessage, status))
{
// TODO: Error dialog...
printf("Query error!\n");
return false;
}
if (status != 200)
{
// TODO: Error dialog...
printf("Query error; status not 200!\n%s\n", responseBody.c_str());
return false;
}
try
{
nlohmann::json responseJson = nlohmann::json::parse(responseBody);
for (size_t i = 0; i < responseJson.size(); i++)
{
auto& release = responseJson[i];
if (preRelease && release["prerelease"])
{
outManifest = release["assets"];
break;
}
else if (!preRelease && !release["prerelease"])
{
outManifest = release["assets"];
break;
}
if (i == responseJson.size()-1 && outManifest.empty())
release[0]["assets"]; // Just take the first one then.
}
}
catch (const std::exception& ex)
{
printf("%s - Exception while parsing response:\n%s\n", __FUNCTION__, ex.what());
//Warning(eDLL_T::ENGINE, "%s - Exception while parsing response:\n%s\n", __FUNCTION__, ex.what());
// TODO: Error dialog; report to amos or something like that.
return false;
}
return !outManifest.empty();
}
void BeginInstall(CDownloadProgress* pProgress, const bool bPrerelease, const bool bOptionalAssets)
{
string responseMesage;
nlohmann::json manifest;
// These files will NOT be downloaded from the release depots.
std::set<string> blackList;
blackList.insert("symbols.zip");
// Download core game files.
if (!DownloadLatestGitHubReleaseManifest(XorStr("https://api.github.com/repos/SlaveBuild/N1094_CL456479/releases"), responseMesage, manifest, bPrerelease))
{
// TODO: Error dialog.
return;
}
DownloadAssetList(pProgress, manifest, blackList, DEFAULT_DEPOT_DOWNLOAD_DIR);
// Download SDK files.
if (!DownloadLatestGitHubReleaseManifest(XorStr("https://api.github.com/repos/Mauler125/r5sdk/releases"), responseMesage, manifest, bPrerelease))
{
// TODO: Error dialog.
return;
}
DownloadAssetList(pProgress, manifest, blackList, DEFAULT_DEPOT_DOWNLOAD_DIR);
// Install process cannot be canceled.
pProgress->SetCanCancel(false);
}
void CBaseSurface::OnInstallClick(Forms::Control* Sender)
{
CBaseSurface* pSurf = (CBaseSurface*)Sender;
const bool bPartial = pSurf->m_bPartialInstall;
//----------------------------------------------------------------------------
// Disk space check
//----------------------------------------------------------------------------
char currentDir[MAX_PATH]; // Get current dir.
GetCurrentDirectoryA(sizeof(currentDir), currentDir);
// Does this disk have enough space?
ULARGE_INTEGER avaliableSize;
GetDiskFreeSpaceEx(currentDir, &avaliableSize, nullptr, nullptr);
const int minRequiredSpace = bPartial ? MIN_REQUIRED_DISK_SPACE : MIN_REQUIRED_DISK_SPACE_OPT;
const int currentAvailSpace = (int)(avaliableSize.QuadPart / uint64_t(1024 * 1024 * 1024));
//if (currentAvailSpace < minRequiredSpace)
//{
// // TODO: Make dialog box.
// printf("There is not enough space available on the disk to install R5Reloaded; you need at least %iGB, you currently have %iGB\n", minRequiredSpace, currentAvailSpace);
// return;
//}
auto downloadSurface = std::make_unique<CDownloadProgress>();
CDownloadProgress* pProgress = downloadSurface.get();
pProgress->SetAutoClose(true);
Threading::Thread([pProgress] {
BeginInstall(pProgress);
}).Start();
pProgress->ShowDialog();
}
void CBaseSurface::OnAdvancedClick(Forms::Control* Sender)
@ -91,16 +318,10 @@ void CBaseSurface::OnAdvancedClick(Forms::Control* Sender)
void CBaseSurface::OnSupportClick(Forms::Control* /*Sender*/)
{
//auto pAdvancedSurface = std::make_unique<CAdvancedSurface>();
//pAdvancedSurface->ShowDialog((Forms::Form*)Sender->FindForm());
ShellExecute(0, 0, XorStr("https://www.paypal.com/donate/?hosted_button_id=S28DHC2TF6UV4"), 0, 0, SW_SHOW);
}
void CBaseSurface::OnJoinClick(Forms::Control* /*Sender*/)
{
//auto pAdvancedSurface = std::make_unique<CAdvancedSurface>();
//pAdvancedSurface->ShowDialog((Forms::Form*)Sender->FindForm());
ShellExecute(0, 0, XorStr("https://discord.com/invite/jqMkUdXrBr"), 0, 0, SW_SHOW);
}

View File

@ -10,6 +10,8 @@ public:
};
protected:
static void OnInstallClick(Forms::Control* Sender);
static void OnAdvancedClick(Forms::Control* Sender);
@ -40,4 +42,8 @@ private:
UIX::UIXButton* m_DonateButton;
UIX::UIXButton* m_JoinButton;
UIX::UIXButton* m_AdvancedButton;
// When this is false, the installer will
// download the HD textures as well (STARPAK's).
bool m_bPartialInstall;
};

View File

@ -0,0 +1,115 @@
#include "pch.h"
#include "download_surface.h"
CDownloadProgress::CDownloadProgress()
: Forms::Form(), m_bCanClose(false), m_bCanceled(false), m_bAutoClose(false)
{
this->InitializeComponent();
}
void CDownloadProgress::UpdateProgress(uint32_t Progress, bool Finished)
{
this->m_ProgressBar->SetValue(Progress);
if (Finished)
{
this->m_FinishButton->SetEnabled(true);
this->m_CancelButton->SetEnabled(false);
this->m_bCanClose = true;
this->SetText("Download Complete");
if (this->m_bCanceled || this->m_bAutoClose)
this->Close();
}
}
bool CDownloadProgress::IsCanceled()
{
return this->m_bCanceled;
}
void CDownloadProgress::SetCanCancel(bool bEnable)
{
m_CancelButton->SetEnabled(bEnable);
}
void CDownloadProgress::SetAutoClose(bool Value)
{
this->m_bAutoClose = Value;
}
void CDownloadProgress::SetExportLabel(const char* pNewLabel)
{
m_DownloadLabel->SetText(pNewLabel);
}
void CDownloadProgress::InitializeComponent()
{
this->SuspendLayout();
this->SetAutoScaleDimensions({ 6, 13 });
this->SetAutoScaleMode(Forms::AutoScaleMode::Font);
this->SetText("Downloading Files...");
this->SetClientSize({ 409, 119 });
this->SetFormBorderStyle(Forms::FormBorderStyle::FixedSingle);
this->SetStartPosition(Forms::FormStartPosition::CenterParent);
this->SetMinimizeBox(false);
this->SetMaximizeBox(false);
this->SetShowInTaskbar(false);
this->SetBackColor(Drawing::Color(47, 54, 61));
this->m_DownloadLabel = new UIX::UIXLabel();
this->m_DownloadLabel->SetSize({ 385, 17 });
this->m_DownloadLabel->SetLocation({ 12, 18 });
this->m_DownloadLabel->SetTabIndex(3);
this->m_DownloadLabel->SetText("Progress:");
this->m_DownloadLabel->SetAnchor(Forms::AnchorStyles::Top | Forms::AnchorStyles::Left | Forms::AnchorStyles::Right);
this->m_DownloadLabel->SetTextAlign(Drawing::ContentAlignment::TopLeft);
this->AddControl(this->m_DownloadLabel);
this->m_CancelButton = new UIX::UIXButton();
this->m_CancelButton->SetSize({ 87, 31 });
this->m_CancelButton->SetLocation({ 310, 76 });
this->m_CancelButton->SetTabIndex(2);
this->m_CancelButton->SetText("Cancel");
this->m_CancelButton->SetAnchor(Forms::AnchorStyles::Bottom | Forms::AnchorStyles::Right);
this->m_CancelButton->Click += &OnCancelClick;
this->AddControl(this->m_CancelButton);
this->m_FinishButton = new UIX::UIXButton();
this->m_FinishButton->SetSize({ 87, 31 });
this->m_FinishButton->SetLocation({ 217, 76 });
this->m_FinishButton->SetTabIndex(1);
this->m_FinishButton->SetText("Ok");
this->m_FinishButton->SetEnabled(false);
this->m_FinishButton->SetAnchor(Forms::AnchorStyles::Bottom | Forms::AnchorStyles::Right);
this->m_FinishButton->Click += &OnFinishClick;
this->AddControl(this->m_FinishButton);
this->m_ProgressBar = new UIX::UIXProgressBar();
this->m_ProgressBar->SetSize({ 385, 29 });
this->m_ProgressBar->SetLocation({ 12, 38 });
this->m_ProgressBar->SetTabIndex(0);
this->m_ProgressBar->SetAnchor(Forms::AnchorStyles::Top | Forms::AnchorStyles::Left | Forms::AnchorStyles::Right);
this->AddControl(this->m_ProgressBar);
this->ResumeLayout(false);
this->PerformLayout();
// END DESIGNER CODE
}
void CDownloadProgress::OnFinishClick(Forms::Control* Sender)
{
((Forms::Form*)Sender->FindForm())->Close();
}
void CDownloadProgress::OnCancelClick(Forms::Control* Sender)
{
((CDownloadProgress*)Sender->FindForm())->CancelProgress();
}
void CDownloadProgress::CancelProgress()
{
this->m_CancelButton->SetEnabled(false);
this->m_CancelButton->SetText("Canceling...");
this->m_bCanceled = true;
}

View File

@ -0,0 +1,37 @@
#pragma once
class CDownloadProgress : public Forms::Form
{
public:
CDownloadProgress();
virtual ~CDownloadProgress() = default;
// Updates the progress
void UpdateProgress(uint32_t Progress, bool Finished);
bool IsCanceled();
void SetCanCancel(bool bEnable);
void SetAutoClose(bool Value);
void SetExportLabel(const char* pNewLabel);
private:
// Internal routine to setup the component
void InitializeComponent();
// Internal event on finish click
static void OnFinishClick(Forms::Control* Sender);
static void OnCancelClick(Forms::Control* Sender);
void CancelProgress(); // Cancels the progress
// Internal controls reference
UIX::UIXLabel* m_DownloadLabel;
UIX::UIXButton* m_CancelButton;
UIX::UIXButton* m_FinishButton;
UIX::UIXProgressBar* m_ProgressBar;
bool m_bCanClose; // Whether or not we can close.
bool m_bCanceled; // Whether or not we canceled it.
bool m_bAutoClose; // Whether or not to automatically close.
};

View File

@ -352,6 +352,39 @@ BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
return TRUE;
}
void LauncherLoggerSink(LogType_t logType, LogLevel_t logLevel, eDLL_T context,
const char* pszLogger, const char* pszFormat, va_list args,
const UINT exitCode /*= NO_ERROR*/, const char* pszUptimeOverride /*= nullptr*/)
{
const char* pszUpTime = pszUptimeOverride ? pszUptimeOverride : Plat_GetProcessUpTime();
string message(pszUpTime);
const char* pszContext = ""; //"GetContextNameByIndex(context, bUseColor);
message.append(pszContext);
NOTE_UNUSED(pszLogger);
//-------------------------------------------------------------------------
// Format actual input
//-------------------------------------------------------------------------
va_list argsCopy;
va_copy(argsCopy, args);
const string formatted = FormatV(pszFormat, argsCopy);
va_end(argsCopy);
message.append(formatted);
printf("%s", message.c_str());
if (exitCode) // Terminate the process if an exit code was passed.
{
if (MessageBoxA(NULL, Format("%s- %s", pszUpTime, formatted.c_str()).c_str(),
"SDK Error", MB_ICONERROR | MB_OK))
{
TerminateProcess(GetCurrentProcess(), exitCode);
}
}
}
///////////////////////////////////////////////////////////////////////////////
// EntryPoint.
///////////////////////////////////////////////////////////////////////////////
@ -363,7 +396,10 @@ int main(int argc, char* argv[]/*, char* envp[]*/)
#ifdef NDEBUG
FreeConsole();
#endif // NDEBUG
curl_global_init(CURL_GLOBAL_ALL);
g_CoreMsgVCallback = LauncherLoggerSink;
g_pLauncher->RunSurface();
curl_global_cleanup();
}
else
{
@ -373,6 +409,7 @@ int main(int argc, char* argv[]/*, char* envp[]*/)
return g_pLauncher->HandleInput();
}
return EXIT_SUCCESS;
}

View File

@ -13,6 +13,8 @@
#include "thirdparty/cppnet/cppkore/UIXGroupBox.h"
#include "thirdparty/cppnet/cppkore/UIXButton.h"
#include "thirdparty/cppnet/cppkore/UIXRadioButton.h"
#include "thirdparty/cppnet/cppkore/UIXProgressBar.h"
#include "thirdparty/cppnet/cppkore/KoreTheme.h"
#include "thirdparty/cppnet/cppkore/Thread.h"
#include "sdklauncher/sdklauncher_const.h"

View File

@ -158,8 +158,8 @@ namespace Themes
Gdiplus::RectF FillBounds(0, 0, (Rect.Width - 1.f) * (Progress / 100.0f), Rect.Height - 1.f);
Drawing::FillRoundRectangle(EventArgs->Graphics.get(), &FillBrush, FillBounds, 2);
}
EventArgs->Graphics->SetSmoothingMode(SmMode);
EventArgs->Graphics->SetSmoothingMode(SmMode);
//EventArgs->Graphics->FillRectangle(&FillBrush, Gdiplus::RectF(2, 2, (Rect.Width - 4.f) * (Progress / 100.0f), Rect.Height - 4.f));
}