Improve detection for DLC only mode. Add template for message prompts.

This commit is contained in:
Dario 2024-12-02 19:19:37 -03:00
parent 3c449b3386
commit 0ef5a57bb1
4 changed files with 112 additions and 23 deletions

View file

@ -201,6 +201,27 @@ bool Installer::checkGameInstall(const std::filesystem::path &baseDirectory)
return std::filesystem::exists(baseDirectory / GameDirectory / GameExecutableFile);
}
bool Installer::checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc)
{
switch (dlc)
{
case DLC::Spagonia:
return std::filesystem::exists(baseDirectory / SpagoniaDirectory / DLCValidationFile);
case DLC::Chunnan:
return std::filesystem::exists(baseDirectory / ChunnanDirectory / DLCValidationFile);
case DLC::Mazuri:
return std::filesystem::exists(baseDirectory / MazuriDirectory / DLCValidationFile);
case DLC::Holoska:
return std::filesystem::exists(baseDirectory / HoloskaDirectory / DLCValidationFile);
case DLC::ApotosShamar:
return std::filesystem::exists(baseDirectory / ApotosShamarDirectory / DLCValidationFile);
case DLC::EmpireCityAdabat:
return std::filesystem::exists(baseDirectory / EmpireCityAdabatDirectory / DLCValidationFile);
default:
return false;
}
}
bool Installer::computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize)
{
for (FilePair pair : filePairs)
@ -288,6 +309,7 @@ constexpr uint32_t PatcherContribution = 512 * 1024 * 1024;
bool Installer::parseSources(const Input &input, Journal &journal, Sources &sources)
{
journal = Journal();
sources = Sources();
// Parse the contents of the base game.

View file

@ -72,6 +72,7 @@ struct Installer
};
static bool checkGameInstall(const std::filesystem::path &baseDirectory);
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
static bool computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize);
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void()> &progressCallback);
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &targetVfs, Journal &journal);

View file

@ -18,8 +18,6 @@
#include <res/miles_electric_icon_dds.h>
#include <res/arrow_circle_dds.h>
#define SKIP_SOURCE_CHECKS 0
static constexpr double SCANLINES_ANIMATION_TIME = 0.0;
static constexpr double SCANLINES_ANIMATION_DURATION = 15.0;
@ -74,9 +72,12 @@ static ImFont *g_newRodinFont;
static double g_appearTime = 0.0;
static double g_disappearTime = DBL_MAX;
static bool g_isDisappearing = false;
static std::filesystem::path g_installPath = ".";
static std::filesystem::path g_gameSourcePath;
static std::filesystem::path g_updateSourcePath;
static std::array<std::filesystem::path, int(DLC::Count)> g_dlcSourcePaths;
static std::array<bool, int(DLC::Count)> g_dlcInstalled = {};
static std::array<std::unique_ptr<GuestTexture>, 8> g_installTextures;
static std::unique_ptr<GuestTexture> g_milesElectricIcon;
static std::unique_ptr<GuestTexture> g_arrowCircle;
@ -102,7 +103,10 @@ enum class WizardPage
InstallFailed,
};
static WizardPage g_currentPage = WizardPage::Introduction;
static WizardPage g_firstPage = WizardPage::Introduction;
static WizardPage g_currentPage = g_firstPage;
static std::string g_currentMessagePrompt = "";
static bool g_currentMessagePromptConfirmation = false;
const char INSTALLER_TEXT[] = "INSTALLER";
const char INSTALLING_TEXT[] = "INSTALLING";
@ -400,7 +404,7 @@ static void DrawButton(ImVec2 min, ImVec2 max, const char *buttonText, bool sour
int baser = 0;
int baseg = 0;
if (!sourceButton && buttonEnabled && (alpha >= 1.0f) && ImGui::IsMouseHoveringRect(min, max, false))
if (g_currentMessagePrompt.empty() && !sourceButton && buttonEnabled && (alpha >= 1.0f) && ImGui::IsMouseHoveringRect(min, max, false))
{
baser = 48;
baseg = 32;
@ -580,6 +584,7 @@ static void ParseSourcePaths(std::list<std::filesystem::path> &paths)
{
assert((g_currentPage == WizardPage::SelectGameAndUpdate) || (g_currentPage == WizardPage::SelectDLC));
constexpr size_t failedPathLimit = 5;
std::list<std::filesystem::path> failedPaths;
if (g_currentPage == WizardPage::SelectGameAndUpdate)
{
@ -593,7 +598,7 @@ static void ParseSourcePaths(std::list<std::filesystem::path> &paths)
{
g_updateSourcePath = path;
}
else
else if (failedPaths.size() < failedPathLimit)
{
failedPaths.push_back(path);
}
@ -608,7 +613,7 @@ static void ParseSourcePaths(std::list<std::filesystem::path> &paths)
{
g_dlcSourcePaths[DLCIndex(dlc)] = path;
}
else
else if (failedPaths.size() < failedPathLimit)
{
failedPaths.push_back(path);
}
@ -617,7 +622,15 @@ static void ParseSourcePaths(std::list<std::filesystem::path> &paths)
if (!failedPaths.empty())
{
// TODO: Show list of content that failed to parse with a prompt.
std::stringstream stringStream;
stringStream << "Some of the files that were selected are not valid." << std::endl;
for (const std::filesystem::path &path : failedPaths)
{
stringStream << std::endl << path.filename().string();
}
g_currentMessagePrompt = stringStream.str();
g_currentMessagePromptConfirmation = false;
}
}
@ -663,7 +676,7 @@ static void DrawSources()
{
for (int i = 0; i < 6; i++)
{
DrawSourceButton((i < 3) ? SourceColumnLeft : SourceColumnRight, float(i % 3), DLC_SOURCE_TEXT[i], !g_dlcSourcePaths[i].empty());
DrawSourceButton((i < 3) ? SourceColumnLeft : SourceColumnRight, float(i % 3), DLC_SOURCE_TEXT[i], !g_dlcSourcePaths[i].empty() || g_dlcInstalled[i]);
}
}
}
@ -687,7 +700,7 @@ static void DrawInstallingProgress()
static void InstallerThread()
{
if (!Installer::install(g_installerSources, ".", false, g_installerJournal, [&]() {
if (!Installer::install(g_installerSources, g_installPath, false, g_installerJournal, [&]() {
g_installerProgressRatioTarget = float(double(g_installerJournal.progressCounter) / double(g_installerJournal.progressTotal));
}))
{
@ -703,6 +716,7 @@ static void InstallerThread()
static void InstallerStart()
{
g_currentPage = WizardPage::Installing;
g_installerStartTime = ImGui::GetTime();
g_installerProgressRatioCurrent = 0.0f;
g_installerProgressRatioTarget = 0.0f;
@ -713,7 +727,7 @@ static void InstallerStart()
static bool InstallerParseSources()
{
std::filesystem::space_info spaceInfo = std::filesystem::space(".");
std::filesystem::space_info spaceInfo = std::filesystem::space(g_installPath);
g_installerAvailableSize = spaceInfo.available;
Installer::Input installerInput;
@ -734,12 +748,11 @@ static void DrawNextButton()
{
if (g_currentPage != WizardPage::Installing) {
bool nextButtonEnabled = !g_isDisappearing;
#if !SKIP_SOURCE_CHECKS
if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate)
{
nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty();
}
#endif
bool skipButton = false;
if (g_currentPage == WizardPage::SelectDLC)
{
@ -761,11 +774,46 @@ static void DrawNextButton()
XexPatcher::Result patcherResult;
if (g_currentPage == WizardPage::SelectGameAndUpdate && (patcherResult = Installer::checkGameUpdateCompatibility(g_gameSourcePath, g_updateSourcePath), patcherResult != XexPatcher::Result::Success))
{
// TODO: Show error prompt for compatibility failure check. Tell user to try with different files.
g_currentMessagePrompt = "The specified game and update file are incompatible.\n\nPlease ensure the files are for the same version and region and try again.";
g_currentMessagePromptConfirmation = false;
}
else if (g_currentPage == WizardPage::SelectDLC && !InstallerParseSources())
else if (g_currentPage == WizardPage::SelectDLC)
{
// TODO: Show an error that the sources were unable to be parsed. Ask to try again.
// Check if any of the DLC was not specified.
bool dlcIncomplete = false;
for (int i = 0; (i < int(DLC::Count)) && !dlcIncomplete; i++)
{
if (g_dlcSourcePaths[i].empty() && !g_dlcInstalled[i])
{
dlcIncomplete = true;
}
}
bool dlcInstallerMode = g_gameSourcePath.empty();
if (!InstallerParseSources())
{
// Some of the sources that were provided to the installer are not valid. Restart the file selection process.
g_currentMessagePrompt = "Some of the files that have been provided are not valid.\n\nPlease make sure all the specified files are correct and try again.";
g_currentMessagePromptConfirmation = false;
g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate;
}
else if (dlcIncomplete && !dlcInstallerMode)
{
// Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer.
g_currentMessagePrompt = "It is highly recommended that you install all of the DLC, as it includes high quality lighting textures for the stages in each pack.\n\nAre you sure you want to skip this step?";
g_currentMessagePromptConfirmation = true;
}
else if (skipButton && dlcInstallerMode)
{
// Nothing was selected and the installer was in DLC mode, just close it.
g_isDisappearing = true;
g_disappearTime = ImGui::GetTime();
}
else
{
// Start the installer outright, this switches to the right page on its own.
InstallerStart();
}
}
else if (g_currentPage == WizardPage::InstallSucceeded)
{
@ -774,16 +822,11 @@ static void DrawNextButton()
}
else if (g_currentPage == WizardPage::InstallFailed)
{
g_currentPage = WizardPage::Introduction;
g_currentPage = g_firstPage;
}
else
{
g_currentPage = WizardPage(int(g_currentPage) + 1);
if (g_currentPage == WizardPage::Installing)
{
InstallerStart();
}
}
}
}
@ -862,6 +905,22 @@ static void DrawBorders()
DrawVerticalBorder(true);
}
static void DrawMessagePrompt()
{
if (g_currentMessagePrompt.empty())
{
return;
}
// TODO: Put message prompt here.
if (false && g_currentPage == WizardPage::SelectDLC)
{
// If user confirms the message prompt that they wish to skip installing the DLC, start the installer.
InstallerStart();
}
}
void InstallerWizard::Init()
{
auto &io = ImGui::GetIO();
@ -897,6 +956,7 @@ void InstallerWizard::Draw()
DrawInstallingProgress();
DrawNextButton();
DrawBorders();
DrawMessagePrompt();
if (g_isDisappearing)
{
@ -927,7 +987,13 @@ bool InstallerWizard::Run(bool skipGame)
if (skipGame)
{
g_currentPage = WizardPage::SelectDLC;
for (int i = 0; i < int(DLC::Count); i++)
{
g_dlcInstalled[i] = Installer::checkDLCInstall(g_installPath, DLC(i + 1));
}
g_firstPage = WizardPage::SelectDLC;
g_currentPage = g_firstPage;
}
Window::SetCursorAllowed(true);

@ -1 +1 @@
Subproject commit d9063dd234b92fd7ab35e72d1839d0fcfdc83456
Subproject commit 79a2a18cc8013dd6d76d8300f703f19f6e0ec484