2023-02-25 20:51:48 +01:00
# include "utils/logger.h"
2022-02-03 16:24:36 +01:00
# include <coreinit/filesystem.h>
2018-06-28 22:27:25 +02:00
# include <malloc.h>
2023-12-16 17:16:43 +01:00
# include <stdbool.h>
2023-12-02 21:20:23 +01:00
# include <stdio.h>
2022-02-03 16:24:36 +01:00
# include <wups.h>
2021-09-24 19:57:15 +02:00
# include <wups/config/WUPSConfigItemBoolean.h>
2023-12-02 21:20:23 +01:00
# include <wups/config/WUPSConfigItemMultipleValues.h>
2023-12-16 17:16:43 +01:00
# include <wups/config/WUPSConfigItemStub.h>
2018-06-28 22:27:25 +02:00
/**
Mandatory plugin information .
If not set correctly , the loader will refuse to use the plugin .
* */
WUPS_PLUGIN_NAME ( " Example plugin " ) ;
WUPS_PLUGIN_DESCRIPTION ( " This is just an example plugin and will log the FSOpenFile function. " ) ;
WUPS_PLUGIN_VERSION ( " v1.0 " ) ;
WUPS_PLUGIN_AUTHOR ( " Maschell " ) ;
WUPS_PLUGIN_LICENSE ( " BSD " ) ;
2023-02-25 20:51:48 +01:00
# define LOG_FS_OPEN_CONFIG_ID "logFSOpen"
2018-06-28 22:27:25 +02:00
/**
2019-11-18 11:50:03 +01:00
All of this defines can be used in ANY file .
It ' s possible to split it up into multiple files .
2018-06-28 22:27:25 +02:00
* */
2019-11-18 11:50:03 +01:00
2021-10-01 17:24:45 +02:00
WUPS_USE_WUT_DEVOPTAB ( ) ; // Use the wut devoptabs
2023-02-25 20:51:48 +01:00
WUPS_USE_STORAGE ( " example_plugin " ) ; // Unique id for the storage api
2021-09-24 19:57:15 +02:00
bool logFSOpen = true ;
2019-11-18 11:50:03 +01:00
2023-12-02 21:20:23 +01:00
/**
* Callback that will be called if the config has been changed
*/
void logFSOpenChanged ( ConfigItemBoolean * item , bool newValue ) {
DEBUG_FUNCTION_LINE_INFO ( " New value in logFSOpenChanged: %d " , newValue ) ;
logFSOpen = newValue ;
// If the value has changed, we store it in the storage.
2023-12-14 17:20:38 +01:00
WUPSStorageAPI_StoreBool ( NULL , LOG_FS_OPEN_CONFIG_ID , logFSOpen ) ;
2023-12-02 21:20:23 +01:00
}
WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback ( WUPSConfigCategoryHandle root ) {
{
// Let's create a new category called "Settings"
WUPSConfigCategoryHandle settingsCategory ;
WUPSConfigAPICreateCategoryOptionsV1 settingsCategoryOptions = { . name = " Settings " } ;
if ( WUPSConfigAPI_Category_Create ( settingsCategoryOptions , & settingsCategory ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to create settings category " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
// Add a new item to this settings category
2023-12-16 17:16:43 +01:00
if ( WUPSConfigItemBoolean_AddToCategory ( settingsCategory , LOG_FS_OPEN_CONFIG_ID , " Log FSOpen calls " , true , logFSOpen , & logFSOpenChanged ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
2023-12-02 21:20:23 +01:00
DEBUG_FUNCTION_LINE_ERR ( " Failed to add item to category " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
// Add the category to the root.
if ( WUPSConfigAPI_Category_AddCategory ( root , settingsCategory ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to add category to root item " ) ;
}
}
{
// We can also have categories inside categories!
WUPSConfigCategoryHandle categoryLevel1 ;
WUPSConfigAPICreateCategoryOptionsV1 catLev1Options = { . name = " Category with subcategory " } ;
if ( WUPSConfigAPI_Category_Create ( catLev1Options , & categoryLevel1 ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to create categoryLevel1 " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
WUPSConfigCategoryHandle categoryLevel2 ;
WUPSConfigAPICreateCategoryOptionsV1 catLev2Options = { . name = " Category inside category " } ;
if ( WUPSConfigAPI_Category_Create ( catLev2Options , & categoryLevel2 ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to create categoryLevel1 " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
2023-12-16 17:16:43 +01:00
if ( WUPSConfigItemBoolean_AddToCategory ( categoryLevel2 , " stubInsideCategory " , " This is stub item inside a nested category " , false , false , NULL ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
2023-12-02 21:20:23 +01:00
DEBUG_FUNCTION_LINE_ERR ( " Failed to add stub item to root category " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
// add categoryLevel2 to categoryLevel1
if ( WUPSConfigAPI_Category_AddCategory ( categoryLevel1 , categoryLevel2 ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to add category to root item " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
// add categoryLevel2 to categoryLevel1
if ( WUPSConfigAPI_Category_AddCategory ( root , categoryLevel1 ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to add category to root item " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
}
{
// We can also directly add items to the root category
2023-12-16 17:16:43 +01:00
if ( WUPSConfigItemStub_AddToCategory ( root , " This is stub item without category " ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
2023-12-02 21:20:23 +01:00
DEBUG_FUNCTION_LINE_ERR ( " Failed to add stub item to root category " ) ;
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
ConfigItemMultipleValuesPair values [ 10 ] ;
int numOfElements = sizeof ( values ) / sizeof ( values [ 0 ] ) ;
for ( int i = 0 ; i < numOfElements ; i + + ) {
# define STR_SIZE 10
char * str = ( char * ) malloc ( STR_SIZE ) ;
if ( ! str ) {
OSFatal ( " Failed to allocate memory " ) ;
}
snprintf ( str , STR_SIZE , " %d " , i ) ;
values [ i ] . value = i ;
values [ i ] . valueName = str ;
}
2023-12-16 17:16:43 +01:00
WUPSConfigAPIStatus multValuesRes = WUPSConfigItemMultipleValues_AddToCategory ( root , " multival " , " Multiple values " , 0 , 0 , values , numOfElements , NULL ) ;
2023-12-02 21:20:23 +01:00
for ( int i = 0 ; i < sizeof ( values ) / sizeof ( values [ 0 ] ) ; i + + ) {
2023-12-16 17:16:43 +01:00
free ( ( void * ) values [ i ] . valueName ) ;
2023-12-02 21:20:23 +01:00
}
2023-12-16 17:16:43 +01:00
if ( multValuesRes ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
2023-12-02 21:20:23 +01:00
return WUPSCONFIG_API_CALLBACK_RESULT_ERROR ;
}
}
return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS ;
}
void ConfigMenuClosedCallback ( ) {
2023-12-14 17:20:38 +01:00
WUPSStorageAPI_SaveStorage ( false ) ;
2023-12-02 21:20:23 +01:00
}
2018-06-28 22:27:25 +02:00
/**
2023-02-25 20:51:48 +01:00
Gets called ONCE when the plugin was loaded .
2018-06-28 22:27:25 +02:00
* */
2022-02-03 16:24:36 +01:00
INITIALIZE_PLUGIN ( ) {
2023-02-25 20:51:48 +01:00
// Logging only works when compiled with `make DEBUG=1`. See the README for more information.
initLogging ( ) ;
2022-02-03 16:24:36 +01:00
DEBUG_FUNCTION_LINE ( " INITIALIZE_PLUGIN of example_plugin! " ) ;
2023-12-02 21:20:23 +01:00
WUPSConfigAPIOptionsV1 configOptions = { . name = " example_plugin " } ;
if ( WUPSConfigAPI_Init ( configOptions , ConfigMenuOpenedCallback , ConfigMenuClosedCallback ) ! = WUPSCONFIG_API_RESULT_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to init config api " ) ;
}
2023-12-14 17:20:38 +01:00
WUPSStorageError storageRes ;
// Try to get value from storage
if ( ( storageRes = WUPSStorageAPI_GetBool ( NULL , LOG_FS_OPEN_CONFIG_ID , & logFSOpen ) ) = = WUPS_STORAGE_ERROR_NOT_FOUND ) {
2022-09-04 09:46:40 +02:00
2023-12-14 17:20:38 +01:00
// Add the value to the storage if it's missing.
if ( WUPSStorageAPI_StoreBool ( NULL , LOG_FS_OPEN_CONFIG_ID , logFSOpen ) ! = WUPS_STORAGE_ERROR_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to store bool " ) ;
2022-09-04 09:46:40 +02:00
}
2023-12-14 17:20:38 +01:00
} else if ( storageRes ! = WUPS_STORAGE_ERROR_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to get bool %s (%d) " , WUPSConfigAPI_GetStatusStr ( storageRes ) , storageRes ) ;
} else {
DEBUG_FUNCTION_LINE_ERR ( " Successfully read the value from storage: %d %s (%d) " , logFSOpen , WUPSConfigAPI_GetStatusStr ( storageRes ) , storageRes ) ;
2021-09-24 19:57:15 +02:00
}
2023-12-14 17:20:38 +01:00
WUPSStorageAPI_SaveStorage ( false ) ;
2023-02-25 20:51:48 +01:00
deinitLogging ( ) ;
2018-06-28 22:27:25 +02:00
}
/**
2023-02-25 20:51:48 +01:00
Gets called when the plugin will be unloaded .
2018-06-28 22:27:25 +02:00
* */
2022-02-03 16:24:36 +01:00
DEINITIALIZE_PLUGIN ( ) {
2020-12-16 15:10:17 +01:00
DEBUG_FUNCTION_LINE ( " DEINITIALIZE_PLUGIN of example_plugin! " ) ;
2018-06-28 22:27:25 +02:00
}
/**
Gets called when an application starts .
* */
2022-02-03 16:24:36 +01:00
ON_APPLICATION_START ( ) {
2023-02-25 20:51:48 +01:00
initLogging ( ) ;
2018-06-28 22:27:25 +02:00
2020-12-16 15:10:17 +01:00
DEBUG_FUNCTION_LINE ( " ON_APPLICATION_START of example_plugin! " ) ;
2022-02-03 16:24:36 +01:00
}
2018-06-28 22:27:25 +02:00
2023-02-25 20:51:48 +01:00
/**
* Gets called when an application actually ends
*/
ON_APPLICATION_ENDS ( ) {
deinitLogging ( ) ;
}
2018-06-28 22:27:25 +02:00
/**
2021-04-06 12:32:44 +02:00
Gets called when an application request to exit .
2018-06-28 22:27:25 +02:00
* */
2022-02-03 16:24:36 +01:00
ON_APPLICATION_REQUESTS_EXIT ( ) {
2023-02-25 20:51:48 +01:00
DEBUG_FUNCTION_LINE_INFO ( " ON_APPLICATION_REQUESTS_EXIT of example_plugin! " ) ;
2018-06-28 22:27:25 +02:00
}
/**
This defines a function replacement .
It allows to replace the system function with an own function .
2023-02-25 20:51:48 +01:00
So whenever a game / application calls an overridden function , your function gets called instead .
2018-06-28 22:27:25 +02:00
Currently it ' s only possible to override functions that are loaded from . rpl files of OSv10 ( 00050010 - 1000400 A ) .
Signature of this macro :
DECL_FUNCTION ( RETURN_TYPE , ARBITRARY_NAME_OF_FUNCTION , ARGS_SEPERATED_BY_COMMA ) {
//Your code goes here.
}
Within this macro , two more function get declare you can use .
2023-02-25 20:51:48 +01:00
my_ARBITRARY_NAME_OF_FUNCTION and real_ARBITRARY_NAME_OF_FUNCTION
2018-06-28 22:27:25 +02:00
RETURN_TYPE my_ARBITRARY_NAME_OF_FUNCTION ( ARGS_SEPERATED_BY_COMMA ) :
is just name of the function that gets declared in this macro .
It has the same effect as calling the overridden function directly .
RETURN_TYPE real_ARBITRARY_NAME_OF_FUNCTION ( ARGS_SEPERATED_BY_COMMA ) :
is the name of the function , that leads to function that was overridden .
Use this to call the original function that will be overridden .
2023-02-25 20:51:48 +01:00
CAUTION : Other plugins may already have manipulated the return value or arguments .
2018-06-28 22:27:25 +02:00
2023-02-25 20:51:48 +01:00
Use this macro for each function you want to override
2018-06-28 22:27:25 +02:00
* */
DECL_FUNCTION ( int , FSOpenFile , FSClient * pClient , FSCmdBlock * pCmd , const char * path , const char * mode , int * handle , int error ) {
int result = real_FSOpenFile ( pClient , pCmd , path , mode , handle , error ) ;
2021-09-24 19:57:15 +02:00
if ( logFSOpen ) {
2023-02-25 20:51:48 +01:00
DEBUG_FUNCTION_LINE_INFO ( " FSOpenFile called for folder %s! Result %d " , path , result ) ;
2021-09-24 19:57:15 +02:00
}
2018-06-28 22:27:25 +02:00
return result ;
}
/**
This tells the loader which functions from which library ( . rpl ) should be replaced with which function from this file .
The list of possible libraries can be found in the wiki . ( In general it ' s WUPS_LOADER_LIBRARY_ + the name of the RPL in caps lock )
WUPS_MUST_REPLACE ( FUNCTION_NAME_IN_THIS_FILE , NAME_OF_LIB_WHICH_CONTAINS_THIS_FUNCTION , NAME_OF_FUNCTION_TO_OVERRIDE )
Define this for each function you want to override .
* */
2022-02-03 16:24:36 +01:00
WUPS_MUST_REPLACE ( FSOpenFile , WUPS_LOADER_LIBRARY_COREINIT , FSOpenFile ) ;