mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-24 19:52:37 +01:00
Added installation for additional packages to game boot
This commit is contained in:
parent
8901cc9ae6
commit
6702c14b88
@ -24,6 +24,12 @@ inline void strcpy_trunc(char (&dst)[N], const char (&src)[N2])
|
||||
dst[count] = '\0';
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
inline bool ends_with(const std::string& src, const char (&end)[N])
|
||||
{
|
||||
return src.size() >= N - 1 && src.compare(src.size() - (N - 1), N - 1, end, N - 1) == 0;
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "../Crypto/unself.h"
|
||||
#include "../Crypto/unpkg.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
#include <thread>
|
||||
@ -212,6 +213,7 @@ void Emulator::Init()
|
||||
fs::create_dir(dev_hdd0 + "game/");
|
||||
fs::create_dir(dev_hdd0 + "game/TEST12345/");
|
||||
fs::create_dir(dev_hdd0 + "game/TEST12345/USRDIR/");
|
||||
fs::create_dir(dev_hdd0 + "game/.locks/");
|
||||
fs::create_dir(dev_hdd0 + "home/");
|
||||
fs::create_dir(dev_hdd0 + "home/00000001/");
|
||||
fs::create_dir(dev_hdd0 + "home/00000001/exdata/");
|
||||
@ -223,7 +225,7 @@ void Emulator::Init()
|
||||
fs::create_dir(dev_hdd1 + "game/");
|
||||
fs::create_path(dev_hdd1);
|
||||
fs::create_path(dev_usb);
|
||||
|
||||
|
||||
#ifdef WITH_GDB_DEBUGGER
|
||||
fxm::make<GDBDebugServer>();
|
||||
#endif
|
||||
@ -265,6 +267,51 @@ bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Emulator::InstallPkg(const std::string& path)
|
||||
{
|
||||
LOG_SUCCESS(GENERAL, "Installing package: %s", path);
|
||||
|
||||
atomic_t<double> progress(0.);
|
||||
int int_progress = 0;
|
||||
{
|
||||
// Run PKG unpacking asynchronously
|
||||
scope_thread worker("PKG Installer", [&]
|
||||
{
|
||||
if (pkg_install(path, progress))
|
||||
{
|
||||
progress = 1.;
|
||||
return;
|
||||
}
|
||||
|
||||
progress = -1.;
|
||||
});
|
||||
|
||||
// Wait for the completion
|
||||
while (std::this_thread::sleep_for(5ms), std::abs(progress) < 1.)
|
||||
{
|
||||
// TODO: update unified progress dialog
|
||||
double pval = progress;
|
||||
pval < 0 ? pval += 1. : pval;
|
||||
pval *= 100.;
|
||||
|
||||
if (static_cast<int>(pval) > int_progress)
|
||||
{
|
||||
int_progress = static_cast<int>(pval);
|
||||
LOG_SUCCESS(GENERAL, "... %u%%", int_progress);
|
||||
}
|
||||
|
||||
m_cb.process_events();
|
||||
}
|
||||
}
|
||||
|
||||
if (progress >= 1.)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Emulator::GetHddDir()
|
||||
{
|
||||
const std::string& emu_dir_ = g_cfg.vfs.emulator_dir;
|
||||
@ -297,7 +344,7 @@ void Emulator::Load(bool add_only)
|
||||
{
|
||||
Init();
|
||||
|
||||
// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations)
|
||||
// Load game list (maps ABCD12345 IDs to /dev_bdvd/ locations)
|
||||
YAML::Node games = YAML::Load(fs::file{fs::get_config_dir() + "/games.yml", fs::read + fs::create}.to_string());
|
||||
|
||||
if (!games.IsMap())
|
||||
@ -453,7 +500,8 @@ void Emulator::Load(bool add_only)
|
||||
}
|
||||
else if (!Emu.disc.empty())
|
||||
{
|
||||
vfs::mount("dev_bdvd", Emu.disc);
|
||||
bdvd_dir = Emu.disc;
|
||||
vfs::mount("dev_bdvd", bdvd_dir);
|
||||
LOG_NOTICE(LOADER, "Disk: %s", vfs::get("/dev_bdvd"));
|
||||
}
|
||||
else if (_cat == "DG" || _cat == "GD")
|
||||
@ -468,6 +516,73 @@ void Emulator::Load(bool add_only)
|
||||
return;
|
||||
}
|
||||
|
||||
// Install PKGDIR, INSDIR, PS3_EXTRA
|
||||
if (!bdvd_dir.empty())
|
||||
{
|
||||
const std::string ins_dir = vfs::get("/dev_bdvd/PS3_GAME/INSDIR/");
|
||||
const std::string pkg_dir = vfs::get("/dev_bdvd/PS3_GAME/PKGDIR/");
|
||||
const std::string extra_dir = vfs::get("/dev_bdvd/PS3_GAME/PS3_EXTRA/");
|
||||
fs::file lock_file;
|
||||
|
||||
if (fs::is_dir(ins_dir) || fs::is_dir(pkg_dir) || fs::is_dir(extra_dir))
|
||||
{
|
||||
// Create lock file to prevent double installation
|
||||
lock_file.open(hdd0_game + ".locks/" + m_title_id, fs::read + fs::create + fs::excl);
|
||||
}
|
||||
|
||||
if (lock_file && fs::is_dir(ins_dir))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Found INSDIR: %s", ins_dir);
|
||||
|
||||
for (auto&& entry : fs::dir{ins_dir})
|
||||
{
|
||||
if (!entry.is_directory && ends_with(entry.name, ".PKG") && !InstallPkg(ins_dir + entry.name))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to install /dev_bdvd/PS3_GAME/INSDIR/%s", entry.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lock_file && fs::is_dir(pkg_dir))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Found PKGDIR: %s", pkg_dir);
|
||||
|
||||
for (auto&& entry : fs::dir{pkg_dir})
|
||||
{
|
||||
if (entry.is_directory && entry.name.compare(0, 3, "PKG", 3) == 0)
|
||||
{
|
||||
const std::string pkg_file = pkg_dir + entry.name + "/INSTALL.PKG";
|
||||
|
||||
if (fs::is_file(pkg_file) && !InstallPkg(pkg_file))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to install /dev_bdvd/PS3_GAME/PKGDIR/%s/INSTALL.PKG", entry.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lock_file && fs::is_dir(extra_dir))
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Found PS3_EXTRA: %s", extra_dir);
|
||||
|
||||
for (auto&& entry : fs::dir{extra_dir})
|
||||
{
|
||||
if (entry.is_directory && entry.name[0] == 'D')
|
||||
{
|
||||
const std::string pkg_file = extra_dir + entry.name + "/DATA000.PKG";
|
||||
|
||||
if (fs::is_file(pkg_file) && !InstallPkg(pkg_file))
|
||||
{
|
||||
LOG_ERROR(LOADER, "Failed to install /dev_bdvd/PS3_GAME/PKGDIR/%s/DATA000.PKG", entry.name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check game updates
|
||||
const std::string hdd0_boot = hdd0_game + m_title_id + "/USRDIR/EBOOT.BIN";
|
||||
|
||||
|
@ -245,6 +245,7 @@ public:
|
||||
}
|
||||
|
||||
bool BootGame(const std::string& path, bool direct = false, bool add_only = false);
|
||||
bool InstallPkg(const std::string& path);
|
||||
|
||||
static std::string GetHddDir();
|
||||
static std::string GetLibDir();
|
||||
@ -372,7 +373,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_int<2, 128> frames{this, "Buffer Count", 32};
|
||||
|
||||
} audio{this};
|
||||
|
||||
|
||||
struct node_io : cfg::node
|
||||
{
|
||||
node_io(cfg::node* _this) : cfg::node(_this, "Input/Output") {}
|
||||
@ -384,7 +385,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_enum<fake_camera_type> camera_type{this, "Camera type", fake_camera_type::unknown};
|
||||
|
||||
} io{this};
|
||||
|
||||
|
||||
struct node_sys : cfg::node
|
||||
{
|
||||
node_sys(cfg::node* _this) : cfg::node(_this, "System") {}
|
||||
@ -392,7 +393,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_enum<CellSysutilLang> language{this, "Language"};
|
||||
|
||||
} sys{this};
|
||||
|
||||
|
||||
struct node_net : cfg::node
|
||||
{
|
||||
node_net(cfg::node* _this) : cfg::node(_this, "Net") {}
|
||||
@ -405,7 +406,7 @@ struct cfg_root : cfg::node
|
||||
struct node_misc : cfg::node
|
||||
{
|
||||
node_misc(cfg::node* _this) : cfg::node(_this, "Miscellaneous") {}
|
||||
|
||||
|
||||
cfg::_bool autostart{this, "Automatically start games after boot", true};
|
||||
cfg::_bool autoexit{this, "Exit RPCS3 when process finishes"};
|
||||
cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode" };
|
||||
|
@ -105,7 +105,7 @@ void rpcs3_app::InitializeCallbacks()
|
||||
quit();
|
||||
};
|
||||
callbacks.call_after = [=](std::function<void()> func)
|
||||
{
|
||||
{
|
||||
RequestCallAfter(std::move(func));
|
||||
};
|
||||
|
||||
@ -176,7 +176,7 @@ void rpcs3_app::InitializeCallbacks()
|
||||
gameWindow = ret;
|
||||
return std::unique_ptr<gs_frame>(ret);
|
||||
}
|
||||
case video_renderer::opengl:
|
||||
case video_renderer::opengl:
|
||||
{
|
||||
gl_gs_frame* ret = new gl_gs_frame(w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
|
||||
gameWindow = ret;
|
||||
|
@ -38,6 +38,7 @@
|
||||
|
||||
#include "Loader/PUP.h"
|
||||
#include "Loader/TAR.h"
|
||||
#include "Loader/PSF.h"
|
||||
|
||||
#include "Utilities/Thread.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
@ -67,7 +68,7 @@ auto Pause = []()
|
||||
else if (!Emu.GetBoot().empty()) Emu.Load();
|
||||
};
|
||||
|
||||
/* An init method is used so that RPCS3App can create the necessary connects before calling init (specifically the stylesheet connect).
|
||||
/* An init method is used so that RPCS3App can create the necessary connects before calling init (specifically the stylesheet connect).
|
||||
* Simplifies logic a bit.
|
||||
*/
|
||||
void main_window::Init()
|
||||
@ -108,7 +109,7 @@ void main_window::Init()
|
||||
|
||||
Q_EMIT RequestGlobalStylesheetChange(guiSettings->GetCurrentStylesheetPath());
|
||||
ConfigureGuiFromSettings(true);
|
||||
|
||||
|
||||
if (!utils::has_ssse3())
|
||||
{
|
||||
QMessageBox::critical(this, "SSSE3 Error (with three S, not two)",
|
||||
@ -252,7 +253,7 @@ void main_window::BootElf()
|
||||
"SELF files (EBOOT.BIN *.self);;"
|
||||
"BOOT files (*BOOT.BIN);;"
|
||||
"BIN files (*.bin);;"
|
||||
"All files (*.*)"),
|
||||
"All files (*.*)"),
|
||||
Q_NULLPTR, QFileDialog::DontResolveSymlinks);
|
||||
|
||||
if (filePath == NULL)
|
||||
@ -603,7 +604,7 @@ void main_window::DecryptSPRXLibraries()
|
||||
LOG_NOTICE(GENERAL, "Finished decrypting all SPRX libraries.");
|
||||
}
|
||||
|
||||
/** Needed so that when a backup occurs of window state in guisettings, the state is current.
|
||||
/** Needed so that when a backup occurs of window state in guisettings, the state is current.
|
||||
* Also, so that on close, the window state is preserved.
|
||||
*/
|
||||
void main_window::SaveWindowState()
|
||||
@ -622,7 +623,7 @@ void main_window::SaveWindowState()
|
||||
void main_window::RepaintThumbnailIcons()
|
||||
{
|
||||
QColor newColor = gui::get_Label_Color("thumbnail_icon_color");
|
||||
|
||||
|
||||
auto icon = [&newColor](const QString& path)
|
||||
{
|
||||
return gui_settings::colorizedIcon(QPixmap::fromImage(gui_settings::GetOpaqueImageArea(path)), gui::mw_tool_icon_color, newColor);
|
||||
@ -918,7 +919,7 @@ QAction* main_window::CreateRecentAction(const q_string_pair& entry, const uint&
|
||||
act->setData(entry.first);
|
||||
act->setToolTip(entry.second);
|
||||
act->setShortcut(tr("Ctrl+%1").arg(sc_idx));
|
||||
|
||||
|
||||
// truncate if too long
|
||||
if (shown_name.length() > 60)
|
||||
{
|
||||
@ -977,7 +978,7 @@ void main_window::AddRecentAction(const q_string_pair& entry)
|
||||
m_rg_entries.prepend(entry);
|
||||
m_recentGameActs.prepend(act);
|
||||
}
|
||||
|
||||
|
||||
// refill menu with actions
|
||||
for (int i = 0; i < m_recentGameActs.count(); i++)
|
||||
{
|
||||
@ -1040,7 +1041,7 @@ void main_window::CreateActions()
|
||||
ui->toolbar_start->setEnabled(false);
|
||||
ui->toolbar_stop->setEnabled(false);
|
||||
|
||||
m_categoryVisibleActGroup = new QActionGroup(this);
|
||||
m_categoryVisibleActGroup = new QActionGroup(this);
|
||||
m_categoryVisibleActGroup->addAction(ui->showCatHDDGameAct);
|
||||
m_categoryVisibleActGroup->addAction(ui->showCatDiscGameAct);
|
||||
m_categoryVisibleActGroup->addAction(ui->showCatHomeAct);
|
||||
@ -1530,7 +1531,7 @@ void main_window::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
/** Override the Qt close event to have the emulator stop and the application die. May add a warning dialog in future.
|
||||
/** Override the Qt close event to have the emulator stop and the application die. May add a warning dialog in future.
|
||||
*/
|
||||
void main_window::closeEvent(QCloseEvent* closeEvent)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user