Skip to content

Commit

Permalink
HLE: improve cellHddGameCheck
Browse files Browse the repository at this point in the history
  • Loading branch information
Megamouse committed Sep 11, 2020
1 parent 9ff0b46 commit 6d56566
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 31 deletions.
196 changes: 167 additions & 29 deletions rpcs3/Emu/Cell/Modules/cellGame.cpp
Expand Up @@ -3,6 +3,7 @@
#include "Emu/VFS.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_sync.h"

#include "cellSysutil.h"
#include "cellMsgDialog.h"
Expand Down Expand Up @@ -159,10 +160,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;
Expand All @@ -178,13 +196,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))
{
Expand Down Expand Up @@ -215,14 +233,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)
{
case CELL_HDDGAME_CBRESULT_OK:
{
return CELL_HDDGAME_ERROR_CBRESULT;
// Game confirmed that it wants to create directory
const auto setParam = set->setParam;

if (new_data)
{
if (!setParam)
{
return CELL_GAMEDATA_ERROR_PARAM;
}

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, "GD"));
}

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;

// TODO ?
case CELL_HDDGAME_CBRESULT_ERR_NOSPACE:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB);
error_msg = fmt::format("Not enough space to create HDD boot game.\nSpace Needed: %d KB", result->errNeedSizeKB);
break;

return CELL_OK;
case CELL_HDDGAME_CBRESULT_ERR_BROKEN:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_BROKEN");
error_msg = fmt::format("HDD boot game %s is corrupt!", game_dir);
break;

case CELL_HDDGAME_CBRESULT_ERR_NODATA:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NODATA");
error_msg = fmt::format("HDD boot game %s could not be found!", game_dir);
break;

case CELL_HDDGAME_CBRESULT_ERR_INVALID:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg);
error_msg = fmt::format("Error: %s", result->invalidMsg);
break;

default:
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
error_msg = fmt::format("Error: %s", result->invalidMsg);
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()
Expand Down Expand Up @@ -552,14 +663,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")));

Expand All @@ -574,6 +679,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.
Expand Down Expand Up @@ -603,15 +714,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
Expand Down Expand Up @@ -644,7 +755,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;
}
Expand All @@ -657,26 +768,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 = fmt::format("Not enough space to create game data.\nSpace Needed: %d KB", cbResult->errNeedSizeKB);
break;

case CELL_GAMEDATA_CBRESULT_ERR_BROKEN:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_BROKEN");
return CELL_GAMEDATA_ERROR_CBRESULT;
error_msg = fmt::format("The game data in %s is corrupt!", game_dir);
break;

case CELL_GAMEDATA_CBRESULT_ERR_NODATA:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NODATA");
return CELL_GAMEDATA_ERROR_CBRESULT;
error_msg = fmt::format("The game data in %s could not be found!", game_dir);
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_addr);
error_msg = fmt::format("Error: %s", cbResult->invalidMsg_addr);
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_addr);
error_msg = fmt::format("Error: %s", cbResult->invalidMsg_addr);
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)
Expand Down
4 changes: 2 additions & 2 deletions rpcs3/Emu/Cell/Modules/cellGame.h
@@ -1,4 +1,4 @@
#pragma once
#pragma once

#include "Emu/Cell/ErrorCodes.h"

Expand Down Expand Up @@ -304,7 +304,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;
Expand Down

0 comments on commit 6d56566

Please sign in to comment.