diff --git a/rpcs3/Emu/Cell/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp index 85482c2a08..d9d2ef5810 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -463,6 +463,7 @@ void fmt_class_string::format(std::string& out, u64 arg) STR_CASE(SCE_NP_MATCHING_ERROR_SHUTDOWN); STR_CASE(SCE_NP_MATCHING_ERROR_SYSUTIL_SERVER_BUSY); STR_CASE(SCE_NP_MATCHING_ERROR_SEND_INVITATION_PARTIALLY_FAILED); + STR_CASE(SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE); STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_OUT_OF_SERVICE); STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_MAINTENANCE); STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_SERVER_BUSY); @@ -477,6 +478,7 @@ void fmt_class_string::format(std::string& out, u64 arg) STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_REQUEST_FORBIDDEN); STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_INTERNAL_ERROR); STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_ROOM_OVER); + STR_CASE(SCE_NP_MATCHING_SERVER_ERROR_ROOM_CLOSED); } return unknown; @@ -3748,10 +3750,147 @@ error_code sceNpManagerSubSignout(vm::ptr npId) return CELL_OK; } +// FUN_000146fc +error_code check_attr_id(const SceNpMatchingAttr* attr) +{ + ensure(!!attr); + if (!attr) return SCE_NP_MATCHING_ERROR_INVALID_ATTR_ID; // Satisfy compiler + + switch (attr->type) + { + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN: + { + return SCE_NP_MATCHING_ERROR_INVALID_ATTR_ID; + } + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM: + { + if (attr->id < SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT || + attr->id > SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG) + return SCE_NP_MATCHING_ERROR_INVALID_ATTR_ID; + break; + } + case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN: + case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM: + { + if (attr->id < 1 || attr->id > 16) + return SCE_NP_MATCHING_ERROR_INVALID_ATTR_ID; + break; + } + default: + break; + } + + return CELL_OK; +} + +// FUN_0001476c +error_code check_duplicate_attr(vm::cptr attribute) +{ + std::set attr_type_id; + + for (const SceNpMatchingAttr* attr = attribute.get_ptr(); attribute && attr;) + { + // There are 4 types times 16 ids + const s32 type_id = (attr->type - 1) * 16 + attr->id - 1; + + if (!attr_type_id.insert(type_id).second) + return SCE_NP_MATCHING_ERROR_DUPLICATE; + + if (attr->next) + attr = attr->next.get_ptr(); + else + break; + } + + return CELL_OK; +} + +// FUN_00011718 +error_code check_attr_id_and_duplicate(vm::cptr attribute) +{ + for (const SceNpMatchingAttr* attr = attribute.get_ptr(); attribute && attr;) + { + error_code err = check_attr_id(attr); + if (err != CELL_OK) + return err; + + if (attr->next) + attr = attr->next.get_ptr(); + else + break; + } + + return check_duplicate_attr(attribute); +} + +// FUN_000245e0 +error_code check_text(vm::cptr text) +{ + if (!text) + return SCE_NP_UTIL_ERROR_INVALID_ARGUMENT; + + u32 count = 0; + + while (true) + { + const char c = *text; + if (c == '\0') + break; + + const u32 val = static_cast(static_cast(c)); + + if (c < '\0') + { + if ((val & 0xe0) == 0xc0 && val > 0xc1 && + (text[1] & 0xc0U) == 0x80) + { + text += 2; + } + else if ((val & 0xf0) == 0xe0 && + (text[1] & 0xc0U) == 0x80 && + (text[2] & 0xc0U) == 0x80) + { + text += 3; + } + else + { + if ((val & 0xf8) != 0xf0 || + (text[1] & 0xc0U) != 0x80 || + (text[2] & 0xc0U) != 0x80 || + (text[3] & 0xc0U) != 0x80) + { + return SCE_NP_UTIL_ERROR_INVALID_CHARACTER; + } + text += 4; + } + } + else + { + if (false) // TODO: check current char + return SCE_NP_UTIL_ERROR_INVALID_CHARACTER; + + text++; + } + + count++; + } + + return not_an_error(count); +} + error_code sceNpMatchingCreateCtx(vm::ptr npId, vm::ptr handler, vm::ptr arg, vm::ptr ctx_id) { sceNp.todo("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_MAX; + return CELL_OK; } @@ -3759,6 +3898,15 @@ error_code sceNpMatchingDestroyCtx(u32 ctx_id) { sceNp.todo("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3766,6 +3914,37 @@ error_code sceNpMatchingGetResult(u32 ctx_id, u32 req_id, vm::ptr buf, vm: { sceNp.todo("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!size) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + + const u64 id_check = static_cast(static_cast(req_id)) >> 0x17 & 0x3f; + if (id_check > 32 || (1 << id_check & 0x1f89ad040U) == 0) + return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID; + + if (buf) + { + // TODO: copy data to buf + } + else + { + constexpr u32 required_size = 0; // TODO + *size = required_size; + } + + if (event) + { + //*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM + } + return CELL_OK; } @@ -3773,6 +3952,27 @@ error_code sceNpMatchingGetResultGUI(vm::ptr buf, vm::ptr size, vm::p { sceNp.todo("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!size) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (buf) + { + // TODO: copy data to buf + } + else + { + constexpr u32 required_size = 0; // TODO + *size = required_size; + } + + if (event) + { + //*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM + } + return CELL_OK; } @@ -3780,6 +3980,28 @@ error_code sceNpMatchingSetRoomInfo(u32 ctx_id, vm::ptr lobby_id, { sceNp.todo("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (false) // TODO: some timeout with 30000000 us ? + return SCE_NP_MATCHING_ERROR_BUSY; + + if (!lobby_id || !room_id || !req_id || !attr) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + error_code err = check_attr_id_and_duplicate(attr); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3787,6 +4009,25 @@ error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr lob { sceNp.todo("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!lobby_id || !room_id || !req_id || !attr) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + error_code err = check_attr_id_and_duplicate(attr); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3794,6 +4035,28 @@ error_code sceNpMatchingGetRoomInfo(u32 ctx_id, vm::ptr lobby_id, { sceNp.todo("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (false) // TODO: some timeout with 30000000 us ? + return SCE_NP_MATCHING_ERROR_BUSY; + + if (!lobby_id || !room_id || !req_id || !attr) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + error_code err = check_attr_id_and_duplicate(attr); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3801,6 +4064,25 @@ error_code sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr lob { sceNp.todo("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!lobby_id || !room_id || !req_id || !attr) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + error_code err = check_attr_id_and_duplicate(attr); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3808,6 +4090,21 @@ error_code sceNpMatchingSetRoomSearchFlag(u32 ctx_id, vm::ptr lobb { sceNp.todo("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!lobby_id || !room_id || !req_id || (flag < SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN || flag > SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH)) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3815,6 +4112,21 @@ error_code sceNpMatchingGetRoomSearchFlag(u32 ctx_id, vm::ptr lobb { sceNp.todo("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!lobby_id || !room_id || !req_id) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3822,14 +4134,118 @@ error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr { sceNp.todo("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!buflen) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } +// FUN_00014bdc +error_code check_room_list_params([[maybe_unused]] u32 ctx_id, vm::ptr communicationId, vm::ptr range, vm::ptr cond, + vm::ptr attribute, vm::ptr handler, int param_7, int param_8) +{ + if (!communicationId || !range || !handler) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if ((!param_8 && !range->start) || range->max > 20) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + u32 total_count = 0; + u32 inequality_count = 0; + u32 max_count = 10; + if (param_7 != 0) + { + max_count = 9; + } + + for (const SceNpMatchingSearchCondition* con = cond.get_ptr(); cond && con;) + { + if (++total_count > max_count) + return SCE_NP_MATCHING_ERROR_COND_MAX; + + if (con->comp_type != SCE_NP_MATCHING_CONDITION_TYPE_VALUE || + con->comp_op < SCE_NP_MATCHING_CONDITION_SEARCH_EQ || + con->comp_op > SCE_NP_MATCHING_CONDITION_SEARCH_GE) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + + if (con->comp_op > SCE_NP_MATCHING_CONDITION_SEARCH_NE && + ++inequality_count > max_count) + return SCE_NP_MATCHING_ERROR_COMP_OP_INEQUALITY_MAX; + + switch (con->target_attr_type) + { + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN: + case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN: + { + return SCE_NP_MATCHING_ERROR_INVALID_COND; + } + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM: + { + if (param_7 == 0) + { + if (con->target_attr_id < SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT || + con->target_attr_id > SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + } + else + { + if (con->target_attr_id == SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + } + break; + } + case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM: + { + const u32 max_id = (param_7 == 0) ? 16 : 8; + if (con->target_attr_id < 1 || con->target_attr_id > max_id) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + break; + } + default: + break; + } + + if (con->next) + con = con->next.get_ptr(); + else + break; + } + + return check_attr_id_and_duplicate(attribute); +} + error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr communicationId, vm::ptr range, vm::ptr cond, vm::ptr attr, vm::ptr handler, vm::ptr arg) { - sceNp.todo( - "sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg); + sceNp.todo("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg); + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + // This check is used in all sceNpMatchingGetRoomList functions + error_code err = check_room_list_params(ctx_id, communicationId, range, cond, attr, handler, 1, 0); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + err = CELL_OK; // GetRoomListLimit + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } return CELL_OK; } @@ -3838,6 +4254,21 @@ error_code sceNpMatchingKickRoomMember(u32 ctx_id, vm::cptr room_id { sceNp.todo("sceNpMatchingKickRoomMember(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!room_id || !user_id || !req_id) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3845,6 +4276,24 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr { sceNp.todo("sceNpMatchingKickRoomMemberWithOpt(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, opt=*0x%x, opt_len=%d, req_id=*0x%x)", ctx_id, room_id, user_id, opt, opt_len, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!room_id || !user_id || !req_id) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (opt && (opt_len < 0 || opt_len > 16)) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } @@ -3854,7 +4303,60 @@ error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr sceNp.todo("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout, handler, arg); - return CELL_OK; + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!communicationId || !handler || available_num < 2 || timeout < 1) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + u32 total_count = 0; + constexpr u32 max_count = 9; + + for (const SceNpMatchingSearchCondition* con = cond.get_ptr(); cond && con;) + { + if (++total_count > max_count) + return SCE_NP_MATCHING_ERROR_COND_MAX; + + if (con->comp_op < SCE_NP_MATCHING_CONDITION_SEARCH_EQ || + con->comp_op > SCE_NP_MATCHING_CONDITION_SEARCH_NE) + return SCE_NP_MATCHING_ERROR_INVALID_COMP_OP; + + if (con->comp_type == 1) // weird, should be != SCE_NP_MATCHING_CONDITION_TYPE_VALUE + return SCE_NP_MATCHING_ERROR_INVALID_COMP_TYPE; + + switch (con->target_attr_type) + { + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN: + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM: + case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN: + { + return SCE_NP_MATCHING_ERROR_INVALID_COND; + } + case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM: + { + if (con->target_attr_id < 1 || con->target_attr_id > 8) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + break; + } + default: + break; + } + + if (con->next) + con = con->next.get_ptr(); + else + break; + } + + // TODO: set callback: handler + arg + + error_code err = CELL_OK; // QuickMatch + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } + + return err; } error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr room_id, vm::cptr communicationId, vm::cptr dsts, s32 num, s32 slot_type, @@ -3863,53 +4365,316 @@ error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr room sceNp.todo("sceNpMatchingSendInvitationGUI(ctx_id=%d, room_id=*0x%x, communicationId=*0x%x, dsts=*0x%x, num=%d, slot_type=%d, subject=%s, body=%s, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, communicationId, dsts, num, slot_type, subject, body, container, handler, arg); - return CELL_OK; + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!room_id || !communicationId || !subject || !body) // TODO: || (in_stack_0000007c != 0) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (dsts && (num <= 0 || num > SCE_NP_MATCHING_INVITATION_DESTINATION_MAX)) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + error_code err = check_text(subject); + if (err < 0) + return err; + + if (err > 16) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + err = check_text(body); + if (err < 0) + return err; + + if (err > 128) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (slot_type < SCE_NP_MATCHING_ROOM_SLOT_TYPE_PUBLIC || slot_type > SCE_NP_MATCHING_ROOM_SLOT_TYPE_PRIVATE) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + err = CELL_OK; // SendInvitation + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } + + return err; } error_code sceNpMatchingAcceptInvitationGUI(u32 ctx_id, vm::cptr communicationId, sys_memory_container_t container, vm::ptr handler, vm::ptr arg) { sceNp.todo("sceNpMatchingAcceptInvitationGUI(ctx_id=%d, communicationId=*0x%x, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, container, handler, arg); - return CELL_OK; + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!communicationId || !handler) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + error_code err = CELL_OK; // AcceptInvitation + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } + + return err; +} + +// FUN_00014d90 +error_code check_attr_create_room(vm::cptr attribute) +{ + for (const SceNpMatchingAttr* attr = attribute.get_ptr(); attribute && attr;) + { + error_code err = check_attr_id(attr); + if (err != CELL_OK) + return err; + + if (attr->type == SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM) + { + if (attr->id >= SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_TOTAL_NUM && + attr->id <= SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PRIVATE_NUM) + return SCE_NP_MATCHING_ERROR_INVALID_ATTR_ID; + + if (attr->value.num > 1 && + (attr->id == SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE || + attr->id == SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG)) + return SCE_NP_MATCHING_ERROR_INVALID_ATTR_VALUE; + } + else if (attr->type == SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN) + { + const u32 max_size = attr->id < 3 ? 256 : 64; + if (attr->value.data.size > max_size) + return SCE_NP_MATCHING_ERROR_INVALID_ATTR; + } + + if (attr->next) + attr = attr->next.get_ptr(); + else + break; + } + + error_code err = check_duplicate_attr(attribute); + if (err != CELL_OK) + return err; + + bool found_total_slots = false; + bool found_private_slots = false; + u32 total_slots = 0; + u32 private_slots = 0; + + for (const SceNpMatchingAttr* attr = attribute.get_ptr(); attribute && attr;) + { + if (attr->type == SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM) + { + if (attr->id == SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT) + { + total_slots = attr->value.num; + found_total_slots = true; + } + else if (attr->id == SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVATE_SLOT) + { + private_slots = attr->value.num; + found_private_slots = true; + } + + if (found_total_slots && found_private_slots) + { + if ((total_slots > 0 && total_slots <= 16) && + static_cast(private_slots) >= 0 && + static_cast(total_slots - private_slots) > 0) + { + return CELL_OK; + } + + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + } + } + + if (attr->next) + attr = attr->next.get_ptr(); + else + break; + } + + return SCE_NP_MATCHING_ERROR_ATTR_NOT_SPECIFIED; } error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr communicationId, vm::cptr attr, vm::ptr handler, vm::ptr arg) { sceNp.todo("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + if (!communicationId || !handler) - { return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + // This check is used in all sceNpMatchingCreateRoom functions + error_code err = check_attr_create_room(attr); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + err = CELL_OK; // create_room + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? } - return CELL_OK; + return err; } error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr room_id, vm::ptr handler, vm::ptr arg) { sceNp.todo("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg); - return CELL_OK; + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!room_id || !handler) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + error_code err = CELL_OK; // join_room + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } + + return err; } error_code sceNpMatchingLeaveRoom(u32 ctx_id, vm::cptr room_id, vm::ptr req_id) { sceNp.todo("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id); + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } -error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr communicationId, vm::cptr cond, vm::cptr attr, +error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr communicationId, vm::cptr cond, vm::cptr attribute, vm::ptr handler, vm::ptr arg) { - sceNp.todo("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attr, handler, arg); + sceNp.todo("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attribute, handler, arg); - return CELL_OK; + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (!communicationId || !handler) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + u32 total_count = 0; + u32 inequality_count = 0; + constexpr u32 max_count = 9; + + for (const SceNpMatchingSearchCondition* con = cond.get_ptr(); cond && con;) + { + if (++total_count > max_count) + return SCE_NP_MATCHING_ERROR_COND_MAX; + + if (con->comp_type != SCE_NP_MATCHING_CONDITION_TYPE_VALUE || + con->comp_op < SCE_NP_MATCHING_CONDITION_SEARCH_EQ || + con->comp_op > SCE_NP_MATCHING_CONDITION_SEARCH_GE) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + + if (con->comp_op > SCE_NP_MATCHING_CONDITION_SEARCH_NE && + ++inequality_count > max_count) + return SCE_NP_MATCHING_ERROR_COMP_OP_INEQUALITY_MAX; + + switch (con->target_attr_type) + { + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN: + case SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN: + { + return SCE_NP_MATCHING_ERROR_INVALID_COND; + } + case SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM: + { + if (con->target_attr_id != SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + break; + } + case SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM: + { + if (con->target_attr_id < 1 || con->target_attr_id > 8) + return SCE_NP_MATCHING_ERROR_INVALID_COND; + break; + } + default: + break; + } + + if (con->next) + con = con->next.get_ptr(); + else + break; + } + + error_code err = check_attr_id_and_duplicate(attribute); + if (err != CELL_OK) + return err; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + // TODO: set callback: handler + arg + + //err = search_join_room + if (err != CELL_OK && static_cast(err) != SCE_NP_MATCHING_ERROR_BUSY) + { + // TODO ? + } + + return err; } error_code sceNpMatchingGrantOwnership(u32 ctx_id, vm::cptr room_id, vm::cptr user_id, vm::ptr req_id) { sceNp.todo("sceNpMatchingGrantOwnership(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id); + if (false) // TODO + return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED; + + if (!room_id || !user_id || !req_id) + return SCE_NP_MATCHING_ERROR_INVALID_ARG; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_BUSY; + + if (false) // TODO + return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND; + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h index 295ff7634b..5854dc582e 100644 --- a/rpcs3/Emu/Cell/Modules/sceNp.h +++ b/rpcs3/Emu/Cell/Modules/sceNp.h @@ -523,6 +523,8 @@ enum SceNpError : u32 SCE_NP_MATCHING_ERROR_SHUTDOWN = 0x8002a730, SCE_NP_MATCHING_ERROR_SYSUTIL_SERVER_BUSY = 0x8002a731, SCE_NP_MATCHING_ERROR_SEND_INVITATION_PARTIALLY_FAILED = 0x8002a732, + SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE = 0x8002a733, + SCE_NP_MATCHING_SERVER_ERROR_OUT_OF_SERVICE = 0x8002a740, SCE_NP_MATCHING_SERVER_ERROR_MAINTENANCE = 0x8002a741, SCE_NP_MATCHING_SERVER_ERROR_SERVER_BUSY = 0x8002a742, @@ -537,6 +539,84 @@ enum SceNpError : u32 SCE_NP_MATCHING_SERVER_ERROR_REQUEST_FORBIDDEN = 0x8002a74b, SCE_NP_MATCHING_SERVER_ERROR_INTERNAL_ERROR = 0x8002a74c, SCE_NP_MATCHING_SERVER_ERROR_ROOM_OVER = 0x8002a74d, + SCE_NP_MATCHING_SERVER_ERROR_ROOM_CLOSED = 0x8002a74e, +}; + +enum +{ + SCE_NP_MATCHING_EVENT_ERROR = 0x0001, + SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE = 0x0002, + SCE_NP_MATCHING_EVENT_RESERVED1 = 0x0003, + SCE_NP_MATCHING_EVENT_RESERVED2 = 0x0004, + SCE_NP_MATCHING_EVENT_ROOM_UPDATE_NEW_MEMBER = 0x0005, + SCE_NP_MATCHING_EVENT_ROOM_UPDATE_MEMBER_LEAVE = 0x0006, + SCE_NP_MATCHING_EVENT_ROOM_DISAPPEARED = 0x0007, + SCE_NP_MATCHING_EVENT_RESERVED3 = 0x0008, + SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE = 0x0009, + SCE_NP_MATCHING_EVENT_SET_ROOM_INFO_DONE = 0x000a, + SCE_NP_MATCHING_EVENT_GRANT_OWNER_DONE = 0x000b, + SCE_NP_MATCHING_EVENT_ROOM_UPDATE_OWNER_CHANGE = 0x000c, + SCE_NP_MATCHING_EVENT_KICK_MEMBER_DONE = 0x000d, + SCE_NP_MATCHING_EVENT_ROOM_KICKED = 0x000e, + SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE = 0x000f, + SCE_NP_MATCHING_EVENT_SET_ROOM_SEARCH_FLAG_DONE = 0x0010, +}; + +enum +{ + SCE_NP_MATCHING_ATTR_TYPE_BASIC_BIN = 1, + SCE_NP_MATCHING_ATTR_TYPE_BASIC_NUM = 2, + SCE_NP_MATCHING_ATTR_TYPE_GAME_BIN = 3, + SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM = 4, +}; + +enum +{ + SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT = 1, + SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVATE_SLOT = 2, + SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_TOTAL_NUM = 3, + SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PUBLIC_NUM = 4, + SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PRIVATE_NUM = 5, + SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE = 6, + SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG = 7, +}; + +enum +{ + SCE_NP_MATCHING_ROOM_SLOT_TYPE_PUBLIC = 0, + SCE_NP_MATCHING_ROOM_SLOT_TYPE_PRIVATE = 1, +}; + +enum +{ + SCE_NP_MATCHING_ROOM_PRIVILEGE_TYPE_NO_AUTO_GRANT = 0, + SCE_NP_MATCHING_ROOM_PRIVILEGE_TYPE_AUTO_GRANT = 1, +}; + +enum +{ + SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN = 0, + SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH = 1, +}; + +enum +{ + SCE_NP_MATCHING_CONDITION_SEARCH_EQ = 0, + SCE_NP_MATCHING_CONDITION_SEARCH_NE = 1, + SCE_NP_MATCHING_CONDITION_SEARCH_LT = 2, + SCE_NP_MATCHING_CONDITION_SEARCH_LE = 3, + SCE_NP_MATCHING_CONDITION_SEARCH_GT = 4, + SCE_NP_MATCHING_CONDITION_SEARCH_GE = 5, +}; + +enum +{ + SCE_NP_MATCHING_CONDITION_TYPE_VALUE = 0, +}; + +enum +{ + SCE_NP_MATCHING_INVITATION_DESTINATION_MAX = 12, }; // Basic presence options