mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-04-28 13:27:58 +03:00
296 lines
8.9 KiB
C++
296 lines
8.9 KiB
C++
#include <stdafx.h>
|
|
#include <cpuid.h>
|
|
#include <cpu/guest_thread.h>
|
|
#include <gpu/video.h>
|
|
#include <kernel/function.h>
|
|
#include <kernel/memory.h>
|
|
#include <kernel/heap.h>
|
|
#include <kernel/xam.h>
|
|
#include <kernel/io/file_system.h>
|
|
#include <file.h>
|
|
#include <xex.h>
|
|
#include <apu/audio.h>
|
|
#include <hid/hid.h>
|
|
#include <user/config.h>
|
|
#include <user/paths.h>
|
|
#include <user/registry.h>
|
|
#include <kernel/xdbf.h>
|
|
#include <install/installer.h>
|
|
#include <install/update_checker.h>
|
|
#include <os/logger.h>
|
|
#include <os/process.h>
|
|
#include <os/registry.h>
|
|
#include <ui/game_window.h>
|
|
#include <ui/installer_wizard.h>
|
|
#include <mod/mod_loader.h>
|
|
#include <preload_executable.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <timeapi.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32) && defined(UNLEASHED_RECOMP_D3D12)
|
|
static std::array<std::string_view, 3> g_D3D12RequiredModules =
|
|
{
|
|
"D3D12/D3D12Core.dll",
|
|
"dxcompiler.dll",
|
|
"dxil.dll"
|
|
};
|
|
#endif
|
|
|
|
const size_t XMAIOBegin = 0x7FEA0000;
|
|
const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
|
|
|
|
Memory g_memory;
|
|
Heap g_userHeap;
|
|
XDBFWrapper g_xdbfWrapper;
|
|
std::unordered_map<uint16_t, GuestTexture*> g_xdbfTextureCache;
|
|
|
|
void HostStartup()
|
|
{
|
|
#ifdef _WIN32
|
|
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
#endif
|
|
|
|
g_userHeap.Init();
|
|
|
|
hid::Init();
|
|
}
|
|
|
|
// Name inspired from nt's entry point
|
|
void KiSystemStartup()
|
|
{
|
|
const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game");
|
|
const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update");
|
|
XamRegisterContent(gameContent, GAME_INSTALL_DIRECTORY "/game");
|
|
XamRegisterContent(updateContent, GAME_INSTALL_DIRECTORY "/update");
|
|
|
|
const auto saveFilePath = GetSaveFilePath(true);
|
|
bool saveFileExists = std::filesystem::exists(saveFilePath);
|
|
|
|
if (!saveFileExists)
|
|
{
|
|
// Copy base save data to modded save as fallback.
|
|
std::error_code ec;
|
|
std::filesystem::create_directories(saveFilePath.parent_path(), ec);
|
|
|
|
if (!ec)
|
|
{
|
|
std::filesystem::copy_file(GetSaveFilePath(false), saveFilePath, ec);
|
|
saveFileExists = !ec;
|
|
}
|
|
}
|
|
|
|
if (saveFileExists)
|
|
{
|
|
std::u8string savePathU8 = saveFilePath.parent_path().u8string();
|
|
XamRegisterContent(XamMakeContent(XCONTENTTYPE_SAVEDATA, "SYS-DATA"), (const char*)(savePathU8.c_str()));
|
|
}
|
|
|
|
// Mount game
|
|
XamContentCreateEx(0, "game", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
|
XamContentCreateEx(0, "update", &updateContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
|
|
|
// OS mounts game data to D:
|
|
XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
|
|
|
std::error_code ec;
|
|
for (auto& file : std::filesystem::directory_iterator(GAME_INSTALL_DIRECTORY "/dlc", ec))
|
|
{
|
|
if (file.is_directory())
|
|
{
|
|
std::u8string fileNameU8 = file.path().filename().u8string();
|
|
std::u8string filePathU8 = file.path().u8string();
|
|
XamRegisterContent(XamMakeContent(XCONTENTTYPE_DLC, (const char*)(fileNameU8.c_str())), (const char*)(filePathU8.c_str()));
|
|
}
|
|
}
|
|
|
|
XAudioInitializeSystem();
|
|
}
|
|
|
|
uint32_t LdrLoadModule(const std::filesystem::path &path)
|
|
{
|
|
auto loadResult = LoadFile(path);
|
|
if (loadResult.empty())
|
|
{
|
|
assert("Failed to load module" && false);
|
|
return 0;
|
|
}
|
|
|
|
auto* header = reinterpret_cast<const Xex2Header*>(loadResult.data());
|
|
auto* security = reinterpret_cast<const Xex2SecurityInfo*>(loadResult.data() + header->securityOffset);
|
|
const auto* fileFormatInfo = reinterpret_cast<const Xex2OptFileFormatInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_FILE_FORMAT_INFO));
|
|
auto entry = *reinterpret_cast<const uint32_t*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_ENTRY_POINT));
|
|
ByteSwapInplace(entry);
|
|
|
|
auto srcData = loadResult.data() + header->headerSize;
|
|
auto destData = reinterpret_cast<uint8_t*>(g_memory.Translate(security->loadAddress));
|
|
|
|
if (fileFormatInfo->compressionType == XEX_COMPRESSION_NONE)
|
|
{
|
|
memcpy(destData, srcData, security->imageSize);
|
|
}
|
|
else if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC)
|
|
{
|
|
auto* blocks = reinterpret_cast<const Xex2FileBasicCompressionBlock*>(fileFormatInfo + 1);
|
|
const size_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionInfo)) - 1;
|
|
|
|
for (size_t i = 0; i < numBlocks; i++)
|
|
{
|
|
memcpy(destData, srcData, blocks[i].dataSize);
|
|
|
|
srcData += blocks[i].dataSize;
|
|
destData += blocks[i].dataSize;
|
|
|
|
memset(destData, 0, blocks[i].zeroSize);
|
|
destData += blocks[i].zeroSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(false && "Unknown compression type.");
|
|
}
|
|
|
|
auto res = reinterpret_cast<const Xex2ResourceInfo*>(getOptHeaderPtr(loadResult.data(), XEX_HEADER_RESOURCE_INFO));
|
|
|
|
g_xdbfWrapper = XDBFWrapper((uint8_t*)g_memory.Translate(res->offset.get()), res->sizeOfData);
|
|
|
|
return entry;
|
|
}
|
|
|
|
__attribute__((constructor(101), target("no-avx,no-avx2"), noinline))
|
|
void init()
|
|
{
|
|
#ifdef __x86_64__
|
|
uint32_t eax, ebx, ecx, edx;
|
|
|
|
// Execute CPUID for processor info and feature bits.
|
|
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
|
|
|
|
// Check for AVX support.
|
|
if ((ecx & (1 << 28)) == 0)
|
|
{
|
|
printf("[*] CPU does not support the AVX instruction set.\n");
|
|
|
|
#ifdef _WIN32
|
|
MessageBoxA(nullptr, "Your CPU does not meet the minimum system requirements.", "Unleashed Recompiled", MB_ICONERROR);
|
|
#endif
|
|
|
|
std::_Exit(1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#ifdef _WIN32
|
|
timeBeginPeriod(1);
|
|
#endif
|
|
|
|
os::process::CheckConsole();
|
|
|
|
if (!os::registry::Init())
|
|
LOGN_WARNING("OS does not support registry.");
|
|
|
|
os::logger::Init();
|
|
|
|
PreloadContext preloadContext;
|
|
preloadContext.PreloadExecutable();
|
|
|
|
bool forceInstaller = false;
|
|
bool forceDLCInstaller = false;
|
|
const char *sdlVideoDriver = nullptr;
|
|
|
|
for (uint32_t i = 1; i < argc; i++)
|
|
{
|
|
forceInstaller = forceInstaller || (strcmp(argv[i], "--install") == 0);
|
|
forceDLCInstaller = forceDLCInstaller || (strcmp(argv[i], "--install-dlc") == 0);
|
|
|
|
if (strcmp(argv[i], "--sdl-video-driver") == 0)
|
|
{
|
|
if ((i + 1) < argc)
|
|
sdlVideoDriver = argv[++i];
|
|
else
|
|
LOGN_WARNING("No argument was specified for --sdl-video-driver. Option will be ignored.");
|
|
}
|
|
}
|
|
|
|
Config::Load();
|
|
|
|
#if defined(_WIN32) && defined(UNLEASHED_RECOMP_D3D12)
|
|
for (auto& dll : g_D3D12RequiredModules)
|
|
{
|
|
if (!std::filesystem::exists(g_executableRoot / dll))
|
|
{
|
|
char text[512];
|
|
snprintf(text, sizeof(text), Localise("System_Win32_MissingDLLs").c_str(), dll.data());
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), text, GameWindow::s_pWindow);
|
|
std::_Exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Check the time since the last time an update was checked. Store the new time if the difference is more than six hours.
|
|
constexpr double TimeBetweenUpdateChecksInSeconds = 6 * 60 * 60;
|
|
time_t timeNow = std::time(nullptr);
|
|
double timeDifferenceSeconds = difftime(timeNow, Config::LastChecked);
|
|
if (timeDifferenceSeconds > TimeBetweenUpdateChecksInSeconds)
|
|
{
|
|
UpdateChecker::initialize();
|
|
UpdateChecker::start();
|
|
Config::LastChecked = timeNow;
|
|
Config::Save();
|
|
}
|
|
|
|
if (Config::ShowConsole)
|
|
os::process::ShowConsole();
|
|
|
|
HostStartup();
|
|
|
|
std::filesystem::path modulePath;
|
|
bool isGameInstalled = Installer::checkGameInstall(GAME_INSTALL_DIRECTORY, modulePath);
|
|
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
|
|
if (runInstallerWizard)
|
|
{
|
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
|
{
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
|
std::_Exit(1);
|
|
}
|
|
|
|
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
|
|
{
|
|
std::_Exit(0);
|
|
}
|
|
}
|
|
|
|
ModLoader::Init();
|
|
|
|
KiSystemStartup();
|
|
|
|
uint32_t entry = LdrLoadModule(modulePath);
|
|
|
|
if (!runInstallerWizard)
|
|
{
|
|
if (!Video::CreateHostDevice(sdlVideoDriver))
|
|
{
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
|
|
std::_Exit(1);
|
|
}
|
|
}
|
|
|
|
Video::StartPipelinePrecompilation();
|
|
|
|
GuestThread::Start({ entry, 0, 0 });
|
|
|
|
return 0;
|
|
}
|
|
|
|
GUEST_FUNCTION_STUB(__imp__vsprintf);
|
|
GUEST_FUNCTION_STUB(__imp___vsnprintf);
|
|
GUEST_FUNCTION_STUB(__imp__sprintf);
|
|
GUEST_FUNCTION_STUB(__imp___snprintf);
|
|
GUEST_FUNCTION_STUB(__imp___snwprintf);
|
|
GUEST_FUNCTION_STUB(__imp__vswprintf);
|
|
GUEST_FUNCTION_STUB(__imp___vscwprintf);
|
|
GUEST_FUNCTION_STUB(__imp__swprintf);
|