2024-06-10 12:18:42 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
2024-07-31 10:25:55 +00:00
|
|
|
#include <fmt/core.h>
|
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "common/config.h"
|
2024-06-11 10:14:33 +00:00
|
|
|
#include "common/debug.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "common/logging/backend.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
#include "common/logging/log.h"
|
Cheats/Patches (#493)
* Cheats/Patches
Adds the possibility of applying cheats/patches according to the specific game serial+version
The logic for adding modifications has not yet been implemented!
Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372
[X]Front-end
[]Back-end
Create a synchronized fork of the cheats/patches repository
* Clang Format
* separate files
The code has been separated into separate files as suggested by georgemoralis.
Added the Patch tab, which has not been implemented yet.
Added the 'applyCheat' area to apply the modification, not implemented yet...
And added LOG_INFO.
* reuse
* initial implementation of cheat functionality
* Update cheats_patches.cpp
sets all added buttons to the size of the largest button.
and fixes some aesthetic issues.
* move eboot_address to module.h
fixes the non-qt builds and makes more sense to be there anyway
* Patchs menu and fixes
adds the possibility to download Patches, it does not modify the memory yet.
and some other fixes
* MemoryPatcher namespace, activate cheats on start
* format
* initial patch implementation
* format
* format again...
* convertValueToHex
* Fixes
Choosing which cheat file to use.
And some other fixes
* fix bytes16, bytes32, bytes64 type patches
If a patch is any of these types we convert it from little endian to big endian
* format
* format again :(
* Implement pattern scanning for mask type patches
* add check to stop patches applying to wrong game
previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed
* format
* Fix 'Hint' 0x400000 | and Author
* Management |save checkbox | shadps4 repository
MENU - Cheats/Patches Management (implementing Patches)
save patches checkbox
add shadps4 repository
* Load saved patches, miscellaneous fixes
* Fix an issue with mask patches not being saved
* format + remove debug log
* multiple patches | TR translation for cheats/patches
* clang
* ENABLE_QT_GUI
* OK
* move memory_patcher to qt_gui
* clang
* add cheats hu_HU
* fix log
* Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version)
---------
Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
|
|
|
#ifdef ENABLE_QT_GUI
|
2024-10-09 10:30:51 +00:00
|
|
|
#include <QtCore>
|
2024-09-13 04:44:20 +00:00
|
|
|
#include "common/memory_patcher.h"
|
Cheats/Patches (#493)
* Cheats/Patches
Adds the possibility of applying cheats/patches according to the specific game serial+version
The logic for adding modifications has not yet been implemented!
Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372
[X]Front-end
[]Back-end
Create a synchronized fork of the cheats/patches repository
* Clang Format
* separate files
The code has been separated into separate files as suggested by georgemoralis.
Added the Patch tab, which has not been implemented yet.
Added the 'applyCheat' area to apply the modification, not implemented yet...
And added LOG_INFO.
* reuse
* initial implementation of cheat functionality
* Update cheats_patches.cpp
sets all added buttons to the size of the largest button.
and fixes some aesthetic issues.
* move eboot_address to module.h
fixes the non-qt builds and makes more sense to be there anyway
* Patchs menu and fixes
adds the possibility to download Patches, it does not modify the memory yet.
and some other fixes
* MemoryPatcher namespace, activate cheats on start
* format
* initial patch implementation
* format
* format again...
* convertValueToHex
* Fixes
Choosing which cheat file to use.
And some other fixes
* fix bytes16, bytes32, bytes64 type patches
If a patch is any of these types we convert it from little endian to big endian
* format
* format again :(
* Implement pattern scanning for mask type patches
* add check to stop patches applying to wrong game
previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed
* format
* Fix 'Hint' 0x400000 | and Author
* Management |save checkbox | shadps4 repository
MENU - Cheats/Patches Management (implementing Patches)
save patches checkbox
add shadps4 repository
* Load saved patches, miscellaneous fixes
* Fix an issue with mask patches not being saved
* format + remove debug log
* multiple patches | TR translation for cheats/patches
* clang
* ENABLE_QT_GUI
* OK
* move memory_patcher to qt_gui
* clang
* add cheats hu_HU
* fix log
* Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version)
---------
Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
|
|
|
#endif
|
2024-09-20 09:34:19 +00:00
|
|
|
#include "common/assert.h"
|
2024-10-19 13:09:36 +00:00
|
|
|
#ifdef ENABLE_DISCORD_RPC
|
2024-10-08 15:14:37 +00:00
|
|
|
#include "common/discord_rpc_handler.h"
|
2024-10-19 13:09:36 +00:00
|
|
|
#endif
|
2024-09-23 11:50:49 +00:00
|
|
|
#include "common/elf_info.h"
|
2024-07-11 12:35:58 +00:00
|
|
|
#include "common/ntapi.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "common/path_util.h"
|
2024-07-09 09:18:34 +00:00
|
|
|
#include "common/polyfill_thread.h"
|
2024-08-15 09:33:10 +00:00
|
|
|
#include "common/scm_rev.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "common/singleton.h"
|
2024-07-04 11:30:34 +00:00
|
|
|
#include "common/version.h"
|
2024-07-31 10:25:55 +00:00
|
|
|
#include "core/file_format/playgo_chunk.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
#include "core/file_format/psf.h"
|
|
|
|
#include "core/file_format/splash.h"
|
2024-09-11 03:50:55 +00:00
|
|
|
#include "core/file_format/trp.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "core/file_sys/fs.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
#include "core/libraries/disc_map/disc_map.h"
|
2024-10-10 14:51:23 +00:00
|
|
|
#include "core/libraries/fiber/fiber.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
#include "core/libraries/libc_internal/libc_internal.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "core/libraries/libs.h"
|
2024-08-19 07:03:05 +00:00
|
|
|
#include "core/libraries/ngs2/ngs2.h"
|
2024-09-11 03:50:55 +00:00
|
|
|
#include "core/libraries/np_trophy/np_trophy.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
#include "core/libraries/rtc/rtc.h"
|
2024-06-10 12:18:42 +00:00
|
|
|
#include "core/linker.h"
|
|
|
|
#include "core/memory.h"
|
|
|
|
#include "emulator.h"
|
2024-07-31 22:11:58 +00:00
|
|
|
#include "video_core/renderdoc.h"
|
2024-07-28 13:54:09 +00:00
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
Frontend::WindowSDL* g_window = nullptr;
|
|
|
|
|
|
|
|
namespace Core {
|
|
|
|
|
2024-07-15 21:22:47 +00:00
|
|
|
Emulator::Emulator() {
|
2024-06-10 12:18:42 +00:00
|
|
|
// Read configuration file.
|
|
|
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
|
|
Config::load(config_dir / "config.toml");
|
|
|
|
|
2024-09-20 04:54:30 +00:00
|
|
|
// Initialize NT API functions and set high priority
|
2024-07-11 13:29:36 +00:00
|
|
|
#ifdef _WIN32
|
2024-07-11 12:35:58 +00:00
|
|
|
Common::NtApi::Initialize();
|
2024-09-20 04:54:30 +00:00
|
|
|
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
|
2024-07-11 13:29:36 +00:00
|
|
|
#endif
|
2024-07-11 12:35:58 +00:00
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
// Start logger.
|
|
|
|
Common::Log::Initialize();
|
|
|
|
Common::Log::Start();
|
2024-07-04 11:30:34 +00:00
|
|
|
LOG_INFO(Loader, "Starting shadps4 emulator v{} ", Common::VERSION);
|
2024-07-31 22:11:58 +00:00
|
|
|
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
|
|
|
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
|
|
|
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
2024-07-15 21:22:47 +00:00
|
|
|
|
2024-10-06 11:53:53 +00:00
|
|
|
LOG_INFO(Config, "General Logtype: {}", Config::getLogType());
|
2024-08-21 22:52:08 +00:00
|
|
|
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
|
|
|
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
|
|
|
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
|
|
|
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
|
|
|
LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId());
|
|
|
|
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
|
|
|
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
|
|
|
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
|
|
|
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
2024-09-03 19:56:23 +00:00
|
|
|
LOG_INFO(Config, "Vulkan rdocMarkersEnable: {}", Config::vkMarkersEnabled());
|
|
|
|
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());
|
2024-08-21 22:52:08 +00:00
|
|
|
|
2024-07-15 21:22:47 +00:00
|
|
|
// Defer until after logging is initialized.
|
|
|
|
memory = Core::Memory::Instance();
|
|
|
|
controller = Common::Singleton<Input::GameController>::Instance();
|
|
|
|
linker = Common::Singleton<Core::Linker>::Instance();
|
2024-07-28 13:54:09 +00:00
|
|
|
|
|
|
|
// Load renderdoc module.
|
|
|
|
VideoCore::LoadRenderDoc();
|
2024-10-09 10:30:51 +00:00
|
|
|
|
|
|
|
// Start the timer (Play Time)
|
|
|
|
#ifdef ENABLE_QT_GUI
|
|
|
|
start_time = std::chrono::steady_clock::now();
|
|
|
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
|
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
|
|
|
QFile file(filePath);
|
|
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
|
|
|
LOG_INFO(Loader, "Error opening or creating play_time.txt");
|
|
|
|
}
|
|
|
|
#endif
|
2024-06-10 12:18:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Emulator::~Emulator() {
|
|
|
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
|
|
Config::save(config_dir / "config.toml");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Emulator::Run(const std::filesystem::path& file) {
|
2024-10-17 08:49:29 +00:00
|
|
|
|
|
|
|
// Use the eboot from the separated updates folder if it's there
|
|
|
|
std::filesystem::path game_patch_folder = file.parent_path().concat("-UPDATE");
|
|
|
|
bool use_game_patch = std::filesystem::exists(game_patch_folder / "sce_sys");
|
|
|
|
std::filesystem::path eboot_path = use_game_patch ? game_patch_folder / file.filename() : file;
|
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
|
|
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
|
|
|
mnt->Mount(file.parent_path(), "/app0");
|
2024-08-29 12:22:19 +00:00
|
|
|
// Certain games may use /hostapp as well such as CUSA001100
|
|
|
|
mnt->Mount(file.parent_path(), "/hostapp");
|
2024-06-10 12:18:42 +00:00
|
|
|
|
2024-09-23 11:50:49 +00:00
|
|
|
auto& game_info = Common::ElfInfo::Instance();
|
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
// Loading param.sfo file if exists
|
2024-06-15 14:51:51 +00:00
|
|
|
std::string id;
|
2024-07-24 06:12:53 +00:00
|
|
|
std::string title;
|
|
|
|
std::string app_version;
|
2024-09-23 11:50:49 +00:00
|
|
|
u32 fw_version;
|
|
|
|
|
2024-10-17 08:49:29 +00:00
|
|
|
std::filesystem::path sce_sys_folder = eboot_path.parent_path() / "sce_sys";
|
2024-06-10 12:18:42 +00:00
|
|
|
if (std::filesystem::is_directory(sce_sys_folder)) {
|
|
|
|
for (const auto& entry : std::filesystem::directory_iterator(sce_sys_folder)) {
|
|
|
|
if (entry.path().filename() == "param.sfo") {
|
|
|
|
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
2024-09-20 09:34:19 +00:00
|
|
|
const bool success = param_sfo->Open(sce_sys_folder / "param.sfo");
|
|
|
|
ASSERT_MSG(success, "Failed to open param.sfo");
|
2024-09-22 05:16:06 +00:00
|
|
|
const auto content_id = param_sfo->GetString("CONTENT_ID");
|
|
|
|
ASSERT_MSG(content_id.has_value(), "Failed to get CONTENT_ID");
|
|
|
|
id = std::string(*content_id, 7, 9);
|
2024-09-11 03:50:55 +00:00
|
|
|
Libraries::NpTrophy::game_serial = id;
|
|
|
|
const auto trophyDir =
|
|
|
|
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) / id / "TrophyFiles";
|
|
|
|
if (!std::filesystem::exists(trophyDir)) {
|
|
|
|
TRP trp;
|
2024-10-17 08:49:29 +00:00
|
|
|
if (!trp.Extract(eboot_path.parent_path(), id)) {
|
2024-09-11 03:50:55 +00:00
|
|
|
LOG_ERROR(Loader, "Couldn't extract trophies");
|
|
|
|
}
|
|
|
|
}
|
Cheats/Patches (#493)
* Cheats/Patches
Adds the possibility of applying cheats/patches according to the specific game serial+version
The logic for adding modifications has not yet been implemented!
Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372
[X]Front-end
[]Back-end
Create a synchronized fork of the cheats/patches repository
* Clang Format
* separate files
The code has been separated into separate files as suggested by georgemoralis.
Added the Patch tab, which has not been implemented yet.
Added the 'applyCheat' area to apply the modification, not implemented yet...
And added LOG_INFO.
* reuse
* initial implementation of cheat functionality
* Update cheats_patches.cpp
sets all added buttons to the size of the largest button.
and fixes some aesthetic issues.
* move eboot_address to module.h
fixes the non-qt builds and makes more sense to be there anyway
* Patchs menu and fixes
adds the possibility to download Patches, it does not modify the memory yet.
and some other fixes
* MemoryPatcher namespace, activate cheats on start
* format
* initial patch implementation
* format
* format again...
* convertValueToHex
* Fixes
Choosing which cheat file to use.
And some other fixes
* fix bytes16, bytes32, bytes64 type patches
If a patch is any of these types we convert it from little endian to big endian
* format
* format again :(
* Implement pattern scanning for mask type patches
* add check to stop patches applying to wrong game
previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed
* format
* Fix 'Hint' 0x400000 | and Author
* Management |save checkbox | shadps4 repository
MENU - Cheats/Patches Management (implementing Patches)
save patches checkbox
add shadps4 repository
* Load saved patches, miscellaneous fixes
* Fix an issue with mask patches not being saved
* format + remove debug log
* multiple patches | TR translation for cheats/patches
* clang
* ENABLE_QT_GUI
* OK
* move memory_patcher to qt_gui
* clang
* add cheats hu_HU
* fix log
* Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version)
---------
Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
|
|
|
#ifdef ENABLE_QT_GUI
|
|
|
|
MemoryPatcher::g_game_serial = id;
|
2024-10-09 10:30:51 +00:00
|
|
|
|
|
|
|
// Timer for 'Play Time'
|
|
|
|
QTimer* timer = new QTimer();
|
|
|
|
QObject::connect(timer, &QTimer::timeout, [this, id]() {
|
|
|
|
UpdatePlayTime(id);
|
|
|
|
start_time = std::chrono::steady_clock::now();
|
|
|
|
});
|
|
|
|
timer->start(60000); // 60000 ms = 1 minute
|
Cheats/Patches (#493)
* Cheats/Patches
Adds the possibility of applying cheats/patches according to the specific game serial+version
The logic for adding modifications has not yet been implemented!
Interface based on issues/372 https://github.com/shadps4-emu/shadPS4/issues/372
[X]Front-end
[]Back-end
Create a synchronized fork of the cheats/patches repository
* Clang Format
* separate files
The code has been separated into separate files as suggested by georgemoralis.
Added the Patch tab, which has not been implemented yet.
Added the 'applyCheat' area to apply the modification, not implemented yet...
And added LOG_INFO.
* reuse
* initial implementation of cheat functionality
* Update cheats_patches.cpp
sets all added buttons to the size of the largest button.
and fixes some aesthetic issues.
* move eboot_address to module.h
fixes the non-qt builds and makes more sense to be there anyway
* Patchs menu and fixes
adds the possibility to download Patches, it does not modify the memory yet.
and some other fixes
* MemoryPatcher namespace, activate cheats on start
* format
* initial patch implementation
* format
* format again...
* convertValueToHex
* Fixes
Choosing which cheat file to use.
And some other fixes
* fix bytes16, bytes32, bytes64 type patches
If a patch is any of these types we convert it from little endian to big endian
* format
* format again :(
* Implement pattern scanning for mask type patches
* add check to stop patches applying to wrong game
previously if you added a patch to a game, but closed the window and opened a different game it would still try to apply the patch, this is now fixed
* format
* Fix 'Hint' 0x400000 | and Author
* Management |save checkbox | shadps4 repository
MENU - Cheats/Patches Management (implementing Patches)
save patches checkbox
add shadps4 repository
* Load saved patches, miscellaneous fixes
* Fix an issue with mask patches not being saved
* format + remove debug log
* multiple patches | TR translation for cheats/patches
* clang
* ENABLE_QT_GUI
* OK
* move memory_patcher to qt_gui
* clang
* add cheats hu_HU
* fix log
* Remove the item from the patchesListView if no patches were added (the game has patches, but not for the current version)
---------
Co-authored-by: CrazyBloo <CrazyBloo@users.noreply.github.com>
2024-08-29 04:18:50 +00:00
|
|
|
#endif
|
2024-09-22 05:16:06 +00:00
|
|
|
title = param_sfo->GetString("TITLE").value_or("Unknown title");
|
2024-06-10 12:18:42 +00:00
|
|
|
LOG_INFO(Loader, "Game id: {} Title: {}", id, title);
|
2024-09-23 11:50:49 +00:00
|
|
|
fw_version = param_sfo->GetInteger("SYSTEM_VER").value_or(0x4700000);
|
2024-09-22 05:16:06 +00:00
|
|
|
app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
2024-06-10 12:18:42 +00:00
|
|
|
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
2024-07-24 16:02:38 +00:00
|
|
|
} else if (entry.path().filename() == "playgo-chunk.dat") {
|
2024-08-19 11:14:14 +00:00
|
|
|
auto* playgo = Common::Singleton<PlaygoFile>::Instance();
|
|
|
|
auto filepath = sce_sys_folder / "playgo-chunk.dat";
|
|
|
|
if (!playgo->Open(filepath)) {
|
|
|
|
LOG_ERROR(Loader, "PlayGo: unable to open file");
|
|
|
|
}
|
2024-11-22 20:20:47 +00:00
|
|
|
} else if (entry.path().filename() == "pic1.png") {
|
2024-06-10 12:18:42 +00:00
|
|
|
auto* splash = Common::Singleton<Splash>::Instance();
|
|
|
|
if (splash->IsLoaded()) {
|
|
|
|
continue;
|
|
|
|
}
|
2024-09-26 08:41:59 +00:00
|
|
|
if (!splash->Open(entry.path())) {
|
2024-06-10 12:18:42 +00:00
|
|
|
LOG_ERROR(Loader, "Game splash: unable to open file");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-31 22:11:58 +00:00
|
|
|
|
2024-09-23 11:50:49 +00:00
|
|
|
game_info.initialized = true;
|
|
|
|
game_info.game_serial = id;
|
|
|
|
game_info.title = title;
|
|
|
|
game_info.app_ver = app_version;
|
|
|
|
game_info.firmware_ver = fw_version & 0xFFF00000;
|
|
|
|
game_info.raw_firmware_ver = fw_version;
|
|
|
|
|
2024-07-25 07:13:14 +00:00
|
|
|
std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version);
|
2024-07-31 22:11:58 +00:00
|
|
|
std::string window_title = "";
|
|
|
|
if (Common::isRelease) {
|
|
|
|
window_title = fmt::format("shadPS4 v{} | {}", Common::VERSION, game_title);
|
|
|
|
} else {
|
2024-09-19 15:46:07 +00:00
|
|
|
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::VERSION, Common::g_scm_branch,
|
|
|
|
Common::g_scm_desc, game_title);
|
2024-07-31 22:11:58 +00:00
|
|
|
}
|
2024-08-20 12:39:56 +00:00
|
|
|
window = std::make_unique<Frontend::WindowSDL>(
|
|
|
|
Config::getScreenWidth(), Config::getScreenHeight(), controller, window_title);
|
2024-09-11 09:56:27 +00:00
|
|
|
|
2024-07-24 06:12:53 +00:00
|
|
|
g_window = window.get();
|
2024-06-10 12:18:42 +00:00
|
|
|
|
2024-06-15 14:51:51 +00:00
|
|
|
const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id;
|
|
|
|
if (!std::filesystem::exists(mount_data_dir)) {
|
|
|
|
std::filesystem::create_directory(mount_data_dir);
|
|
|
|
}
|
|
|
|
mnt->Mount(mount_data_dir, "/data"); // should just exist, manually create with game serial
|
|
|
|
const auto& mount_temp_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
|
2024-07-04 07:51:46 +00:00
|
|
|
if (!std::filesystem::exists(mount_temp_dir)) {
|
|
|
|
std::filesystem::create_directory(mount_temp_dir);
|
|
|
|
}
|
2024-06-15 14:51:51 +00:00
|
|
|
mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir
|
2024-08-09 09:56:03 +00:00
|
|
|
mnt->Mount(mount_temp_dir, "/temp");
|
2024-06-15 14:51:51 +00:00
|
|
|
|
2024-07-26 14:07:22 +00:00
|
|
|
const auto& mount_download_dir =
|
|
|
|
Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id;
|
|
|
|
if (!std::filesystem::exists(mount_download_dir)) {
|
|
|
|
std::filesystem::create_directory(mount_download_dir);
|
|
|
|
}
|
|
|
|
mnt->Mount(mount_download_dir, "/download0");
|
|
|
|
|
2024-07-28 13:54:09 +00:00
|
|
|
const auto& mount_captures_dir = Common::FS::GetUserPath(Common::FS::PathType::CapturesDir);
|
|
|
|
if (!std::filesystem::exists(mount_captures_dir)) {
|
|
|
|
std::filesystem::create_directory(mount_captures_dir);
|
|
|
|
}
|
2024-09-26 08:41:59 +00:00
|
|
|
VideoCore::SetOutputDir(mount_captures_dir, id);
|
2024-07-28 13:54:09 +00:00
|
|
|
|
2024-06-30 16:22:39 +00:00
|
|
|
// Initialize kernel and library facilities.
|
|
|
|
Libraries::InitHLELibs(&linker->GetHLESymbols());
|
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
// Load the module with the linker
|
2024-10-17 08:49:29 +00:00
|
|
|
linker->LoadModule(eboot_path);
|
2024-06-10 12:18:42 +00:00
|
|
|
|
|
|
|
// check if we have system modules to load
|
2024-10-31 14:08:34 +00:00
|
|
|
LoadSystemModules(eboot_path, game_info.game_serial);
|
2024-06-10 15:26:37 +00:00
|
|
|
|
2024-08-22 08:24:31 +00:00
|
|
|
// Load all prx from game's sce_module folder
|
|
|
|
std::filesystem::path sce_module_folder = file.parent_path() / "sce_module";
|
|
|
|
if (std::filesystem::is_directory(sce_module_folder)) {
|
|
|
|
for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) {
|
2024-10-17 08:49:29 +00:00
|
|
|
std::filesystem::path module_path = entry.path();
|
|
|
|
std::filesystem::path update_module_path =
|
|
|
|
eboot_path.parent_path() / "sce_module" / entry.path().filename();
|
|
|
|
if (std::filesystem::exists(update_module_path) && use_game_patch) {
|
|
|
|
module_path = update_module_path;
|
|
|
|
}
|
|
|
|
LOG_INFO(Loader, "Loading {}", fmt::UTF(module_path.u8string()));
|
|
|
|
linker->LoadModule(module_path);
|
2024-06-10 12:18:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-19 13:09:36 +00:00
|
|
|
#ifdef ENABLE_DISCORD_RPC
|
2024-10-08 15:14:37 +00:00
|
|
|
// Discord RPC
|
|
|
|
if (Config::getEnableDiscordRPC()) {
|
|
|
|
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
|
|
|
if (rpc->getRPCEnabled() == false) {
|
|
|
|
rpc->init();
|
|
|
|
}
|
|
|
|
rpc->setStatusPlaying(game_info.title, id);
|
|
|
|
}
|
2024-10-19 13:09:36 +00:00
|
|
|
#endif
|
2024-10-08 15:14:37 +00:00
|
|
|
|
2024-11-21 20:59:38 +00:00
|
|
|
linker->Execute();
|
2024-06-10 12:18:42 +00:00
|
|
|
|
2024-10-19 12:57:01 +00:00
|
|
|
window->initTimers();
|
2024-07-15 21:22:47 +00:00
|
|
|
while (window->isOpen()) {
|
|
|
|
window->waitEvent();
|
2024-06-10 12:18:42 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 10:30:51 +00:00
|
|
|
#ifdef ENABLE_QT_GUI
|
|
|
|
UpdatePlayTime(id);
|
|
|
|
#endif
|
|
|
|
|
2024-06-10 12:18:42 +00:00
|
|
|
std::exit(0);
|
|
|
|
}
|
|
|
|
|
2024-10-31 14:08:34 +00:00
|
|
|
void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) {
|
2024-11-06 05:20:58 +00:00
|
|
|
constexpr std::array<SysModules, 11> ModulesToLoad{
|
2024-08-19 07:03:05 +00:00
|
|
|
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
|
2024-10-10 14:51:23 +00:00
|
|
|
{"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber},
|
2024-07-17 12:44:20 +00:00
|
|
|
{"libSceUlt.sprx", nullptr},
|
2024-07-25 20:01:12 +00:00
|
|
|
{"libSceJson.sprx", nullptr},
|
|
|
|
{"libSceJson2.sprx", nullptr},
|
2024-06-26 11:43:01 +00:00
|
|
|
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
|
|
|
|
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
|
2024-06-30 07:12:36 +00:00
|
|
|
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
|
2024-09-06 21:14:51 +00:00
|
|
|
{"libSceJpegEnc.sprx", nullptr},
|
2024-09-11 13:48:16 +00:00
|
|
|
{"libSceRazorCpu.sprx", nullptr},
|
2024-11-06 05:20:58 +00:00
|
|
|
{"libSceCesCs.sprx", nullptr}}};
|
2024-06-26 11:43:01 +00:00
|
|
|
|
|
|
|
std::vector<std::filesystem::path> found_modules;
|
2024-06-10 15:26:37 +00:00
|
|
|
const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
|
|
|
|
for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) {
|
2024-06-26 11:43:01 +00:00
|
|
|
found_modules.push_back(entry.path());
|
|
|
|
}
|
2024-07-17 12:37:32 +00:00
|
|
|
for (const auto& [module_name, init_func] : ModulesToLoad) {
|
2024-07-17 14:57:54 +00:00
|
|
|
const auto it = std::ranges::find_if(
|
|
|
|
found_modules, [&](const auto& path) { return path.filename() == module_name; });
|
2024-07-17 12:37:32 +00:00
|
|
|
if (it != found_modules.end()) {
|
|
|
|
LOG_INFO(Loader, "Loading {}", it->string());
|
|
|
|
linker->LoadModule(*it);
|
|
|
|
continue;
|
2024-06-26 11:43:01 +00:00
|
|
|
}
|
2024-07-17 12:37:32 +00:00
|
|
|
if (init_func) {
|
|
|
|
LOG_INFO(Loader, "Can't Load {} switching to HLE", module_name);
|
|
|
|
init_func(&linker->GetHLESymbols());
|
2024-06-26 11:43:01 +00:00
|
|
|
} else {
|
2024-07-17 12:37:32 +00:00
|
|
|
LOG_INFO(Loader, "No HLE available for {} module", module_name);
|
2024-06-10 15:26:37 +00:00
|
|
|
}
|
|
|
|
}
|
2024-10-31 15:05:44 +00:00
|
|
|
if (std::filesystem::exists(sys_module_path / game_serial)) {
|
|
|
|
for (const auto& entry :
|
|
|
|
std::filesystem::directory_iterator(sys_module_path / game_serial)) {
|
|
|
|
LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(),
|
|
|
|
game_serial);
|
|
|
|
linker->LoadModule(entry.path());
|
|
|
|
}
|
2024-10-31 14:08:34 +00:00
|
|
|
}
|
2024-06-10 15:26:37 +00:00
|
|
|
}
|
|
|
|
|
2024-10-09 10:30:51 +00:00
|
|
|
#ifdef ENABLE_QT_GUI
|
|
|
|
void Emulator::UpdatePlayTime(const std::string& serial) {
|
|
|
|
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
|
|
|
QString filePath = QString::fromStdString((user_dir / "play_time.txt").string());
|
|
|
|
|
|
|
|
QFile file(filePath);
|
|
|
|
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
|
|
|
LOG_INFO(Loader, "Error opening play_time.txt");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto end_time = std::chrono::steady_clock::now();
|
|
|
|
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time);
|
|
|
|
int totalSeconds = duration.count();
|
|
|
|
|
|
|
|
QTextStream in(&file);
|
|
|
|
QStringList lines;
|
|
|
|
QString content;
|
|
|
|
while (!in.atEnd()) {
|
|
|
|
content += in.readLine() + "\n";
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
QStringList existingLines = content.split('\n', Qt::SkipEmptyParts);
|
|
|
|
int accumulatedSeconds = 0;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for (const QString& line : existingLines) {
|
|
|
|
QStringList parts = line.split(' ');
|
|
|
|
if (parts.size() == 2 && parts[0] == QString::fromStdString(serial)) {
|
|
|
|
QStringList timeParts = parts[1].split(':');
|
|
|
|
if (timeParts.size() == 3) {
|
|
|
|
int hours = timeParts[0].toInt();
|
|
|
|
int minutes = timeParts[1].toInt();
|
|
|
|
int seconds = timeParts[2].toInt();
|
|
|
|
accumulatedSeconds = hours * 3600 + minutes * 60 + seconds;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
accumulatedSeconds += totalSeconds;
|
|
|
|
int hours = accumulatedSeconds / 3600;
|
|
|
|
int minutes = (accumulatedSeconds % 3600) / 60;
|
|
|
|
int seconds = accumulatedSeconds % 60;
|
|
|
|
QString playTimeSaved = QString::number(hours) + ":" +
|
|
|
|
QString::number(minutes).rightJustified(2, '0') + ":" +
|
|
|
|
QString::number(seconds).rightJustified(2, '0');
|
|
|
|
|
|
|
|
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
|
|
QTextStream out(&file);
|
|
|
|
bool lineUpdated = false;
|
|
|
|
|
|
|
|
for (const QString& line : existingLines) {
|
|
|
|
if (line.startsWith(QString::fromStdString(serial))) {
|
|
|
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
|
|
|
lineUpdated = true;
|
|
|
|
} else {
|
|
|
|
out << line << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!lineUpdated) {
|
|
|
|
out << QString::fromStdString(serial) + " " + playTimeSaved + "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_INFO(Loader, "Playing time for {}: {}", serial, playTimeSaved.toStdString());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-06-13 21:58:57 +00:00
|
|
|
} // namespace Core
|