2025-04-08 18:46:57 +02:00
|
|
|
#include "Emu/Cell/PPUModule.h"
|
|
|
|
|
#include "Emu/IdManager.h"
|
2014-06-02 19:27:24 +02:00
|
|
|
#include "Emu/System.h"
|
2020-02-15 23:36:20 +01:00
|
|
|
#include "Emu/VFS.h"
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "Emu/system_utils.hpp"
|
|
|
|
|
#include "stdafx.h"
|
2023-02-13 19:57:38 +01:00
|
|
|
|
|
|
|
|
#include "Emu/RSX/Overlays/overlay_manager.h"
|
2021-04-21 23:20:33 +02:00
|
|
|
#include "Emu/RSX/Overlays/overlay_user_list_dialog.h"
|
2014-03-11 18:40:37 +01:00
|
|
|
|
|
|
|
|
#include "cellUserInfo.h"
|
|
|
|
|
|
2018-02-08 21:56:38 +01:00
|
|
|
#include "cellSysutil.h"
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "util/StrUtil.h"
|
2016-04-27 00:27:24 +02:00
|
|
|
|
2018-08-25 14:39:00 +02:00
|
|
|
LOG_CHANNEL(cellUserInfo);
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2021-04-21 23:20:33 +02:00
|
|
|
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;
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
if (const fs::file file{rpcs3::utils::get_hdd0_dir() +
|
|
|
|
|
fmt::format("home/%08d/localusername", user_id)})
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
|
|
|
|
username = file.to_string();
|
|
|
|
|
username.resize(CELL_USERINFO_USERNAME_SIZE); // TODO: investigate
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return username;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <>
|
2016-08-16 17:46:24 +02:00
|
|
|
void fmt_class_string<CellUserInfoError>::format(std::string& out, u64 arg)
|
|
|
|
|
{
|
|
|
|
|
format_enum(out, arg, [](auto error)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
switch (error)
|
|
|
|
|
{
|
|
|
|
|
STR_CASE(CELL_USERINFO_ERROR_BUSY);
|
|
|
|
|
STR_CASE(CELL_USERINFO_ERROR_INTERNAL);
|
|
|
|
|
STR_CASE(CELL_USERINFO_ERROR_PARAM);
|
|
|
|
|
STR_CASE(CELL_USERINFO_ERROR_NOUSER);
|
|
|
|
|
}
|
2016-08-16 17:46:24 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
return unknown;
|
|
|
|
|
});
|
2016-08-16 17:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <>
|
2025-04-08 18:46:57 +02:00
|
|
|
void fmt_class_string<cell_user_callback_result>::format(std::string& out,
|
|
|
|
|
u64 arg)
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
|
|
|
|
format_enum(out, arg, [](auto error)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
switch (error)
|
|
|
|
|
{
|
|
|
|
|
STR_CASE(CELL_USERINFO_RET_OK);
|
|
|
|
|
STR_CASE(CELL_USERINFO_RET_CANCEL);
|
|
|
|
|
}
|
2021-04-21 23:20:33 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
return unknown;
|
|
|
|
|
});
|
2021-04-21 23:20:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-15 13:30:14 +02:00
|
|
|
error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
2014-03-11 18:40:37 +01:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat);
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2015-12-11 18:09:24 +01:00
|
|
|
if (id > CELL_SYSUTIL_USERID_MAX)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2020-03-20 12:15:28 +01:00
|
|
|
// ****** sysutil userinfo parameter error : 1 ******
|
|
|
|
|
return {CELL_USERINFO_ERROR_PARAM, "1"};
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2015-12-11 18:09:24 +01:00
|
|
|
if (id == CELL_SYSUTIL_USERID_CURRENT)
|
|
|
|
|
{
|
2018-03-17 07:17:27 +01:00
|
|
|
// We want the int value, not the string.
|
|
|
|
|
id = Emu.GetUsrId();
|
2015-12-11 18:09:24 +01:00
|
|
|
}
|
|
|
|
|
|
2021-04-21 23:20:33 +02:00
|
|
|
const std::string path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
2016-04-09 12:03:53 +02:00
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
if (!fs::is_dir(path))
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.error("cellUserInfoGetStat(): CELL_USERINFO_ERROR_NOUSER. "
|
|
|
|
|
"User %d doesn't exist. Did you delete the user folder?",
|
|
|
|
|
id);
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_USERINFO_ERROR_NOUSER;
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
const fs::file f(path + "localusername");
|
2016-04-09 12:03:53 +02:00
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
if (!f)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.error(
|
|
|
|
|
"cellUserInfoGetStat(): CELL_USERINFO_ERROR_INTERNAL. Username for "
|
|
|
|
|
"user %08u doesn't exist. Did you delete the username file?",
|
|
|
|
|
id);
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_USERINFO_ERROR_INTERNAL;
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2020-03-20 12:15:28 +01:00
|
|
|
if (stat)
|
|
|
|
|
{
|
|
|
|
|
stat->id = id;
|
|
|
|
|
strcpy_trunc(stat->name, f.to_string());
|
|
|
|
|
}
|
2016-04-09 12:03:53 +02:00
|
|
|
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
error_code
|
|
|
|
|
cellUserInfoSelectUser_ListType(vm::ptr<CellUserInfoTypeSet> listType,
|
|
|
|
|
vm::ptr<CellUserInfoFinishCallback> funcSelect,
|
|
|
|
|
u32 container, vm::ptr<void> userdata)
|
2014-03-11 18:40:37 +01:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning("cellUserInfoSelectUser_ListType(listType=*0x%x, "
|
|
|
|
|
"funcSelect=*0x%x, container=0x%x, userdata=*0x%x)",
|
|
|
|
|
listType, funcSelect, container, userdata);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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;
|
2021-04-21 22:12:21 +02:00
|
|
|
const std::string home_dir = rpcs3::utils::get_hdd0_dir() + "home";
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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?
|
2021-04-21 22:12:21 +02:00
|
|
|
const u32 user_id = rpcs3::utils::check_user(user_folder.name);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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
|
2025-04-08 18:46:57 +02:00
|
|
|
if (listType->type != CELL_USERINFO_LISTTYPE_NOCURRENT ||
|
|
|
|
|
user_id != Emu.GetUsrId())
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0);
|
|
|
|
|
ret < 0)
|
2022-05-30 15:31:01 +02:00
|
|
|
{
|
2023-01-14 00:15:40 +01:00
|
|
|
g_fxo->get<user_info_manager>().dialog_opened = false;
|
2022-05-30 15:31:01 +02:00
|
|
|
return CELL_USERINFO_ERROR_BUSY;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 23:20:33 +02:00
|
|
|
const std::string title = listType->title.get_ptr();
|
|
|
|
|
const u32 focused = listType->focus;
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning("cellUserInfoSelectUser_ListType: opening "
|
|
|
|
|
"user_list_dialog with: title='%s', focused=%d",
|
|
|
|
|
title, focused);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
2025-04-08 18:46:57 +02:00
|
|
|
const error_code result =
|
|
|
|
|
manager->create<rsx::overlays::user_list_dialog>()->show(
|
|
|
|
|
title, focused, user_ids, enable_overlay,
|
|
|
|
|
[funcSelect, userdata](s32 status)
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
|
|
|
|
u32 selected_user_id = 0;
|
|
|
|
|
std::string selected_username;
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
if (status >= 0)
|
|
|
|
|
{
|
|
|
|
|
callback_result = CELL_USERINFO_RET_OK;
|
|
|
|
|
selected_user_id = static_cast<u32>(status);
|
|
|
|
|
selected_username = get_username(selected_user_id);
|
|
|
|
|
}
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning(
|
|
|
|
|
"cellUserInfoSelectUser_ListType: callback_result=%s, "
|
|
|
|
|
"selected_user_id=%d, selected_username='%s'",
|
|
|
|
|
callback_result, selected_user_id, selected_username);
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
g_fxo->get<user_info_manager>().dialog_opened = false;
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);
|
|
|
|
|
|
|
|
|
|
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
});
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
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.");
|
2018-02-08 21:56:38 +01:00
|
|
|
|
|
|
|
|
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
vm::var<CellUserInfoUserStat> selectUser;
|
|
|
|
|
selectUser->id = Emu.GetUsrId();
|
|
|
|
|
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
|
|
|
|
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
});
|
2018-02-08 21:56:38 +01:00
|
|
|
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
error_code
|
|
|
|
|
cellUserInfoSelectUser_SetList(vm::ptr<CellUserInfoListSet> setList,
|
|
|
|
|
vm::ptr<CellUserInfoFinishCallback> funcSelect,
|
|
|
|
|
u32 container, vm::ptr<void> userdata)
|
2014-03-11 18:40:37 +01:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning("cellUserInfoSelectUser_SetList(setList=*0x%x, "
|
|
|
|
|
"funcSelect=*0x%x, container=0x%x, userdata=*0x%x)",
|
|
|
|
|
setList, funcSelect, container, userdata);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
for (usz i = 0; i < CELL_USERINFO_USER_MAX && i < setList->fixedListNum;
|
|
|
|
|
i++)
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
|
|
|
|
if (const u32 id = setList->fixedList->userId[i])
|
|
|
|
|
{
|
|
|
|
|
user_ids.push_back(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (user_ids.empty())
|
|
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
// TODO: Confirm. Also check if this is possible in
|
|
|
|
|
// cellUserInfoSelectUser_ListType.
|
|
|
|
|
cellUserInfo.error("cellUserInfoSelectUser_SetList: callback_result=%s",
|
|
|
|
|
CELL_USERINFO_ERROR_NOUSER);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
vm::var<CellUserInfoUserStat> selectUser;
|
|
|
|
|
funcSelect(ppu, CELL_USERINFO_ERROR_NOUSER, selectUser, userdata);
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
});
|
2023-02-13 11:33:06 +01:00
|
|
|
|
2021-04-21 23:20:33 +02:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
// TODO: does this function return an error if any (user_id > 0 && not_found)
|
|
|
|
|
// ?
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
if (s32 ret = sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_BEGIN, 0);
|
|
|
|
|
ret < 0)
|
2022-05-30 15:31:01 +02:00
|
|
|
{
|
2023-01-14 00:15:40 +01:00
|
|
|
g_fxo->get<user_info_manager>().dialog_opened = false;
|
2022-05-30 15:31:01 +02:00
|
|
|
return CELL_USERINFO_ERROR_BUSY;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-21 23:20:33 +02:00
|
|
|
const std::string title = setList->title.get_ptr();
|
|
|
|
|
const u32 focused = setList->focus;
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning("cellUserInfoSelectUser_SetList: opening "
|
|
|
|
|
"user_list_dialog with: title='%s', focused=%d",
|
|
|
|
|
title, focused);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
2025-04-08 18:46:57 +02:00
|
|
|
const error_code result =
|
|
|
|
|
manager->create<rsx::overlays::user_list_dialog>()->show(
|
|
|
|
|
title, focused, user_ids, enable_overlay,
|
|
|
|
|
[funcSelect, userdata](s32 status)
|
2021-04-21 23:20:33 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
|
|
|
|
u32 selected_user_id = 0;
|
|
|
|
|
std::string selected_username;
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
if (status >= 0)
|
|
|
|
|
{
|
|
|
|
|
callback_result = CELL_USERINFO_RET_OK;
|
|
|
|
|
selected_user_id = static_cast<u32>(status);
|
|
|
|
|
selected_username = get_username(selected_user_id);
|
|
|
|
|
}
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning(
|
|
|
|
|
"cellUserInfoSelectUser_SetList: callback_result=%s, "
|
|
|
|
|
"selected_user_id=%d, selected_username='%s'",
|
|
|
|
|
callback_result, selected_user_id, selected_username);
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
g_fxo->get<user_info_manager>().dialog_opened = false;
|
2025-04-05 21:50:45 +02:00
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
sysutil_send_system_cmd(CELL_SYSUTIL_DRAWING_END, 0);
|
|
|
|
|
|
|
|
|
|
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
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;
|
|
|
|
|
});
|
|
|
|
|
});
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
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.");
|
2018-02-08 21:56:38 +01:00
|
|
|
|
|
|
|
|
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
vm::var<CellUserInfoUserStat> selectUser;
|
|
|
|
|
selectUser->id = Emu.GetUsrId();
|
|
|
|
|
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
|
|
|
|
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
});
|
2018-02-08 21:56:38 +01:00
|
|
|
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-15 13:30:14 +02:00
|
|
|
void cellUserInfoEnableOverlay(s32 enable)
|
2014-03-11 18:40:37 +01:00
|
|
|
{
|
2021-04-21 23:20:33 +02:00
|
|
|
cellUserInfo.notice("cellUserInfoEnableOverlay(enable=%d)", enable);
|
|
|
|
|
auto& manager = g_fxo->get<user_info_manager>();
|
|
|
|
|
manager.enable_overlay = enable != 0;
|
2014-03-11 18:40:37 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
error_code cellUserInfoGetList(vm::ptr<u32> listNum,
|
|
|
|
|
vm::ptr<CellUserInfoUserList> listBuf,
|
|
|
|
|
vm::ptr<u32> currentUserId)
|
2014-03-11 18:40:37 +01:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning(
|
|
|
|
|
"cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)",
|
|
|
|
|
listNum, listBuf, currentUserId);
|
2014-03-11 18:40:37 +01:00
|
|
|
|
2014-05-25 22:31:40 +02:00
|
|
|
// If only listNum is NULL, an error will be returned
|
2019-10-16 05:46:43 +02:00
|
|
|
if (!listNum)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2019-10-16 05:46:43 +02:00
|
|
|
if (listBuf || !currentUserId)
|
|
|
|
|
{
|
|
|
|
|
return CELL_USERINFO_ERROR_PARAM;
|
|
|
|
|
}
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
|
|
|
|
|
2021-04-21 22:12:21 +02:00
|
|
|
const std::string home_dir = rpcs3::utils::get_hdd0_dir() + "home";
|
2021-04-21 23:20:33 +02:00
|
|
|
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?
|
2021-04-21 22:12:21 +02:00
|
|
|
const u32 user_id = rpcs3::utils::check_user(user_folder.name);
|
2021-04-21 23:20:33 +02:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
cellUserInfo.warning(
|
|
|
|
|
"cellUserInfoGetList: Cannot add user %s. Too many users.",
|
|
|
|
|
user_folder.name);
|
2021-04-21 23:20:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-01 02:51:48 +02:00
|
|
|
if (listNum)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2021-04-21 23:20:33 +02:00
|
|
|
*listNum = static_cast<u32>(user_ids.size());
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-01 02:51:48 +02:00
|
|
|
if (listBuf)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2021-04-21 23:20:33 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
2014-05-19 15:05:53 +02:00
|
|
|
|
2014-09-01 02:51:48 +02:00
|
|
|
if (currentUserId)
|
2016-04-09 12:03:53 +02:00
|
|
|
{
|
2018-03-17 07:17:27 +01:00
|
|
|
// We want the int value, not the string.
|
|
|
|
|
*currentUserId = Emu.GetUsrId();
|
2016-04-09 12:03:53 +02:00
|
|
|
}
|
2017-12-16 01:03:49 +01:00
|
|
|
|
2014-03-11 18:40:37 +01:00
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 20:43:03 +01:00
|
|
|
DECLARE(ppu_module_manager::cellUserInfo)("cellUserInfo", []()
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
REG_FUNC(cellUserInfo, cellUserInfoGetStat);
|
|
|
|
|
REG_FUNC(cellUserInfo, cellUserInfoSelectUser_ListType);
|
|
|
|
|
REG_FUNC(cellUserInfo, cellUserInfoSelectUser_SetList);
|
|
|
|
|
REG_FUNC(cellUserInfo, cellUserInfoEnableOverlay);
|
|
|
|
|
REG_FUNC(cellUserInfo, cellUserInfoGetList);
|
|
|
|
|
});
|