Skip to content

Commit f462e2f

Browse files
committed
Harden iOS install validation diagnostics
1 parent 294f633 commit f462e2f

4 files changed

Lines changed: 87 additions & 4 deletions

File tree

UnleashedRecomp/install/installer.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ bool Installer::checkGameInstall(const std::filesystem::path &baseDirectory, std
357357
#ifdef UNLEASHED_RECOMP_IOS
358358
if (!std::filesystem::exists(baseDirectory / InstallValidationFile))
359359
return false;
360+
361+
Journal journal;
362+
if (!checkInstallCompleteness(baseDirectory, journal, []()
363+
{
364+
return true;
365+
}))
366+
{
367+
return false;
368+
}
360369
#endif
361370

362371
return true;
@@ -396,6 +405,35 @@ bool Installer::checkAllDLC(const std::filesystem::path& baseDirectory)
396405
return result;
397406
}
398407

408+
bool Installer::checkInstallCompleteness(const std::filesystem::path &baseDirectory, Journal &journal, const std::function<bool()> &progressCallback)
409+
{
410+
if (!checkFiles({ GameFiles, GameFilesSize }, GameHashes, baseDirectory / GameDirectory, journal, progressCallback, true))
411+
{
412+
return false;
413+
}
414+
415+
if (!checkFiles({ UpdateFiles, UpdateFilesSize }, UpdateHashes, baseDirectory / UpdateDirectory, journal, progressCallback, true))
416+
{
417+
return false;
418+
}
419+
420+
for (int i = 1; i < (int)DLC::Count; i++)
421+
{
422+
if (checkDLCInstall(baseDirectory, (DLC)i))
423+
{
424+
Installer::DLCSource dlcSource;
425+
fillDLCSource((DLC)i, dlcSource);
426+
427+
if (!checkFiles(dlcSource.filePairs, dlcSource.fileHashes, baseDirectory / dlcSource.targetSubDirectory, journal, progressCallback, true))
428+
{
429+
return false;
430+
}
431+
}
432+
}
433+
434+
return true;
435+
}
436+
399437
bool Installer::checkInstallIntegrity(const std::filesystem::path &baseDirectory, Journal &journal, const std::function<bool()> &progressCallback)
400438
{
401439
// Run the file checks twice: once to fill out the progress counter and the file sizes, and another pass to do the hash integrity checks.

UnleashedRecomp/install/installer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct Installer
7575
static bool checkGameInstall(const std::filesystem::path &baseDirectory, std::filesystem::path &modulePath);
7676
static bool checkDLCInstall(const std::filesystem::path &baseDirectory, DLC dlc);
7777
static bool checkAllDLC(const std::filesystem::path &baseDirectory);
78+
static bool checkInstallCompleteness(const std::filesystem::path &baseDirectory, Journal &journal, const std::function<bool()> &progressCallback);
7879
static bool checkInstallIntegrity(const std::filesystem::path &baseDirectory, Journal &journal, const std::function<bool()> &progressCallback);
7980
static bool computeTotalSize(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, Journal &journal, uint64_t &totalSize);
8081
static bool checkFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, const std::filesystem::path &targetDirectory, Journal &journal, const std::function<bool()> &progressCallback, bool checkSizeOnly);

UnleashedRecomp/main.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ Heap g_userHeap;
4949
XDBFWrapper g_xdbfWrapper;
5050
std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
5151

52+
static std::string PathToUTF8(const std::filesystem::path& path)
53+
{
54+
auto pathU8 = path.u8string();
55+
return std::string(pathU8.begin(), pathU8.end());
56+
}
57+
5258
void HostStartup()
5359
{
5460
#ifdef _WIN32
@@ -207,6 +213,10 @@ int main(int argc, char *argv[])
207213

208214
os::logger::Init();
209215

216+
#ifdef UNLEASHED_RECOMP_IOS
217+
LOGN("iOS startup build: install-validation-v3");
218+
#endif
219+
210220
PreloadContext preloadContext;
211221
preloadContext.PreloadExecutable();
212222

@@ -248,10 +258,14 @@ int main(int argc, char *argv[])
248258
// Create the console to show progress to the user, otherwise it will seem as if the game didn't boot at all.
249259
os::process::ShowConsole();
250260

261+
const auto installCheckPath = GetGamePath();
262+
fprintf(stdout, "Checking installation at %s\n", PathToUTF8(installCheckPath).c_str());
263+
LOGFN("Checking installation at {}", PathToUTF8(installCheckPath));
264+
251265
Journal journal;
252266
double lastProgressMiB = 0.0;
253267
double lastTotalMib = 0.0;
254-
Installer::checkInstallIntegrity(GAME_INSTALL_DIRECTORY, journal, [&]()
268+
Installer::checkInstallIntegrity(installCheckPath, journal, [&]()
255269
{
256270
constexpr double MiBDivisor = 1024.0 * 1024.0;
257271
constexpr double MiBProgressThreshold = 128.0;
@@ -326,8 +340,16 @@ int main(int argc, char *argv[])
326340

327341
HostStartup();
328342

343+
const auto gamePath = GetGamePath();
329344
std::filesystem::path modulePath;
330-
bool isGameInstalled = Installer::checkGameInstall(GetGamePath(), modulePath);
345+
LOGFN("Game path: {}", PathToUTF8(gamePath));
346+
bool isGameInstalled = Installer::checkGameInstall(gamePath, modulePath);
347+
LOGFN("Install status before wizard: installed={}, forceInstaller={}, forceDLCInstaller={}, modulePath={}",
348+
isGameInstalled,
349+
forceInstaller,
350+
forceDLCInstaller,
351+
PathToUTF8(modulePath));
352+
331353
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
332354
if (runInstallerWizard)
333355
{
@@ -337,10 +359,21 @@ int main(int argc, char *argv[])
337359
std::_Exit(1);
338360
}
339361

340-
if (!InstallerWizard::Run(GetGamePath(), isGameInstalled && forceDLCInstaller))
362+
if (!InstallerWizard::Run(gamePath, isGameInstalled && forceDLCInstaller))
341363
{
364+
LOGN("Installer wizard cancelled.");
342365
std::_Exit(0);
343366
}
367+
368+
isGameInstalled = Installer::checkGameInstall(gamePath, modulePath);
369+
LOGFN("Install status after wizard: installed={}, modulePath={}", isGameInstalled, PathToUTF8(modulePath));
370+
if (!isGameInstalled)
371+
{
372+
const std::string errorMessage = "The game data installation did not finish correctly. Please run the installer again and select the base game ISO plus update file.";
373+
LOGN_ERROR(errorMessage);
374+
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), errorMessage.c_str(), GameWindow::s_pWindow);
375+
std::_Exit(4);
376+
}
344377
}
345378

346379
ModLoader::Init();
@@ -350,7 +383,16 @@ int main(int argc, char *argv[])
350383

351384
KiSystemStartup();
352385

386+
LOGFN("Loading module from {}", PathToUTF8(modulePath));
353387
uint32_t entry = LdrLoadModule(modulePath);
388+
if (entry == 0)
389+
{
390+
const std::string errorMessage = "Failed to load the patched game executable. Please run the installer again.";
391+
LOGN_ERROR(errorMessage);
392+
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), errorMessage.c_str(), GameWindow::s_pWindow);
393+
std::_Exit(4);
394+
}
395+
LOGFN("Loaded module entry: 0x{:08X}", entry);
354396

355397
if (!runInstallerWizard)
356398
{
@@ -361,8 +403,10 @@ int main(int argc, char *argv[])
361403
}
362404
}
363405

406+
LOGN("Starting pipeline precompilation.");
364407
Video::StartPipelinePrecompilation();
365408

409+
LOGFN("Starting guest thread at 0x{:08X}", entry);
366410
GuestThread::Start({ entry, 0, 0 });
367411

368412
return 0;

UnleashedRecomp/res/version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
VERSION_MILESTONE=""
22
VERSION_MAJOR=1
33
VERSION_MINOR=0
4-
VERSION_REVISION=3
4+
VERSION_REVISION=4

0 commit comments

Comments
 (0)