mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-07 23:45:12 +00:00
Implement most of cellUserInfo
This commit is contained in:
parent
61450335a5
commit
087dccd194
10 changed files with 562 additions and 28 deletions
|
|
@ -1,7 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/RSX/Overlays/overlay_user_list_dialog.h"
|
||||
|
||||
#include "cellUserInfo.h"
|
||||
|
||||
|
|
@ -10,6 +12,25 @@
|
|||
|
||||
LOG_CHANNEL(cellUserInfo);
|
||||
|
||||
struct user_info_manager
|
||||
{
|
||||
atomic_t<bool> enable_overlay{false};
|
||||
atomic_t<bool> dialog_opened{false};
|
||||
};
|
||||
|
||||
std::string get_username(const u32 user_id)
|
||||
{
|
||||
std::string username;
|
||||
|
||||
if (const fs::file file{Emulator::GetHddDir() + fmt::format("home/%08d/localusername", user_id)})
|
||||
{
|
||||
username = file.to_string();
|
||||
username.resize(CELL_USERINFO_USERNAME_SIZE); // TODO: investigate
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellUserInfoError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
|
|
@ -27,6 +48,21 @@ void fmt_class_string<CellUserInfoError>::format(std::string& out, u64 arg)
|
|||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<cell_user_callback_result>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_USERINFO_RET_OK);
|
||||
STR_CASE(CELL_USERINFO_RET_CANCEL);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
||||
{
|
||||
cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat);
|
||||
|
|
@ -43,7 +79,7 @@ error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
id = Emu.GetUsrId();
|
||||
}
|
||||
|
||||
const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
||||
const std::string path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
||||
|
||||
if (!fs::is_dir(path))
|
||||
{
|
||||
|
|
@ -70,12 +106,103 @@ error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
|
||||
error_code cellUserInfoSelectUser_ListType(vm::ptr<CellUserInfoTypeSet> listType, vm::ptr<CellUserInfoFinishCallback> funcSelect, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoSelectUser_ListType(listType=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", listType, funcSelect, container, userdata);
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType(listType=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", listType, funcSelect, container, userdata);
|
||||
|
||||
if (!listType || !funcSelect) // TODO: confirm
|
||||
{
|
||||
return CELL_USERINFO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
std::vector<u32> user_ids;
|
||||
const std::string home_dir = Emulator::GetHddDir() + "home";
|
||||
|
||||
for (const auto& user_folder : fs::dir(home_dir))
|
||||
{
|
||||
if (!user_folder.is_directory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the folder name exactly 8 all-numerical characters long?
|
||||
const u32 user_id = Emulator::CheckUsr(user_folder.name);
|
||||
|
||||
if (user_id == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the localusername file exist?
|
||||
if (!fs::is_file(home_dir + "/" + user_folder.name + "/localusername"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: maybe also restrict this to CELL_USERINFO_USER_MAX
|
||||
if (listType->type != CELL_USERINFO_LISTTYPE_NOCURRENT || user_id != Emu.GetUsrId())
|
||||
{
|
||||
user_ids.push_back(user_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened.exchange(true))
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
const std::string title = listType->title.get_ptr();
|
||||
const u32 focused = listType->focus;
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType: opening user_list_dialog with: title='%s', focused=%d", title, focused);
|
||||
|
||||
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
||||
const error_code result = manager->create<rsx::overlays::user_list_dialog>()->show(title, focused, user_ids, enable_overlay, [funcSelect, userdata](s32 status)
|
||||
{
|
||||
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
||||
u32 selected_user_id = 0;
|
||||
std::string selected_username;
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
callback_result = CELL_USERINFO_RET_OK;
|
||||
selected_user_id = static_cast<u32>(status);
|
||||
selected_username = get_username(selected_user_id);
|
||||
}
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
if (status >= 0)
|
||||
{
|
||||
selectUser->id = selected_user_id;
|
||||
strcpy_trunc(selectUser->name, selected_username);
|
||||
}
|
||||
funcSelect(ppu, callback_result, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
g_fxo->get<user_info_manager>().dialog_opened = false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cellUserInfo.error("User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback.");
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_OK, selectUser, userdata);
|
||||
selectUser->id = Emu.GetUsrId();
|
||||
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
||||
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
|
|
@ -84,12 +211,99 @@ error_code cellUserInfoSelectUser_ListType(vm::ptr<CellUserInfoTypeSet> listType
|
|||
|
||||
error_code cellUserInfoSelectUser_SetList(vm::ptr<CellUserInfoListSet> setList, vm::ptr<CellUserInfoFinishCallback> funcSelect, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoSelectUser_SetList(setList=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", setList, funcSelect, container, userdata);
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList(setList=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", setList, funcSelect, container, userdata);
|
||||
|
||||
if (!setList || !funcSelect) // TODO: confirm
|
||||
{
|
||||
return CELL_USERINFO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
std::vector<u32> user_ids;
|
||||
|
||||
for (usz i = 0; i < CELL_USERINFO_USER_MAX && i < setList->fixedListNum; i++)
|
||||
{
|
||||
if (const u32 id = setList->fixedList->userId[i])
|
||||
{
|
||||
user_ids.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (user_ids.empty())
|
||||
{
|
||||
// TODO: Confirm. Also check if this is possible in cellUserInfoSelectUser_ListType.
|
||||
cellUserInfo.error("cellUserInfoSelectUser_SetList: callback_result=%s", CELL_USERINFO_ERROR_NOUSER);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_USERINFO_ERROR_NOUSER, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// TODO: does this function return an error if any (user_id > 0 && not_found) ?
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened.exchange(true))
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
const std::string title = setList->title.get_ptr();
|
||||
const u32 focused = setList->focus;
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList: opening user_list_dialog with: title='%s', focused=%d", title, focused);
|
||||
|
||||
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
||||
const error_code result = manager->create<rsx::overlays::user_list_dialog>()->show(title, focused, user_ids, enable_overlay, [funcSelect, userdata](s32 status)
|
||||
{
|
||||
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
||||
u32 selected_user_id = 0;
|
||||
std::string selected_username;
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
callback_result = CELL_USERINFO_RET_OK;
|
||||
selected_user_id = static_cast<u32>(status);
|
||||
selected_username = get_username(selected_user_id);
|
||||
}
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
if (status >= 0)
|
||||
{
|
||||
selectUser->id = selected_user_id;
|
||||
strcpy_trunc(selectUser->name, selected_username);
|
||||
}
|
||||
funcSelect(ppu, callback_result, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
g_fxo->get<user_info_manager>().dialog_opened = false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cellUserInfo.error("User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback.");
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_OK, selectUser, userdata);
|
||||
selectUser->id = Emu.GetUsrId();
|
||||
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
||||
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
|
|
@ -98,12 +312,14 @@ error_code cellUserInfoSelectUser_SetList(vm::ptr<CellUserInfoListSet> setList,
|
|||
|
||||
void cellUserInfoEnableOverlay(s32 enable)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoEnableOverlay(enable=%d)", enable);
|
||||
cellUserInfo.notice("cellUserInfoEnableOverlay(enable=%d)", enable);
|
||||
auto& manager = g_fxo->get<user_info_manager>();
|
||||
manager.enable_overlay = enable != 0;
|
||||
}
|
||||
|
||||
error_code cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserList> listBuf, vm::ptr<u32> currentUserId)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
cellUserInfo.warning("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
|
||||
// If only listNum is NULL, an error will be returned
|
||||
if (!listNum)
|
||||
|
|
@ -114,17 +330,58 @@ error_code cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserLis
|
|||
}
|
||||
}
|
||||
|
||||
const std::string home_dir = Emulator::GetHddDir() + "home";
|
||||
std::vector<u32> user_ids;
|
||||
|
||||
for (const auto& user_folder : fs::dir(home_dir))
|
||||
{
|
||||
if (!user_folder.is_directory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the folder name exactly 8 all-numerical characters long?
|
||||
const u32 user_id = Emulator::CheckUsr(user_folder.name);
|
||||
|
||||
if (user_id == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the localusername file exist?
|
||||
if (!fs::is_file(home_dir + "/" + user_folder.name + "/localusername"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (user_ids.size() < CELL_USERINFO_USER_MAX)
|
||||
{
|
||||
user_ids.push_back(user_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellUserInfo.warning("cellUserInfoGetList: Cannot add user %s. Too many users.", user_folder.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (listNum)
|
||||
{
|
||||
*listNum = 1;
|
||||
*listNum = static_cast<u32>(user_ids.size());
|
||||
}
|
||||
|
||||
if (listBuf)
|
||||
{
|
||||
std::memset(listBuf.get_ptr(), 0, listBuf.size());
|
||||
|
||||
// We report only one user, so it must be the current user
|
||||
listBuf->userId[0] = Emu.GetUsrId();
|
||||
for (usz i = 0; i < CELL_USERINFO_USER_MAX; i++)
|
||||
{
|
||||
if (i < user_ids.size())
|
||||
{
|
||||
listBuf->userId[i] = user_ids[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
listBuf->userId[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUserId)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue