HLE: improve cellHddGameCheck

This commit is contained in:
Megamouse 2020-09-28 21:18:23 +02:00 committed by Ivan
parent fe3c7926f7
commit 27643cb715
4 changed files with 211 additions and 33 deletions

View File

@ -5,6 +5,7 @@
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_fs.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "cellSysutil.h"
#include "cellMsgDialog.h"
@ -172,10 +173,27 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
return CELL_HDDGAME_ERROR_PARAM;
}
std::string dir = dirName.get_ptr();
std::string game_dir = dirName.get_ptr();
// TODO: Find error code
verify(HERE), dir.size() == 9;
verify(HERE), game_dir.size() == 9;
const std::string dir = "/dev_hdd0/game/" + game_dir;
psf::registry sfo = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
const u32 new_data = sfo.empty() && !fs::is_file(vfs::get(dir + "/PARAM.SFO")) ? CELL_GAMEDATA_ISNEWDATA_YES : CELL_GAMEDATA_ISNEWDATA_NO;
if (!new_data)
{
const auto cat = psf::get_string(sfo, "CATEGORY", "");
if (cat != "HG")
{
return CELL_GAMEDATA_ERROR_BROKEN;
}
}
const std::string usrdir = dir + "/USRDIR";
vm::var<CellHddGameCBResult> result;
vm::var<CellHddGameStatGet> get;
@ -191,13 +209,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
get->ctime = 0; // TODO
get->mtime = 0; // TODO
get->sizeKB = CELL_HDDGAME_SIZEKB_NOTCALC;
strcpy_trunc(get->contentInfoPath, "/dev_hdd0/game/" + dir);
strcpy_trunc(get->hddGamePath, "/dev_hdd0/game/" + dir + "/USRDIR");
strcpy_trunc(get->contentInfoPath, dir);
strcpy_trunc(get->hddGamePath, usrdir);
vm::var<CellHddGameSystemFileParam> setParam;
set->setParam = setParam;
const std::string& local_dir = vfs::get("/dev_hdd0/game/" + dir);
const std::string& local_dir = vfs::get(dir);
if (!fs::is_dir(local_dir))
{
@ -228,14 +246,107 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
funcStat(ppu, result, get, set);
if (result->result != u32{CELL_HDDGAME_CBRESULT_OK} && result->result != u32{CELL_HDDGAME_CBRESULT_OK_CANCEL})
std::string error_msg;
switch (result->result)
{
return CELL_HDDGAME_ERROR_CBRESULT;
case CELL_HDDGAME_CBRESULT_OK:
{
// Game confirmed that it wants to create directory
const auto setParam = set->setParam;
if (new_data)
{
if (!setParam)
{
return CELL_GAMEDATA_ERROR_PARAM;
}
// TODO ?
if (!fs::create_path(vfs::get(usrdir)))
{
return {CELL_GAME_ERROR_ACCESS_ERROR, usrdir};
}
}
if (setParam)
{
if (new_data)
{
psf::assign(sfo, "CATEGORY", psf::string(3, "HG"));
}
psf::assign(sfo, "TITLE_ID", psf::string(CELL_GAME_SYSP_TITLEID_SIZE, setParam->titleId));
psf::assign(sfo, "TITLE", psf::string(CELL_GAME_SYSP_TITLE_SIZE, setParam->title));
psf::assign(sfo, "VERSION", psf::string(CELL_GAME_SYSP_VERSION_SIZE, setParam->dataVersion));
psf::assign(sfo, "PARENTAL_LEVEL", +setParam->parentalLevel);
psf::assign(sfo, "RESOLUTION", +setParam->resolution);
psf::assign(sfo, "SOUND_FORMAT", +setParam->soundFormat);
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{
if (!setParam->titleLang[i][0])
{
continue;
}
psf::assign(sfo, fmt::format("TITLE_%02d", i), psf::string(CELL_GAME_SYSP_TITLE_SIZE, setParam->titleLang[i]));
}
psf::save_object(fs::file(vfs::get(dir + "/PARAM.SFO"), fs::rewrite), sfo);
}
return CELL_OK;
}
case CELL_HDDGAME_CBRESULT_OK_CANCEL:
cellGame.warning("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_OK_CANCEL");
return CELL_OK;
case CELL_HDDGAME_CBRESULT_ERR_NOSPACE:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, fmt::format("%d", result->errNeedSizeKB).c_str());
break;
case CELL_HDDGAME_CBRESULT_ERR_BROKEN:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_BROKEN");
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_BROKEN, game_dir.c_str());
break;
case CELL_HDDGAME_CBRESULT_ERR_NODATA:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NODATA");
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NODATA, game_dir.c_str());
break;
case CELL_HDDGAME_CBRESULT_ERR_INVALID:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, result->invalidMsg.get_ptr());
break;
default:
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, result->invalidMsg.get_ptr());
break;
}
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS) // Maybe != CELL_GAMEDATA_ERRDIALOG_NONE
{
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
// Reschedule after a blocking dialog returns
if (ppu.check_state())
{
return 0;
}
if (res != CELL_OK)
{
return CELL_GAMEDATA_ERROR_INTERNAL;
}
}
return CELL_HDDGAME_ERROR_CBRESULT;
}
error_code cellHddGameCheck2(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellHddGameStatCallback> funcStat, u32 container)
@ -593,14 +704,8 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
return CELL_GAMEDATA_ERROR_PARAM;
}
// TODO: output errors (errDialog)
const std::string dir = "/dev_hdd0/game/"s + dirName.get_ptr();
const std::string usrdir = dir + "/USRDIR";
vm::var<CellGameDataCBResult> cbResult;
vm::var<CellGameDataStatGet> cbGet;
vm::var<CellGameDataStatSet> cbSet;
const std::string game_dir = dirName.get_ptr();
const std::string dir = "/dev_hdd0/game/"s + game_dir;
psf::registry sfo = psf::load_object(fs::file(vfs::get(dir + "/PARAM.SFO")));
@ -615,6 +720,12 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
}
}
const std::string usrdir = dir + "/USRDIR";
vm::var<CellGameDataCBResult> cbResult;
vm::var<CellGameDataStatGet> cbGet;
vm::var<CellGameDataStatSet> cbSet;
cbGet->isNewData = new_data;
// TODO: Use the free space of the computer's HDD where RPCS3 is being run.
@ -644,15 +755,15 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
funcStat(ppu, cbResult, cbGet, cbSet);
std::string error_msg;
switch (cbResult->result)
{
case CELL_GAMEDATA_CBRESULT_OK_CANCEL:
{
// TODO: do not process game data(directory)
cellGame.warning("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_OK_CANCEL");
return CELL_OK;
}
case CELL_GAMEDATA_CBRESULT_OK:
{
// Game confirmed that it wants to create directory
@ -685,7 +796,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{
if (!cbSet->setParam->titleLang[i][0])
if (!setParam->titleLang[i][0])
{
continue;
}
@ -698,26 +809,53 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
return CELL_OK;
}
case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE: // TODO: process errors, error message and needSizeKB result
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE");
return CELL_GAMEDATA_ERROR_CBRESULT;
case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", cbResult->errNeedSizeKB);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, fmt::format("%d", cbResult->errNeedSizeKB).c_str());
break;
case CELL_GAMEDATA_CBRESULT_ERR_BROKEN:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_BROKEN");
return CELL_GAMEDATA_ERROR_CBRESULT;
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_BROKEN, game_dir.c_str());
break;
case CELL_GAMEDATA_CBRESULT_ERR_NODATA:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NODATA");
return CELL_GAMEDATA_ERROR_CBRESULT;
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NODATA, game_dir.c_str());
break;
case CELL_GAMEDATA_CBRESULT_ERR_INVALID:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID");
return CELL_GAMEDATA_ERROR_CBRESULT;
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID. Error message: %s", cbResult->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, cbResult->invalidMsg.get_ptr());
break;
default:
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x)");
return CELL_GAMEDATA_ERROR_CBRESULT;
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, cbResult->invalidMsg.get_ptr());
break;
}
if (errDialog == CELL_GAMEDATA_ERRDIALOG_ALWAYS) // Maybe != CELL_GAMEDATA_ERRDIALOG_NONE
{
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
// Reschedule after a blocking dialog returns
if (ppu.check_state())
{
return 0;
}
if (res != CELL_OK)
{
return CELL_GAMEDATA_ERROR_INTERNAL;
}
}
return CELL_GAMEDATA_ERROR_CBRESULT;
}
error_code cellGameDataCheckCreate(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Emu/Cell/ErrorCodes.h"
@ -73,6 +73,8 @@ enum
CELL_GAME_SIZEKB_NOTCALC = -1,
CELL_GAME_THEMEINSTALL_BUFSIZE_MIN = 4096,
CELL_GAME_ATTRIBUTE_PATCH = 0x1,
CELL_GAME_ATTRIBUTE_APP_HOME = 0x2,
CELL_GAME_ATTRIBUTE_DEBUG = 0x4,
@ -87,6 +89,7 @@ enum
CELL_GAME_DISCTYPE_OTHER = 0,
CELL_GAME_DISCTYPE_PS3 = 1,
CELL_GAME_DISCTYPE_PS2 = 2,
};
//Parameter IDs of PARAM.SFO
@ -137,6 +140,25 @@ enum
CELL_GAME_ERRDIALOG_NOSPACE_EXIT = 102,
};
enum // CellGameResolution
{
CELL_GAME_RESOLUTION_480 = 0x01,
CELL_GAME_RESOLUTION_576 = 0x02,
CELL_GAME_RESOLUTION_720 = 0x04,
CELL_GAME_RESOLUTION_1080 = 0x08,
CELL_GAME_RESOLUTION_480SQ = 0x10,
CELL_GAME_RESOLUTION_576SQ = 0x20,
};
enum // CellGameSoundFormat
{
CELL_GAME_SOUNDFORMAT_2LPCM = 0x01,
CELL_GAME_SOUNDFORMAT_51LPCM = 0x04,
CELL_GAME_SOUNDFORMAT_71LPCM = 0x10,
CELL_GAME_SOUNDFORMAT_51DDENC = 0x102,
CELL_GAME_SOUNDFORMAT_51DTSENC = 0x202,
};
struct CellGameContentSize
{
be_t<s32> hddFreeSizeKB;
@ -157,8 +179,8 @@ struct CellGameDataCBResult
{
be_t<s32> result;
be_t<s32> errNeedSizeKB;
be_t<u32> invalidMsg_addr;
be_t<u32> reserved;
vm::bptr<char> invalidMsg;
vm::bptr<void> reserved;
};
enum // old consts
@ -304,7 +326,7 @@ struct CellHddGameSystemFileParam
struct CellHddGameCBResult
{
be_t<u32> result;
be_t<s32> result;
be_t<s32> errNeedSizeKB;
vm::bptr<char> invalidMsg;
vm::bptr<void> reserved;

View File

@ -37,6 +37,16 @@ enum class localized_string_id
CELL_GAME_DATA_EXIT_BROKEN,
CELL_HDD_GAME_EXIT_BROKEN,
CELL_HDD_GAME_CHECK_NOSPACE,
CELL_HDD_GAME_CHECK_BROKEN,
CELL_HDD_GAME_CHECK_NODATA,
CELL_HDD_GAME_CHECK_INVALID,
CELL_GAMEDATA_CHECK_NOSPACE,
CELL_GAMEDATA_CHECK_BROKEN,
CELL_GAMEDATA_CHECK_NODATA,
CELL_GAMEDATA_CHECK_INVALID,
CELL_MSG_DIALOG_ERROR_DEFAULT,
CELL_MSG_DIALOG_ERROR_80010001,
CELL_MSG_DIALOG_ERROR_80010002,

View File

@ -65,6 +65,14 @@ private:
case localized_string_id::CELL_GAME_ERROR_DIR_NAME: return tr("Directory name: %0", "Game Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_GAME_DATA_EXIT_BROKEN: return tr("There has been an error!\n\nPlease remove the game data for this title.", "Game Error");
case localized_string_id::CELL_HDD_GAME_EXIT_BROKEN: return tr("There has been an error!\n\nPlease reinstall the HDD boot game.", "Game Error");
case localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE: return tr("Not enough space to create HDD boot game.\nSpace Needed: %0 KB", "HDD Game Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_HDD_GAME_CHECK_BROKEN: return tr("HDD boot game %0 is corrupt!", "HDD Game Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_HDD_GAME_CHECK_NODATA: return tr("HDD boot game %0 could not be found!", "HDD Game Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_HDD_GAME_CHECK_INVALID: return tr("Error: %0", "HDD Game Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE: return tr("Not enough space to create game data.\nSpace Needed: %0 KB", "Gamedata Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_GAMEDATA_CHECK_BROKEN: return tr("The game data in %0 is corrupt!", "Gamedata Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_GAMEDATA_CHECK_NODATA: return tr("The game data in %0 could not be found!", "Gamedata Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_GAMEDATA_CHECK_INVALID: return tr("Error: %0", "Gamedata Check Error").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_MSG_DIALOG_ERROR_80010001: return tr("The resource is temporarily unavailable.\n(%0)", "Error code").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_MSG_DIALOG_ERROR_80010002: return tr("Invalid argument or flag.\n(%0)", "Error code").arg(std::forward<Args>(args)...);
case localized_string_id::CELL_MSG_DIALOG_ERROR_80010003: return tr("The feature is not yet implemented.\n(%0)", "Error code").arg(std::forward<Args>(args)...);