2018-12-23 00:16:03 +01:00
# include " stdafx.h "
2015-10-26 22:09:31 +01:00
# include "Emu/System.h"
2016-03-21 20:42:14 +01:00
# include "Emu/IdManager.h"
# include "Emu/Cell/PPUModule.h"
2014-03-17 20:34:19 +01:00
2017-01-28 13:32:45 +01:00
# include "restore_new.h"
2014-08-23 22:40:04 +02:00
# include "Utilities/rXml.h"
2017-01-28 13:32:45 +01:00
# include "define_new_memleakdetect.h"
2014-02-16 02:51:04 +01:00
# include "Loader/TRP.h"
2014-03-20 19:23:14 +01:00
# include "Loader/TROPUSR.h"
2016-03-21 20:42:14 +01:00
2014-08-23 22:40:04 +02:00
# include "sceNp.h"
# include "sceNpTrophy.h"
2018-12-23 00:16:03 +01:00
# include "cellSysutil.h"
2014-04-01 02:33:55 +02:00
2016-04-27 00:27:24 +02:00
# include "Utilities/StrUtil.h"
2019-01-02 23:35:39 +01:00
# include "Emu/Cell/lv2/sys_event.h"
# include "Emu/Cell/lv2/sys_process.h"
2019-12-17 23:43:00 +01:00
# include <cmath>
2018-08-25 14:39:00 +02:00
LOG_CHANNEL ( sceNpTrophy ) ;
2014-02-16 02:51:04 +01:00
2017-10-24 17:43:05 +02:00
TrophyNotificationBase : : ~ TrophyNotificationBase ( )
{
}
2015-07-02 03:54:36 +02:00
struct trophy_context_t
2014-02-16 02:51:04 +01:00
{
2017-01-25 18:50:30 +01:00
static const u32 id_base = 1 ;
static const u32 id_step = 1 ;
2019-12-17 20:55:16 +01:00
static const u32 id_count = 4 ;
2017-01-25 18:50:30 +01:00
2014-02-16 02:51:04 +01:00
std : : string trp_name ;
2016-03-21 20:42:14 +01:00
fs : : file trp_stream ;
2014-04-18 13:28:27 +02:00
std : : unique_ptr < TROPUSRLoader > tropusr ;
2015-07-02 03:54:36 +02:00
} ;
2014-04-15 16:12:15 +02:00
2015-07-02 03:54:36 +02:00
struct trophy_handle_t
{
2017-01-25 18:50:30 +01:00
static const u32 id_base = 1 ;
static const u32 id_step = 1 ;
2019-12-17 20:55:16 +01:00
static const u32 id_count = 4 ;
bool is_aborted = false ;
} ;
struct sce_np_trophy_manager
{
shared_mutex mtx ;
std : : atomic < bool > is_initialized = false ;
// Get context + check handle given
static std : : pair < trophy_context_t * , SceNpTrophyError > get_context_ex ( u32 context , u32 handle )
{
decltype ( get_context_ex ( 0 , 0 ) ) res { } ;
auto & [ ctxt , error ] = res ;
if ( context < trophy_context_t : : id_base | |
context > = trophy_context_t : : id_base + trophy_context_t : : id_count )
{
// Id was not in range of valid ids
error = SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
return res ;
}
ctxt = idm : : check < trophy_context_t > ( context ) ;
if ( ! ctxt )
{
error = SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT ;
return res ;
}
if ( handle < trophy_handle_t : : id_base | |
handle > = trophy_handle_t : : id_base + trophy_handle_t : : id_count )
{
error = SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
return res ;
}
const auto hndl = idm : : check < trophy_handle_t > ( handle ) ;
if ( ! hndl )
{
error = SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE ;
return res ;
}
else if ( hndl - > is_aborted )
{
error = SCE_NP_TROPHY_ERROR_ABORT ;
return res ;
}
return res ;
}
2015-07-02 03:54:36 +02:00
} ;
2014-04-18 13:28:27 +02:00
2017-05-15 13:30:14 +02:00
template < >
void fmt_class_string < SceNpTrophyError > : : format ( std : : string & out , u64 arg )
{
format_enum ( out , arg , [ ] ( auto error )
{
switch ( error )
{
STR_CASE ( SCE_NP_TROPHY_ERROR_ALREADY_INITIALIZED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_NOT_SUPPORTED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_OUT_OF_MEMORY ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_EXCEEDS_MAX ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INSUFFICIENT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_FORMAT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_BAD_RESPONSE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_GRADE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_CONTEXT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_PROCESSING_ABORTED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_ABORT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_LOCKED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_HIDDEN ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_CANNOT_UNLOCK_PLATINUM ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_ALREADY_UNLOCKED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_TYPE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_HANDLE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_NP_COMM_ID ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_DISC_IO ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNSUPPORTED_FORMAT ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_ALREADY_INSTALLED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_BROKEN_DATA ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_VERIFICATION_FAILURE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_TROPHY_ID ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN_FILE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_DISC_NOT_MOUNTED ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_SHUTDOWN ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_TITLE_ICON_NOT_FOUND ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_TROPHY_ICON_NOT_FOUND ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_INSUFFICIENT_DISK_SPACE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_SAVEDATA_USER_DOES_NOT_MATCH ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_TROPHY_ID_DOES_NOT_EXIST ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_SERVICE_UNAVAILABLE ) ;
STR_CASE ( SCE_NP_TROPHY_ERROR_UNKNOWN ) ;
}
return unknown ;
} ) ;
}
2019-12-21 11:46:43 +01:00
// Helpers
void show_trophy_notification ( u32 context , u32 handle , u32 trophyId , const std : : string & context_name )
{
// Get icon for the notification.
const std : : string padded_trophy_id = fmt : : format ( " %03u " , trophyId ) ;
const std : : string trophy_icon_path = " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + context_name + " /TROP " + padded_trophy_id + " .PNG " ;
fs : : file trophy_icon_file = fs : : file ( vfs : : get ( trophy_icon_path ) ) ;
std : : vector < uchar > trophy_icon_data ;
trophy_icon_file . read ( trophy_icon_data , trophy_icon_file . size ( ) ) ;
vm : : var < SceNpTrophyDetails > details ( { 0 } ) ;
vm : : var < SceNpTrophyData > _ ( { 0 } ) ;
const s32 ret = sceNpTrophyGetTrophyInfo ( context , handle , trophyId , details , _ ) ;
if ( ret ! = CELL_OK )
{
sceNpTrophy . error ( " Failed to get info for trophy dialog. Error code %x " , ret ) ;
* details = SceNpTrophyDetails ( ) ;
}
if ( auto trophy_notification_dialog = Emu . GetCallbacks ( ) . get_trophy_notification_dialog ( ) )
{
trophy_notification_dialog - > ShowTrophyNotification ( * details , trophy_icon_data ) ;
}
}
2015-07-02 03:54:36 +02:00
// Functions
2019-12-21 11:46:43 +01:00
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyInit ( vm : : ptr < void > pool , u32 poolSize , u32 containerId , u64 options )
2015-07-02 03:54:36 +02:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyInit(pool=*0x%x, poolSize=0x%x, containerId=0x%x, options=0x%llx) " , pool , poolSize , containerId , options ) ;
2014-04-18 13:28:27 +02:00
2019-09-08 14:11:39 +02:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-12-17 20:55:16 +01:00
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
2019-09-08 14:11:39 +02:00
if ( trophy_manager - > is_initialized )
{
return SCE_NP_TROPHY_ERROR_ALREADY_INITIALIZED ;
}
if ( options > 0 )
{
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED ;
}
trophy_manager - > is_initialized = true ;
2015-07-02 03:54:36 +02:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyTerm ( )
2015-07-02 03:54:36 +02:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyTerm() " ) ;
2014-02-16 02:51:04 +01:00
2019-09-08 14:11:39 +02:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-12-17 20:55:16 +01:00
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
2019-09-08 14:11:39 +02:00
if ( ! trophy_manager - > is_initialized )
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
}
2019-12-17 20:55:16 +01:00
u32 it = 0 ;
u32 ids [ std : : max ( trophy_context_t : : id_count , trophy_handle_t : : id_count ) ] ;
const auto get_handles = [ & ] ( u32 id , trophy_handle_t & )
{
ids [ it + + ] = id ;
} ;
const auto get_contexts = [ & ] ( u32 id , trophy_context_t & )
{
ids [ it + + ] = id ;
} ;
// This functionality could be implemented in idm instead
idm : : select < trophy_handle_t > ( get_handles ) ;
while ( it )
{
idm : : remove < trophy_handle_t > ( ids [ - - it ] ) ;
}
it = 0 ;
idm : : select < trophy_context_t > ( get_contexts ) ;
while ( it )
{
idm : : remove < trophy_context_t > ( ids [ - - it ] ) ;
}
2019-09-08 14:11:39 +02:00
trophy_manager - > is_initialized = false ;
2015-07-02 03:54:36 +02:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyCreateHandle ( vm : : ptr < u32 > handle )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyCreateHandle(handle=*0x%x) " , handle ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
if ( ! trophy_manager - > is_initialized )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
}
2015-07-02 03:54:36 +02:00
if ( ! handle )
2014-02-16 02:51:04 +01:00
{
2015-07-02 03:54:36 +02:00
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
2014-02-16 02:51:04 +01:00
}
2019-12-17 20:55:16 +01:00
const u32 id = idm : : make < trophy_handle_t > ( ) ;
if ( ! id )
{
return SCE_NP_TROPHY_ERROR_EXCEEDS_MAX ;
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
* handle = id ;
2015-07-02 03:54:36 +02:00
return CELL_OK ;
2015-02-08 12:37:10 +01:00
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyDestroyHandle ( u32 handle )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyDestroyHandle(handle=0x%x) " , handle ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
2019-09-08 14:11:39 +02:00
// TODO: find out if this is checked
2019-12-17 20:55:16 +01:00
//if (!trophy_manager->is_initialized)
2019-09-08 14:11:39 +02:00
//{
// return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
//}
2019-12-17 20:55:16 +01:00
if ( handle < trophy_handle_t : : id_base | |
handle > = trophy_handle_t : : id_base + trophy_handle_t : : id_count )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
if ( ! idm : : remove < trophy_handle_t > ( handle ) )
2015-07-02 03:54:36 +02:00
{
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE ;
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2019-04-10 19:34:44 +02:00
error_code sceNpTrophyGetGameDetails ( )
{
UNIMPLEMENTED_FUNC ( sceNpTrophy ) ;
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyAbortHandle ( u32 handle )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . todo ( " sceNpTrophyAbortHandle(handle=0x%x) " , handle ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
2019-09-08 14:11:39 +02:00
// TODO: find out if this is checked
2019-12-17 20:55:16 +01:00
//if (!trophy_manager->is_initialized)
2019-09-08 14:11:39 +02:00
//{
// return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
//}
2019-12-17 20:55:16 +01:00
if ( handle < trophy_handle_t : : id_base | |
handle > = trophy_handle_t : : id_base + trophy_handle_t : : id_count )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
const auto hndl = idm : : check < trophy_handle_t > ( handle ) ;
2015-07-02 03:54:36 +02:00
if ( ! hndl )
2015-04-25 23:26:54 +02:00
{
2015-07-02 03:54:36 +02:00
return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE ;
2015-04-25 23:26:54 +02:00
}
2019-12-17 20:55:16 +01:00
// Once it is aborted it cannot be used anymore
// TODO: Implement function abortion process maybe? (depends if its actually make sense for some functions)
hndl - > is_aborted = true ;
2015-07-02 03:54:36 +02:00
return CELL_OK ;
}
2019-09-08 14:11:39 +02:00
2017-04-13 19:29:47 +02:00
void deleteTerminateChar ( char * myStr , char _char ) {
2015-07-02 03:54:36 +02:00
2017-02-14 18:46:56 +01:00
char * del = & myStr [ strlen ( myStr ) ] ;
while ( del > myStr & & * del ! = _char )
del - - ;
if ( * del = = _char )
* del = ' \0 ' ;
return ;
}
2019-09-08 14:11:39 +02:00
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyCreateContext ( vm : : ptr < u32 > context , vm : : cptr < SceNpCommunicationId > commId , vm : : cptr < SceNpCommunicationSignature > commSign , u64 options )
2015-07-02 03:54:36 +02:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyCreateContext(context=*0x%x, commId=*0x%x, commSign=*0x%x, options=0x%llx) " , context , commId , commSign , options ) ;
2015-07-02 03:54:36 +02:00
2019-09-08 14:11:39 +02:00
if ( ! commSign )
2017-05-15 13:30:14 +02:00
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
if ( ! trophy_manager - > is_initialized )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
}
2019-10-15 16:04:22 +02:00
if ( ! context | | ! commId | | ! commSign )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2019-10-15 16:04:22 +02:00
if ( options > SCE_NP_TROPHY_OPTIONS_CREATE_CONTEXT_READ_ONLY )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED ;
}
2015-07-02 03:54:36 +02:00
// rough checks for further fmt::format call
2017-02-14 18:46:56 +01:00
if ( commId - > num > 99 )
2015-04-25 23:26:54 +02:00
{
2015-07-02 03:54:36 +02:00
return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID ;
2015-04-25 23:26:54 +02:00
}
2019-09-08 14:11:39 +02:00
2015-07-02 03:54:36 +02:00
// generate trophy context name
2017-02-14 18:46:56 +01:00
std : : string name ;
sceNpTrophy . warning ( " sceNpTrophyCreateContext term=%s data=%s num=%d " , commId - > term , commId - > data , commId - > num ) ;
if ( commId - > term )
{
2019-10-15 16:04:22 +02:00
char trimchar [ 10 ] ;
strcpy_trunc ( trimchar , commId - > data ) ;
2017-04-13 19:29:47 +02:00
deleteTerminateChar ( trimchar , commId - > term ) ;
2017-02-14 18:46:56 +01:00
name = fmt : : format ( " %s_%02d " , trimchar , commId - > num ) ;
}
else
{
2017-04-13 19:29:47 +02:00
name = fmt : : format ( " %s_%02d " , commId - > data , commId - > num ) ;
2017-02-14 18:46:56 +01:00
}
2017-04-13 19:29:47 +02:00
2015-07-02 03:54:36 +02:00
// open trophy pack file
2018-03-11 00:35:41 +01:00
fs : : file stream ( vfs : : get ( Emu . GetDir ( ) + " TROPDIR/ " + name + " /TROPHY.TRP " ) ) ;
2017-12-29 18:04:40 +01:00
2018-03-11 00:35:41 +01:00
if ( ! stream & & Emu . GetCat ( ) = = " GD " )
2017-12-29 18:04:40 +01:00
{
stream . open ( vfs : : get ( " /dev_bdvd/PS3_GAME/TROPDIR/ " + name + " /TROPHY.TRP " ) ) ;
}
2015-07-02 03:54:36 +02:00
// check if exists and opened
2016-03-21 20:42:14 +01:00
if ( ! stream )
2015-04-25 23:26:54 +02:00
{
2014-02-16 02:51:04 +01:00
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST ;
2015-04-25 23:26:54 +02:00
}
2014-02-16 02:51:04 +01:00
2015-07-02 03:54:36 +02:00
// create trophy context
2015-08-05 17:30:32 +02:00
const auto ctxt = idm : : make_ptr < trophy_context_t > ( ) ;
2014-02-16 16:37:32 +01:00
2019-12-17 20:55:16 +01:00
if ( ! ctxt )
{
return SCE_NP_TROPHY_ERROR_EXCEEDS_MAX ;
}
2015-07-02 03:54:36 +02:00
// set trophy context parameters (could be passed to constructor through make_ptr call)
ctxt - > trp_name = std : : move ( name ) ;
ctxt - > trp_stream = std : : move ( stream ) ;
2017-02-04 16:09:02 +01:00
* context = idm : : last_id ( ) ;
2014-02-16 02:51:04 +01:00
2015-07-02 03:54:36 +02:00
return CELL_OK ;
2014-02-16 02:51:04 +01:00
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyDestroyContext ( u32 context )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyDestroyContext(context=0x%x) " , context ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
std : : scoped_lock lock ( trophy_manager - > mtx ) ;
if ( ! trophy_manager - > is_initialized )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
}
2019-12-17 20:55:16 +01:00
if ( context < trophy_context_t : : id_base | |
context > = trophy_context_t : : id_base + trophy_context_t : : id_count )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
if ( ! idm : : remove < trophy_context_t > ( context ) )
2015-07-02 03:54:36 +02:00
{
return SCE_NP_TROPHY_ERROR_UNKNOWN_CONTEXT ;
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyRegisterContext ( ppu_thread & ppu , u32 context , u32 handle , vm : : ptr < SceNpTrophyStatusCallback > statusCb , vm : : ptr < void > arg , u64 options )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . error ( " sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx) " , context , handle , statusCb , arg , options ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2017-05-15 13:30:14 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-02-08 12:37:10 +01:00
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-07-02 03:54:36 +02:00
}
2014-03-06 13:27:58 +01:00
2019-09-08 14:11:39 +02:00
if ( ! statusCb )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2016-03-21 20:42:14 +01:00
TRPLoader trp ( ctxt - > trp_stream ) ;
2014-03-17 20:34:19 +01:00
if ( ! trp . LoadHeader ( ) )
2015-07-13 21:06:16 +02:00
{
2019-10-15 13:19:34 +02:00
sceNpTrophy . error ( " sceNpTrophyRegisterContext(): Failed to load trophy config header " ) ;
2014-03-17 20:34:19 +01:00
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE ;
2015-07-13 21:06:16 +02:00
}
2014-03-17 20:34:19 +01:00
// Rename or discard certain entries based on the files found
2014-04-15 16:12:15 +02:00
const size_t kTargetBufferLength = 31 ;
2015-07-13 21:06:16 +02:00
char target [ kTargetBufferLength + 1 ] ;
2014-04-15 16:12:15 +02:00
target [ kTargetBufferLength ] = 0 ;
2017-10-26 15:12:08 +02:00
strcpy_trunc ( target , fmt : : format ( " TROP_%02d.SFM " , static_cast < s32 > ( g_cfg . sys . language ) ) ) ;
2014-03-17 20:34:19 +01:00
2015-07-13 21:06:16 +02:00
if ( trp . ContainsEntry ( target ) )
{
2014-03-17 20:34:19 +01:00
trp . RemoveEntry ( " TROPCONF.SFM " ) ;
trp . RemoveEntry ( " TROP.SFM " ) ;
trp . RenameEntry ( target , " TROPCONF.SFM " ) ;
}
2015-07-13 21:06:16 +02:00
else if ( trp . ContainsEntry ( " TROP.SFM " ) )
{
2014-03-17 20:34:19 +01:00
trp . RemoveEntry ( " TROPCONF.SFM " ) ;
trp . RenameEntry ( " TROP.SFM " , " TROPCONF.SFM " ) ;
}
2015-07-13 21:06:16 +02:00
else if ( ! trp . ContainsEntry ( " TROPCONF.SFM " ) )
{
2019-12-02 22:31:34 +01:00
sceNpTrophy . error ( " sceNpTrophyRegisterContext(): Invalid/Incomplete trophy config " ) ;
2014-03-17 20:34:19 +01:00
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE ;
}
// Discard unnecessary TROP_XX.SFM files
2015-07-13 21:06:16 +02:00
for ( s32 i = 0 ; i < = 18 ; i + + )
{
2015-08-12 20:38:17 +02:00
strcpy_trunc ( target , fmt : : format ( " TROP_%02d.SFM " , i ) ) ;
2017-10-26 15:12:08 +02:00
if ( i ! = g_cfg . sys . language )
2015-07-13 21:06:16 +02:00
{
2014-03-17 20:34:19 +01:00
trp . RemoveEntry ( target ) ;
2015-07-13 21:06:16 +02:00
}
2014-03-17 20:34:19 +01:00
}
2014-02-16 02:51:04 +01:00
2019-12-19 02:57:40 +01:00
const std : : string trophyPath = " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name ;
2014-03-20 19:23:14 +01:00
if ( ! trp . Install ( trophyPath ) )
2015-07-13 21:06:16 +02:00
{
2019-12-02 22:31:34 +01:00
sceNpTrophy . error ( " sceNpTrophyRegisterContext(): Failed to install trophy context '%s' (%s) " , trophyPath , fs : : g_tls_error ) ;
2014-03-17 20:34:19 +01:00
return SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE ;
2015-07-13 21:06:16 +02:00
}
2017-04-13 19:29:47 +02:00
2014-03-20 19:23:14 +01:00
TROPUSRLoader * tropusr = new TROPUSRLoader ( ) ;
2019-12-19 02:57:40 +01:00
const std : : string trophyUsrPath = trophyPath + " /TROPUSR.DAT " ;
const std : : string trophyConfPath = trophyPath + " /TROPCONF.SFM " ;
2014-03-21 15:07:05 +01:00
tropusr - > Load ( trophyUsrPath , trophyConfPath ) ;
2015-07-02 03:54:36 +02:00
ctxt - > tropusr . reset ( tropusr ) ;
2014-03-20 19:23:14 +01:00
2014-02-16 02:51:04 +01:00
// TODO: Callbacks
2018-09-03 14:09:09 +02:00
// From RE-ing a game's state machine, it seems the possible order is one of the following:
2018-07-10 17:02:41 +02:00
// * Install (Not installed) - Setup - Progress * ? - Finalize - Complete - Installed
// * Reinstall (Corrupted) - Setup - Progress * ? - Finalize - Complete - Installed
// * Update (Required update) - Setup - Progress * ? - Finalize - Complete - Installed
// * Installed
// We will go with the easy path of Installed, and that's it.
2018-09-07 18:26:59 +02:00
2018-12-23 00:16:03 +01:00
// The callback is called once and then if it returns >= 0 the cb is called through events(coming from vsh) that are passed to the CB through cellSysutilCheckCallback
if ( statusCb ( ppu , context , SCE_NP_TROPHY_STATUS_INSTALLED , 100 , 100 , arg ) < 0 )
{
return SCE_NP_TROPHY_ERROR_PROCESSING_ABORTED ;
}
// This emulates vsh sending the events and ensures that not 2 events are processed at once
2019-01-02 23:35:39 +01:00
const std : : pair < u32 , u32 > statuses [ ] =
2018-12-23 00:16:03 +01:00
{
2019-01-02 23:35:39 +01:00
{ SCE_NP_TROPHY_STATUS_PROCESSING_SETUP , 3 } ,
{ SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS , tropusr - > GetTrophiesCount ( ) } ,
{ SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE , 4 } ,
{ SCE_NP_TROPHY_STATUS_PROCESSING_COMPLETE , 0 }
2018-12-23 00:16:03 +01:00
} ;
2018-09-07 18:26:59 +02:00
2019-09-21 13:43:12 +02:00
lv2_obj : : sleep ( ppu ) ;
// Create a counter which is destroyed after the function ends
const auto queued = std : : make_shared < atomic_t < u32 > > ( 0 ) ;
std : : weak_ptr < atomic_t < u32 > > wkptr = queued ;
2019-01-02 23:35:39 +01:00
2018-09-07 18:26:59 +02:00
for ( auto status : statuses )
2017-04-14 12:08:17 +02:00
{
2019-01-02 23:35:39 +01:00
// One status max per cellSysutilCheckCallback call
2019-09-21 13:43:12 +02:00
* queued + = status . second ;
2019-01-02 23:35:39 +01:00
for ( u32 completed = 0 ; completed < = status . second ; completed + + )
{
2019-09-21 13:43:12 +02:00
sysutil_register_cb ( [ statusCb , status , context , completed , arg , wkptr ] ( ppu_thread & cb_ppu ) - > s32
2019-01-02 23:35:39 +01:00
{
statusCb ( cb_ppu , context , status . first , completed , status . second , arg ) ;
2019-09-21 13:43:12 +02:00
const auto queued = wkptr . lock ( ) ;
if ( queued & & ( * queued ) - - = = 1 )
{
queued - > notify_one ( ) ;
}
2019-01-02 23:35:39 +01:00
return 0 ;
} ) ;
}
2019-11-30 22:16:29 +01:00
u64 current = get_system_time ( ) ;
const u64 until = current + 300'000 ;
2019-09-21 13:43:12 +02:00
// If too much time passes just send the rest of the events anyway
2019-11-30 22:16:29 +01:00
for ( u32 old_value ; current < until & & ( old_value = * queued ) ;
current = get_system_time ( ) )
2019-09-21 13:43:12 +02:00
{
2019-11-30 22:16:29 +01:00
queued - > wait ( old_value , atomic_wait_timeout { std : : min < u64 > ( ( until - current ) * 1000 , 300'000'000 ) } ) ;
2019-09-21 13:43:12 +02:00
2019-11-30 22:16:29 +01:00
if ( ppu . is_stopped ( ) )
{
return 0 ;
}
2019-01-02 23:35:39 +01:00
}
2017-04-14 12:08:17 +02:00
}
2014-03-17 20:34:19 +01:00
return CELL_OK ;
2014-02-16 02:51:04 +01:00
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetRequiredDiskSpace ( u32 context , u32 handle , vm : : ptr < u64 > reqspace , u64 options )
2014-02-16 02:51:04 +01:00
{
2017-11-20 14:08:35 +01:00
sceNpTrophy . warning ( " sceNpTrophyGetRequiredDiskSpace(context=0x%x, handle=0x%x, reqspace=*0x%x, options=0x%llx) " , context , handle , reqspace , options ) ;
2014-02-16 02:51:04 +01:00
2017-05-15 13:30:14 +02:00
if ( ! reqspace )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2019-09-08 14:11:39 +02:00
if ( options > 0 )
{
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-09-08 14:11:39 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-02-08 12:37:10 +01:00
}
2014-02-27 04:21:08 +01:00
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-07-02 03:54:36 +02:00
}
2018-06-14 00:11:51 +02:00
if ( ! fs : : is_dir ( vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name ) ) )
2017-11-20 14:08:35 +01:00
{
TRPLoader trp ( ctxt - > trp_stream ) ;
if ( trp . LoadHeader ( ) )
{
* reqspace = trp . GetRequiredSpace ( ) ;
return CELL_OK ;
}
}
2014-03-06 13:27:58 +01:00
2017-11-20 14:08:35 +01:00
* reqspace = 0 ;
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophySetSoundLevel ( u32 context , u32 handle , u32 level , u64 options )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . todo ( " sceNpTrophySetSoundLevel(context=0x%x, handle=0x%x, level=%d, options=0x%llx) " , context , handle , level , options ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( level > 100 | | level < 20 )
2019-09-08 14:11:39 +02:00
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
if ( options > 0 )
{
return SCE_NP_TROPHY_ERROR_NOT_SUPPORTED ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-09-08 14:11:39 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2017-05-15 13:30:14 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2017-05-15 13:30:14 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2017-05-15 13:30:14 +02:00
}
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2017-05-15 13:30:14 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2017-05-15 13:30:14 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2017-05-15 13:30:14 +02:00
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetGameInfo ( u32 context , u32 handle , vm : : ptr < SceNpTrophyGameDetails > details , vm : : ptr < SceNpTrophyGameData > data )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . error ( " sceNpTrophyGetGameInfo(context=0x%x, handle=0x%x, details=*0x%x, data=*0x%x) " , context , handle , details , data ) ;
2014-09-30 20:42:15 +02:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2014-09-30 20:42:15 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-07-02 03:54:36 +02:00
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2014-03-09 04:57:19 +01:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-07-02 03:54:36 +02:00
}
2014-03-09 04:57:19 +01:00
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-09-08 14:11:39 +02:00
if ( ! details & & ! data )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2018-06-14 00:11:51 +02:00
fs : : file config ( vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + " /TROPCONF.SFM " ) ) ;
2017-09-03 21:29:20 +02:00
if ( ! config )
{
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST ;
}
2017-04-13 19:29:47 +02:00
2014-05-02 08:30:32 +02:00
rXmlDocument doc ;
2017-09-03 21:29:20 +02:00
doc . Read ( config . to_string ( ) ) ;
2014-03-20 19:23:14 +01:00
2018-03-21 23:04:05 +01:00
auto trophy_base = doc . GetRoot ( ) ;
if ( trophy_base - > GetChildren ( ) - > GetName ( ) = = " trophyconf " )
{
trophy_base = trophy_base - > GetChildren ( ) ;
}
2018-06-15 10:28:32 +02:00
if ( details )
2019-12-20 04:51:16 +01:00
* details = { } ;
2018-06-15 10:28:32 +02:00
if ( data )
2019-12-20 04:51:16 +01:00
* data = { } ;
2018-06-15 10:28:32 +02:00
2018-03-21 23:04:05 +01:00
for ( std : : shared_ptr < rXmlNode > n = trophy_base - > GetChildren ( ) ; n ; n = n - > GetNext ( ) )
2015-07-26 11:15:15 +02:00
{
2018-03-21 23:04:05 +01:00
const std : : string n_name = n - > GetName ( ) ;
2017-04-13 19:29:47 +02:00
if ( details )
{
2018-03-21 23:04:05 +01:00
if ( n_name = = " title-name " )
2017-04-13 19:29:47 +02:00
{
2018-06-15 10:28:32 +02:00
strcpy_trunc ( details - > title , n - > GetNodeContent ( ) ) ;
2018-03-21 23:04:05 +01:00
continue ;
2017-04-13 19:29:47 +02:00
}
2018-03-21 23:04:05 +01:00
else if ( n_name = = " title-detail " )
2017-04-13 19:29:47 +02:00
{
2018-06-15 10:28:32 +02:00
strcpy_trunc ( details - > description , n - > GetNodeContent ( ) ) ;
2018-03-21 23:04:05 +01:00
continue ;
2017-04-13 19:29:47 +02:00
}
}
2018-03-21 23:04:05 +01:00
if ( n_name = = " trophy " )
2014-03-20 19:23:14 +01:00
{
2017-04-13 19:29:47 +02:00
if ( details )
2014-03-20 19:23:14 +01:00
{
2017-04-13 19:29:47 +02:00
details - > numTrophies + + ;
2018-03-21 23:04:05 +01:00
switch ( n - > GetAttribute ( " ttype " ) [ 0 ] )
{
2017-04-13 19:29:47 +02:00
case ' B ' : details - > numBronze + + ; break ;
case ' S ' : details - > numSilver + + ; break ;
case ' G ' : details - > numGold + + ; break ;
case ' P ' : details - > numPlatinum + + ; break ;
}
}
if ( data )
{
2019-12-19 02:57:40 +01:00
const u32 trophy_id = atoi ( n - > GetAttribute ( " id " ) . c_str ( ) ) ;
2017-04-13 19:29:47 +02:00
if ( ctxt - > tropusr - > GetTrophyUnlockState ( trophy_id ) )
{
data - > unlockedTrophies + + ;
2018-03-21 23:04:05 +01:00
switch ( n - > GetAttribute ( " ttype " ) [ 0 ] )
{
2017-04-13 19:29:47 +02:00
case ' B ' : data - > unlockedBronze + + ; break ;
case ' S ' : data - > unlockedSilver + + ; break ;
case ' G ' : data - > unlockedGold + + ; break ;
case ' P ' : data - > unlockedPlatinum + + ; break ;
}
2014-03-20 19:23:14 +01:00
}
}
}
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2019-04-10 19:34:44 +02:00
error_code sceNpTrophyGetLatestTrophies ( )
{
UNIMPLEMENTED_FUNC ( sceNpTrophy ) ;
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyUnlockTrophy ( u32 context , u32 handle , s32 trophyId , vm : : ptr < u32 > platinumId )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . error ( " sceNpTrophyUnlockTrophy(context=0x%x, handle=0x%x, trophyId=%d, platinumId=*0x%x) " , context , handle , trophyId , platinumId ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-09-08 14:11:39 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-07-02 03:54:36 +02:00
}
2014-03-20 19:23:14 +01:00
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-07-02 03:54:36 +02:00
}
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-12-02 22:31:34 +01:00
if ( trophyId < 0 | | trophyId > = static_cast < s32 > ( ctxt - > tropusr - > GetTrophiesCount ( ) ) )
2020-01-06 09:47:11 +01:00
{
2014-03-20 19:23:14 +01:00
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID ;
2020-01-06 09:47:11 +01:00
}
if ( ctxt - > tropusr - > GetTrophyGrade ( trophyId ) = = SCE_NP_TROPHY_GRADE_PLATINUM )
{
return SCE_NP_TROPHY_ERROR_CANNOT_UNLOCK_PLATINUM ;
}
2015-07-02 03:54:36 +02:00
if ( ctxt - > tropusr - > GetTrophyUnlockState ( trophyId ) )
2020-01-06 09:47:11 +01:00
{
2014-03-20 19:23:14 +01:00
return SCE_NP_TROPHY_ERROR_ALREADY_UNLOCKED ;
2020-01-06 09:47:11 +01:00
}
2014-03-20 19:23:14 +01:00
2019-12-21 11:46:43 +01:00
ctxt - > tropusr - > UnlockTrophy ( trophyId , 0 , 0 ) ; // TODO: add timestamps
2014-03-20 19:23:14 +01:00
2019-12-21 11:46:43 +01:00
// TODO: Make sure that unlocking platinum trophies is properly implemented and improve upon it
const std : : string & config_path = vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + " /TROPCONF.SFM " ) ;
const u32 unlocked_platinum_id = ctxt - > tropusr - > GetUnlockedPlatinumID ( trophyId , config_path ) ;
if ( unlocked_platinum_id ! = SCE_NP_TROPHY_INVALID_TROPHY_ID )
2017-09-21 10:21:43 +02:00
{
2019-12-21 11:46:43 +01:00
sceNpTrophy . warning ( " sceNpTrophyUnlockTrophy: All requirements for unlocking the platinum trophy (ID = %d) were met.) " , unlocked_platinum_id ) ;
if ( ctxt - > tropusr - > UnlockTrophy ( unlocked_platinum_id , 0 , 0 ) ) // TODO: add timestamps
{
sceNpTrophy . success ( " You unlocked a platinum trophy! Hooray!!! " ) ;
}
2017-09-21 10:21:43 +02:00
}
2019-12-21 11:46:43 +01:00
if ( platinumId )
2017-10-24 17:43:05 +02:00
{
2019-12-21 11:46:43 +01:00
* platinumId = unlocked_platinum_id ;
sceNpTrophy . warning ( " sceNpTrophyUnlockTrophy: platinumId was set to %d) " , unlocked_platinum_id ) ;
}
2017-10-24 17:43:05 +02:00
2019-12-21 11:46:43 +01:00
const std : : string trophyPath = " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + " /TROPUSR.DAT " ;
ctxt - > tropusr - > Save ( trophyPath ) ;
2017-10-24 17:43:05 +02:00
2019-12-21 11:46:43 +01:00
if ( g_cfg . misc . show_trophy_popups )
{
// Enqueue popup for the regular trophy
show_trophy_notification ( context , handle , trophyId , ctxt - > trp_name ) ;
2018-01-17 17:14:00 +01:00
2019-12-21 11:46:43 +01:00
if ( unlocked_platinum_id ! = SCE_NP_TROPHY_INVALID_TROPHY_ID )
2019-06-20 15:51:50 +02:00
{
2019-12-21 11:46:43 +01:00
// Enqueue popup for the holy platinum trophy
show_trophy_notification ( context , handle , unlocked_platinum_id , ctxt - > trp_name ) ;
2019-06-20 15:51:50 +02:00
}
2017-10-24 17:43:05 +02:00
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetTrophyUnlockState ( u32 context , u32 handle , vm : : ptr < SceNpTrophyFlagArray > flags , vm : : ptr < u32 > count )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . error ( " sceNpTrophyGetTrophyUnlockState(context=0x%x, handle=0x%x, flags=*0x%x, count=*0x%x) " , context , handle , flags , count ) ;
2014-09-22 21:00:28 +02:00
2019-09-08 14:11:39 +02:00
if ( ! flags | | ! count ) // is count really checked here?
2017-04-13 19:29:47 +02:00
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-09-08 14:11:39 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2014-09-22 21:00:28 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-07-02 03:54:36 +02:00
}
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2014-03-20 19:23:14 +01:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-02-08 12:37:10 +01:00
}
2014-03-20 19:23:14 +01:00
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-12-17 18:21:29 +01:00
const u32 count_ = ctxt - > tropusr - > GetTrophiesCount ( ) ;
2015-02-08 12:37:10 +01:00
* count = count_ ;
if ( count_ > 128 )
2016-01-12 22:57:16 +01:00
sceNpTrophy . error ( " sceNpTrophyGetTrophyUnlockState: More than 128 trophies detected! " ) ;
2014-03-20 19:23:14 +01:00
2019-12-17 18:21:29 +01:00
// Needs hw testing
* flags = { } ;
2014-03-20 19:23:14 +01:00
// Pack up to 128 bools in u32 flag_bits[4]
2015-02-08 12:37:10 +01:00
for ( u32 id = 0 ; id < count_ ; id + + )
2014-03-20 19:23:14 +01:00
{
2015-07-02 03:54:36 +02:00
if ( ctxt - > tropusr - > GetTrophyUnlockState ( id ) )
2017-04-13 19:29:47 +02:00
flags - > flag_bits [ id / 32 ] | = 1 < < ( id % 32 ) ;
2014-03-20 19:23:14 +01:00
else
2017-04-13 19:29:47 +02:00
flags - > flag_bits [ id / 32 ] & = ~ ( 1 < < ( id % 32 ) ) ;
2014-03-20 19:23:14 +01:00
}
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2019-04-10 19:34:44 +02:00
error_code sceNpTrophyGetTrophyDetails ( )
{
UNIMPLEMENTED_FUNC ( sceNpTrophy ) ;
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetTrophyInfo ( u32 context , u32 handle , s32 trophyId , vm : : ptr < SceNpTrophyDetails > details , vm : : ptr < SceNpTrophyData > data )
2014-02-16 02:51:04 +01:00
{
2016-01-12 22:57:16 +01:00
sceNpTrophy . warning ( " sceNpTrophyGetTrophyInfo(context=0x%x, handle=0x%x, trophyId=%d, details=*0x%x, data=*0x%x) " , context , handle , trophyId , details , data ) ;
2014-02-16 02:51:04 +01:00
2019-12-17 20:55:16 +01:00
if ( trophyId < 0 | | trophyId > 127 ) // max 128 trophies
2017-04-13 19:29:47 +02:00
{
2019-09-08 14:11:39 +02:00
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2015-07-02 03:54:36 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2015-07-02 03:54:36 +02:00
}
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2014-03-06 01:52:23 +01:00
2019-12-17 20:55:16 +01:00
if ( error )
2015-07-02 03:54:36 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2015-07-02 03:54:36 +02:00
}
2017-04-13 19:29:47 +02:00
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-09-08 14:11:39 +02:00
if ( ! details & & ! data )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2018-06-14 00:11:51 +02:00
fs : : file config ( vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + " /TROPCONF.SFM " ) ) ;
2017-09-03 21:29:20 +02:00
if ( ! config )
{
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST ;
}
2016-03-21 20:42:14 +01:00
2018-06-15 10:28:32 +02:00
if ( details )
2019-12-20 04:51:16 +01:00
* details = { } ;
2018-06-15 10:28:32 +02:00
if ( data )
2019-12-20 04:51:16 +01:00
* data = { } ;
2018-06-15 10:28:32 +02:00
2017-04-13 19:29:47 +02:00
rXmlDocument doc ;
2017-09-03 21:29:20 +02:00
doc . Read ( config . to_string ( ) ) ;
2017-09-02 13:43:44 +02:00
auto trophy_base = doc . GetRoot ( ) ;
if ( trophy_base - > GetChildren ( ) - > GetName ( ) = = " trophyconf " )
{
trophy_base = trophy_base - > GetChildren ( ) ;
}
2014-03-20 19:23:14 +01:00
2017-04-13 19:29:47 +02:00
bool found = false ;
2017-09-03 21:29:20 +02:00
for ( std : : shared_ptr < rXmlNode > n = trophy_base - > GetChildren ( ) ; n ; n = n - > GetNext ( ) )
{
2014-05-02 08:30:32 +02:00
if ( n - > GetName ( ) = = " trophy " & & ( trophyId = = atoi ( n - > GetAttribute ( " id " ) . c_str ( ) ) ) )
2014-03-20 19:23:14 +01:00
{
2017-04-13 19:29:47 +02:00
found = true ;
2019-12-19 02:57:40 +01:00
const bool hidden = n - > GetAttribute ( " hidden " ) [ 0 ] = = ' y ' ;
const bool unlocked = ! ! ctxt - > tropusr - > GetTrophyUnlockState ( trophyId ) ;
if ( hidden & & ! unlocked ) // Trophy is hidden
2017-04-13 19:29:47 +02:00
{
return SCE_NP_TROPHY_ERROR_HIDDEN ;
2014-03-20 19:23:14 +01:00
}
2017-04-13 19:29:47 +02:00
if ( details )
{
details - > trophyId = trophyId ;
2019-12-19 02:57:40 +01:00
details - > hidden = hidden ;
2018-03-21 23:04:05 +01:00
switch ( n - > GetAttribute ( " ttype " ) [ 0 ] )
{
2017-04-13 19:29:47 +02:00
case ' B ' : details - > trophyGrade = SCE_NP_TROPHY_GRADE_BRONZE ; break ;
case ' S ' : details - > trophyGrade = SCE_NP_TROPHY_GRADE_SILVER ; break ;
case ' G ' : details - > trophyGrade = SCE_NP_TROPHY_GRADE_GOLD ; break ;
case ' P ' : details - > trophyGrade = SCE_NP_TROPHY_GRADE_PLATINUM ; break ;
}
2018-03-21 23:04:05 +01:00
for ( std : : shared_ptr < rXmlNode > n2 = n - > GetChildren ( ) ; n2 ; n2 = n2 - > GetNext ( ) )
{
const std : : string n2_name = n2 - > GetName ( ) ;
if ( n2_name = = " name " )
2017-04-13 19:29:47 +02:00
{
2018-06-15 10:28:32 +02:00
strcpy_trunc ( details - > name , n2 - > GetNodeContent ( ) ) ;
2017-04-13 19:29:47 +02:00
}
2018-03-21 23:04:05 +01:00
else if ( n2_name = = " detail " )
2017-04-13 19:29:47 +02:00
{
2018-06-15 10:28:32 +02:00
strcpy_trunc ( details - > description , n2 - > GetNodeContent ( ) ) ;
2017-04-13 19:29:47 +02:00
}
}
2014-03-20 19:23:14 +01:00
}
2017-04-13 19:29:47 +02:00
if ( data )
{
data - > trophyId = trophyId ;
2019-12-19 02:57:40 +01:00
data - > unlocked = unlocked ;
2017-04-13 19:29:47 +02:00
data - > timestamp = ctxt - > tropusr - > GetTrophyTimestamp ( trophyId ) ;
2014-03-20 19:23:14 +01:00
}
2017-04-13 19:29:47 +02:00
break ;
}
}
2014-03-20 19:23:14 +01:00
2017-04-13 19:29:47 +02:00
if ( ! found )
{
2017-05-15 13:30:14 +02:00
return not_an_error ( SCE_NP_TROPHY_INVALID_TROPHY_ID ) ;
2014-03-20 19:23:14 +01:00
}
2014-03-09 04:57:19 +01:00
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetGameProgress ( u32 context , u32 handle , vm : : ptr < s32 > percentage )
2014-02-16 02:51:04 +01:00
{
2017-04-13 19:29:47 +02:00
sceNpTrophy . warning ( " sceNpTrophyGetGameProgress(context=0x%x, handle=0x%x, percentage=*0x%x) " , context , handle , percentage ) ;
if ( ! percentage )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2019-09-08 14:11:39 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2017-04-13 19:29:47 +02:00
}
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2017-04-13 19:29:47 +02:00
}
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-12-17 23:43:00 +01:00
const u32 unlocked = ctxt - > tropusr - > GetUnlockedTrophiesCount ( ) ;
const u32 trp_count = ctxt - > tropusr - > GetTrophiesCount ( ) ;
2017-04-13 19:29:47 +02:00
2020-02-06 20:52:10 +01:00
// Round result to nearest (TODO: Check 0 trophies)
* percentage = trp_count ? : : rounded_div ( unlocked * 100 , trp_count ) : 0 ;
2019-12-16 20:56:14 +01:00
2020-02-06 20:52:10 +01:00
if ( trp_count = = 0 | | trp_count > 128 )
{
sceNpTrophy . warning ( " sceNpTrophyGetGameProgress(): Trophies count may be invalid or untested (%d) " , trp_count ) ;
}
2015-07-02 03:54:36 +02:00
2014-02-16 02:51:04 +01:00
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetGameIcon ( u32 context , u32 handle , vm : : ptr < void > buffer , vm : : ptr < u32 > size )
2014-02-16 02:51:04 +01:00
{
2017-04-13 19:29:47 +02:00
sceNpTrophy . warning ( " sceNpTrophyGetGameIcon(context=0x%x, handle=0x%x, buffer=*0x%x, size=*0x%x) " , context , handle , buffer , size ) ;
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2017-04-13 19:29:47 +02:00
}
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2017-04-13 19:29:47 +02:00
}
2019-09-08 14:11:39 +02:00
if ( ! size )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2018-06-14 00:11:51 +02:00
fs : : file icon_file ( vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + " /ICON0.PNG " ) ) ;
2017-04-13 19:29:47 +02:00
2017-09-03 21:29:20 +02:00
if ( ! icon_file )
2017-04-13 19:29:47 +02:00
{
return SCE_NP_TROPHY_ERROR_UNKNOWN_FILE ;
}
2017-09-03 21:29:20 +02:00
const u32 icon_size = : : size32 ( icon_file ) ;
2017-04-13 19:29:47 +02:00
2017-09-03 21:29:20 +02:00
if ( buffer & & * size > = icon_size )
2017-04-13 19:29:47 +02:00
{
2017-09-03 21:29:20 +02:00
icon_file . read ( buffer . get_ptr ( ) , icon_size ) ;
2017-04-13 19:29:47 +02:00
}
2017-09-03 21:29:20 +02:00
* size = icon_size ;
2014-02-16 02:51:04 +01:00
2015-07-02 03:54:36 +02:00
return CELL_OK ;
}
2019-04-05 20:14:01 +02:00
error_code sceNpTrophyGetUserInfo ( )
{
UNIMPLEMENTED_FUNC ( sceNpTrophy ) ;
return CELL_OK ;
}
2017-05-15 13:30:14 +02:00
error_code sceNpTrophyGetTrophyIcon ( u32 context , u32 handle , s32 trophyId , vm : : ptr < void > buffer , vm : : ptr < u32 > size )
2015-07-02 03:54:36 +02:00
{
2017-04-13 19:29:47 +02:00
sceNpTrophy . warning ( " sceNpTrophyGetTrophyIcon(context=0x%x, handle=0x%x, trophyId=%d, buffer=*0x%x, size=*0x%x) " , context , handle , trophyId , buffer , size ) ;
2019-12-17 20:55:16 +01:00
const auto trophy_manager = g_fxo - > get < sce_np_trophy_manager > ( ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
std : : shared_lock lock ( trophy_manager - > mtx ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( ! trophy_manager - > is_initialized )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED ;
2017-04-13 19:29:47 +02:00
}
2019-12-17 20:55:16 +01:00
const auto [ ctxt , error ] = trophy_manager - > get_context_ex ( context , handle ) ;
2017-04-13 19:29:47 +02:00
2019-12-17 20:55:16 +01:00
if ( error )
2017-04-13 19:29:47 +02:00
{
2019-12-17 20:55:16 +01:00
return error ;
2017-04-13 19:29:47 +02:00
}
2019-09-08 14:11:39 +02:00
if ( ! size )
{
return SCE_NP_TROPHY_ERROR_INVALID_ARGUMENT ;
}
2020-02-06 21:14:29 +01:00
if ( ! ctxt - > tropusr )
{
// TODO: May return SCE_NP_TROPHY_ERROR_UNKNOWN_TITLE for older sdk version
return SCE_NP_TROPHY_ERROR_CONTEXT_NOT_REGISTERED ;
}
2019-12-02 22:31:34 +01:00
if ( ctxt - > tropusr - > GetTrophiesCount ( ) < = static_cast < u32 > ( trophyId ) )
2017-04-13 19:29:47 +02:00
{
return SCE_NP_TROPHY_ERROR_INVALID_TROPHY_ID ;
}
if ( ! ctxt - > tropusr - > GetTrophyUnlockState ( trophyId ) )
{
bool hidden = false ; // TODO obtain this value
return hidden ? SCE_NP_TROPHY_ERROR_HIDDEN : SCE_NP_TROPHY_ERROR_LOCKED ;
}
2018-06-14 00:11:51 +02:00
fs : : file icon_file ( vfs : : get ( " /dev_hdd0/home/ " + Emu . GetUsr ( ) + " /trophy/ " + ctxt - > trp_name + fmt : : format ( " /TROP%03d.PNG " , trophyId ) ) ) ;
2017-04-13 19:29:47 +02:00
2017-09-03 21:29:20 +02:00
if ( ! icon_file )
2017-04-13 19:29:47 +02:00
{
return SCE_NP_TROPHY_ERROR_UNKNOWN_FILE ;
}
2017-09-03 21:29:20 +02:00
const u32 icon_size = : : size32 ( icon_file ) ;
2017-04-13 19:29:47 +02:00
2017-09-03 21:29:20 +02:00
if ( buffer & & * size > = icon_size )
2017-04-13 19:29:47 +02:00
{
2017-09-03 21:29:20 +02:00
icon_file . read ( buffer . get_ptr ( ) , icon_size ) ;
2017-04-13 19:29:47 +02:00
}
2017-09-03 21:29:20 +02:00
* size = icon_size ;
2015-07-02 03:54:36 +02:00
return CELL_OK ;
}
2016-03-21 20:42:14 +01:00
DECLARE ( ppu_module_manager : : sceNpTrophy ) ( " sceNpTrophy " , [ ] ( )
2015-07-02 03:54:36 +02:00
{
2015-02-20 14:58:40 +01:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetGameProgress ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyRegisterContext ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyCreateHandle ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophySetSoundLevel ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyGetRequiredDiskSpace ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyDestroyContext ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyInit ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyAbortHandle ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyGetGameInfo ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyDestroyHandle ) ;
2019-04-10 19:34:44 +02:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetGameDetails ) ;
2015-02-20 14:58:40 +01:00
REG_FUNC ( sceNpTrophy , sceNpTrophyUnlockTrophy ) ;
2019-04-10 19:34:44 +02:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetLatestTrophies ) ;
2015-02-20 14:58:40 +01:00
REG_FUNC ( sceNpTrophy , sceNpTrophyTerm ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyGetTrophyUnlockState ) ;
2019-04-05 20:14:01 +02:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetUserInfo ) ;
2015-02-20 14:58:40 +01:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetTrophyIcon ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyCreateContext ) ;
2019-04-10 19:34:44 +02:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetTrophyDetails ) ;
2015-02-20 14:58:40 +01:00
REG_FUNC ( sceNpTrophy , sceNpTrophyGetTrophyInfo ) ;
REG_FUNC ( sceNpTrophy , sceNpTrophyGetGameIcon ) ;
2015-02-18 17:22:06 +01:00
} ) ;