You've already forked ultrasm64-2
mirror of
https://github.com/HackerN64/ultrasm64-2.git
synced 2026-01-21 10:38:08 -08:00
git subrepo clone https://gitlab.com/parallel-launcher/libpl2 lib/libpl2
subrepo: subdir: "lib/libpl2" merged: "58e4fa38" upstream: origin: "https://gitlab.com/parallel-launcher/libpl2" branch: "master" commit: "58e4fa38" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo" commit: "4f60dd7"
This commit is contained in:
2
lib/libpl2/.gitignore
vendored
Normal file
2
lib/libpl2/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/public
|
||||
/.vscode
|
||||
11
lib/libpl2/.gitlab-ci.yml
Normal file
11
lib/libpl2/.gitlab-ci.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
image: ubuntu:rolling
|
||||
|
||||
pages:
|
||||
script:
|
||||
- apt update && apt install doxygen -y
|
||||
- doxygen
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
12
lib/libpl2/.gitrepo
Normal file
12
lib/libpl2/.gitrepo
Normal file
@@ -0,0 +1,12 @@
|
||||
; DO NOT EDIT (unless you know what you are doing)
|
||||
;
|
||||
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||
; git-subrepo command. See https://github.com/ingydotnet/git-subrepo#readme
|
||||
;
|
||||
[subrepo]
|
||||
remote = https://gitlab.com/parallel-launcher/libpl2
|
||||
branch = master
|
||||
commit = 58e4fa38badf31b732f853ab15689a55db65f3d2
|
||||
parent = 221c63e659988b7f37df82bd4897dc08fa70e82a
|
||||
method = merge
|
||||
cmdver = 0.4.9
|
||||
2512
lib/libpl2/Doxyfile
Normal file
2512
lib/libpl2/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
21
lib/libpl2/LICENSE
Normal file
21
lib/libpl2/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Matt Pharoah
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
6
lib/libpl2/README.md
Normal file
6
lib/libpl2/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# libpl2
|
||||
|
||||
libpl2 is a helper library to enable decomp roms to integrate with ParallelN64 and Parallel Launcher, allowing for features such as savestate detection, graphics plugin detection, and in-game romhacking.com integration.
|
||||
|
||||
You can find the documentation here:
|
||||
https://parallel-launcher.gitlab.io/libpl2/
|
||||
70
lib/libpl2/libpl2-emu.c
Normal file
70
lib/libpl2/libpl2-emu.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "libpl2-emu.h"
|
||||
|
||||
#include "libpl2-internal.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned short pluginId;
|
||||
unsigned short capabilities;
|
||||
char name[];
|
||||
} plugin_internal_t;
|
||||
|
||||
lpl2_bool lpl2_get_core_version( lpl2_version *version, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( version, err, FALSE )
|
||||
volatile const __lpl2_response *response = __lpl2_query_basic( 0x0001 );
|
||||
volatile const lpl2_version *payload = (volatile const lpl2_version*)response->payload;
|
||||
if( response->protocolStatus == 0 ) {
|
||||
version->major = payload->major;
|
||||
version->minor = payload->minor;
|
||||
version->patch = payload->patch;
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else {
|
||||
version->major = version->minor = version->patch = 0;
|
||||
if( err ) *err = LPL2_UNEXPECTED_ERROR( response->status );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
lpl2_cheat_flags lpl2_get_cheat_flags( lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, LPL2_NO_CHEAT_FLAGS )
|
||||
LPL2_VERIFY_ABI( 2, err, LPL2_NO_CHEAT_FLAGS )
|
||||
volatile const __lpl2_response *response = __lpl2_query_basic( 0x0005 );
|
||||
if( response->protocolStatus != 0 ) {
|
||||
if( err ) *err = LPL2_UNEXPECTED_ERROR( response->status );
|
||||
return LPL2_NO_CHEAT_FLAGS;
|
||||
}
|
||||
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return (lpl2_cheat_flags)response->commandStatus;
|
||||
}
|
||||
|
||||
lpl2_cheat_flags lpl2_clear_cheat_flags( lpl2_cheat_flags flags, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, LPL2_NO_CHEAT_FLAGS )
|
||||
LPL2_VERIFY_ABI( 2, err, LPL2_NO_CHEAT_FLAGS )
|
||||
volatile const __lpl2_response *response = __lpl2_query_byte( 0x0006, (unsigned char)flags );
|
||||
if( response->protocolStatus != 0 ) {
|
||||
if( err ) *err = LPL2_UNEXPECTED_ERROR( response->status );
|
||||
return LPL2_NO_CHEAT_FLAGS;
|
||||
}
|
||||
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return (lpl2_cheat_flags)response->commandStatus;
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_get_graphics_plugin( lpl2_plugin_info *plugin, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( plugin, err, FALSE )
|
||||
volatile const __lpl2_response *response = __lpl2_query_basic( 0x0004 );
|
||||
volatile const plugin_internal_t *payload = (volatile const plugin_internal_t*)response->payload;
|
||||
if( response->status == 0 ) {
|
||||
plugin->pluginId = (lpl2_gfx_plugin)payload->pluginId;
|
||||
plugin->capabilities = (lpl2_gfx_capabilities)payload->capabilities;
|
||||
plugin->name[__lpl2_strcpy( plugin->name, payload->name, 9 )] = '\0';
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else {
|
||||
if( err ) *err = LPL2_UNEXPECTED_ERROR( response->status );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
141
lib/libpl2/libpl2-emu.h
Normal file
141
lib/libpl2/libpl2-emu.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef LIBPL2_EMU_
|
||||
#define LIBPL2_EMU_
|
||||
|
||||
#include "libpl2-error.h"
|
||||
#include "libpl2-version.h"
|
||||
#include "libpl2-stddef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! @defgroup page_emu Emulator Commands
|
||||
*
|
||||
* The functions on this page are handled directly by the emulator core. They
|
||||
* will function even if the emulator core is extracted from Parallel Launcher
|
||||
* and put into a normal RetroArch installation.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! Graphics plugins */
|
||||
typedef enum {
|
||||
LPL2_PLUGIN_PARALLEL = 1, /*!< ParaLLEl */
|
||||
LPL2_PLUGIN_GLIDEN64 = 2, /*!< GlideN64 */
|
||||
LPL2_PLUGIN_OGRE = 3, /*!< OGRE */
|
||||
LPL2_PLUGIN_GLIDE64 = 4, /*!< Glide64 */
|
||||
LPL2_PLUGIN_ANGRYLION = 5, /*!< Angrylion */
|
||||
LPL2_PLUGIN_RICE = 6, /*!< Rice */
|
||||
LPL2_GLN64 = 7, /*!< gln64 */
|
||||
} lpl2_gfx_plugin;
|
||||
|
||||
/*! Graphics plugin capabilities */
|
||||
typedef enum {
|
||||
/*! Indicates that the plugin is rendering at higher resolutions than an actual N64.
|
||||
* @note The ParaLLEl plugin will have this bit set to 0 if its upscaling factor is set to 1
|
||||
*/
|
||||
LPL2_GFX_UPSCALING = 0x0001,
|
||||
|
||||
/*! Indicates that framebuffer emulation is currently enabled on this plugin */
|
||||
LPL2_GFX_FRAMEBUFFER_EMULATION = 0x0002,
|
||||
|
||||
/*! Indicates that the plugin is currently handling depth comparisons accurately (ie. decals will work properly) */
|
||||
LPL2_GFX_ACCURATE_DEPTH_COMPARE = 0x0004,
|
||||
|
||||
/*! Indicates that accurate LLE RSP emulation is being used
|
||||
* @since LIBPL_ABI_VERSION_5
|
||||
*/
|
||||
LPL2_GFX_RSP_EMULATION = 0x0008,
|
||||
|
||||
/*! Indicates that the widescreen viewport hack is being used (GLideN64/OGRE)
|
||||
* @since LIBPL_ABI_VERSION_6
|
||||
*/
|
||||
LPL2_WIDESCREEN_VIEWPORT = 0x0010,
|
||||
} lpl2_gfx_capabilities;
|
||||
|
||||
/*! Cheat status flags */
|
||||
typedef enum {
|
||||
LPL2_USED_CHEATS = 0x01, /*!< Gameshark codes have been used **/
|
||||
LPL2_USED_SAVESTATES = 0x02, /*!< A savestate has been loaded **/
|
||||
LPL2_USED_SLOWDOWN = 0x04, /*!< Emulator slowdown has been used **/
|
||||
LPL2_USED_FRAME_ADVANCE = 0x08, /*!< The emulation has been advanced in frame by frame mode **/
|
||||
LPL2_USED_SPEEDUP = 0x10, /*!< The emulation has been sped up @since LIBPL_ABI_VERSION_4 **/
|
||||
|
||||
// convenience values for clearing flags
|
||||
LPL2_ALL_CHEAT_FLAGS = 0xff, /*!< A mask that covers all flags */
|
||||
LPL2_ALL_TAS_FLAGS = 0xfe, /*!< A mask that covers all flags except for @ref LPL2_USED_CHEATS */
|
||||
LPL2_NO_CHEAT_FLAGS = 0x00 /*!< An empty mask with no flags set */
|
||||
} lpl2_cheat_flags;
|
||||
|
||||
/*! A structure containing information about the current graphics plugin and its settings */
|
||||
typedef struct {
|
||||
lpl2_gfx_plugin pluginId;
|
||||
lpl2_gfx_capabilities capabilities;
|
||||
char name[10];
|
||||
} lpl2_plugin_info;
|
||||
|
||||
/*! Gets the emulator core version
|
||||
*
|
||||
* @param[out] version A pointer to an @ref lpl2_version struct where the ParallelN64 emulator core version will be stored
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE on success, FALSE on an error.
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS version is NULL
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
*
|
||||
* @see ::lpl2_get_launcher_version
|
||||
*/
|
||||
lpl2_bool lpl2_get_core_version( lpl2_version *version, lpl2_err *err ) __attribute__((access(write_only, 1), access(write_only, 2)));
|
||||
|
||||
/*! Check if any cheats or TAS tools have been used.
|
||||
*
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return The current state of the cheat flags.
|
||||
*
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
*
|
||||
* @since LPL_ABI_VERSION_2
|
||||
*/
|
||||
lpl2_cheat_flags lpl2_get_cheat_flags( lpl2_err *err ) __attribute__((access(write_only, 1), warn_unused_result));
|
||||
|
||||
/*! Clears the specified cheat flags, meaning that the next call to @ref lpl2_get_graphics_plugin will no longer report this
|
||||
* cheat as having been used. If the user is actively using cheats at the time this is called, the flags for the active cheats
|
||||
* will not be cleared.
|
||||
*
|
||||
* @param[in] flags A bitmask of the cheat flags to clear
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return The new state of the cheat flags.
|
||||
*
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
*
|
||||
* @since LPL_ABI_VERSION_2
|
||||
*/
|
||||
lpl2_cheat_flags lpl2_clear_cheat_flags( lpl2_cheat_flags flags, lpl2_err *err ) __attribute__((access(write_only, 2)));
|
||||
|
||||
/*! Gets information about the current graphics plugin
|
||||
* @param[out] plugin A pointer to a @ref lpl2_plugin_info struct where the plugin info will be stored
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE on success, FALSE on an error.
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS plugin is NULL
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
*/
|
||||
lpl2_bool lpl2_get_graphics_plugin( lpl2_plugin_info *plugin, lpl2_err *err ) __attribute__((access(write_only, 1), access(write_only, 2)));
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
59
lib/libpl2/libpl2-error.c
Normal file
59
lib/libpl2/libpl2-error.c
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "libpl2-error.h"
|
||||
|
||||
const char *lpl2_get_error_enum_string( lpl2_err error ) {
|
||||
switch( error ) {
|
||||
case LPL2_ERR_OKAY: return "LPL2_ERR_OKAY";
|
||||
case LPL2_ERR_WAIT: return "LPL2_ERR_WAIT";
|
||||
|
||||
case LPL2_ERR_INVALID_ARGUMENTS: return "LPL2_ERR_INVALID_ARGUMENTS";
|
||||
case LPL2_ERR_MISALIGNED_POINTER_ARG: return "LPL2_ERR_MISALIGNED_POINTER_ARG";
|
||||
case LPL2_ERR_BROKEN_PIPE: return "LPL2_ERR_BROKEN_PIPE";
|
||||
|
||||
case LPL2_ERR_LIBPL_NOT_INITIALIZED: return "LPL2_ERR_LIBPL_NOT_INITIALIZED";
|
||||
case LPL2_ERR_LIBPL_NOT_SUPPORTED: return "LPL2_ERR_LIBPL_NOT_SUPPORTED";
|
||||
case LPL2_ERR_LIBPL_OLD_ABI: return "LPL2_ERR_LIBPL_OLD_ABI";
|
||||
|
||||
case LPL2_ERR_SD_CARD_ALREADY_LOADED: return "LPL2_ERR_SD_CARD_ALREADY_LOADED";
|
||||
case LPL2_ERR_SD_CARD_ALREADY_EXISTS: return "LPL2_ERR_SD_CARD_ALREADY_EXISTS";
|
||||
case LPL2_ERR_SD_CARD_CORRUPTED: return "LPL2_ERR_SD_CARD_CORRUPTED";
|
||||
case LPL2_ERR_SD_CARD_CREATE_ERROR: return "LPL2_ERR_SD_CARD_CREATE_ERROR";
|
||||
case LPL2_ERR_SD_CARD_NOT_FOUND: return "LPL2_ERR_SD_CARD_NOT_FOUND";
|
||||
|
||||
case LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED: return "LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED";
|
||||
case LPL2_ERR_RHDC_NETWORK_ERROR: return "LPL2_ERR_RHDC_NETWORK_ERROR";
|
||||
case LPL2_ERR_RHDC_RATE_LIMIT: return "LPL2_ERR_RHDC_RATE_LIMIT";
|
||||
case LPL2_ERR_RHDC_AVATAR_NOT_FOUND: return "LPL2_ERR_RHDC_AVATAR_NOT_FOUND";
|
||||
case LPL2_ERR_RHDC_AVATAR_INVALID: return "LPL2_ERR_RHDC_AVATAR_INVALID";
|
||||
|
||||
default: return "LPL2_ERR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const char *lpl2_get_error_description( lpl2_err error ) {
|
||||
switch( error ) {
|
||||
case LPL2_ERR_OKAY: return "No error";
|
||||
case LPL2_ERR_WAIT: return "Waiting on async result (not an error)";
|
||||
|
||||
case LPL2_ERR_INVALID_ARGUMENTS: return "One or more arguments passed to the function are invalid";
|
||||
case LPL2_ERR_MISALIGNED_POINTER_ARG: return "One or more pointer arguments passed to the function has incorrect alignment";
|
||||
case LPL2_ERR_BROKEN_PIPE: return "The connection to Parallel Launcher has been lost";
|
||||
|
||||
case LPL2_ERR_LIBPL_NOT_INITIALIZED: return "lpl2_init has not been called yet";
|
||||
case LPL2_ERR_LIBPL_NOT_SUPPORTED: return "The emulator does not support libpl";
|
||||
case LPL2_ERR_LIBPL_OLD_ABI: return "The function you are trying to use is from a newer ABI than the one you provied in your lpl2_init call";
|
||||
|
||||
case LPL2_ERR_SD_CARD_ALREADY_LOADED: return "An SD card has already been loaded";
|
||||
case LPL2_ERR_SD_CARD_ALREADY_EXISTS: return "An SD card with the given uid already exists";
|
||||
case LPL2_ERR_SD_CARD_CORRUPTED: return "The emulator failed to load the SD card image";
|
||||
case LPL2_ERR_SD_CARD_CREATE_ERROR: return "An unknown error occurred creating the SD card image";
|
||||
case LPL2_ERR_SD_CARD_NOT_FOUND: return "An SD card with the given uid does not exist";
|
||||
|
||||
case LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED: return "The user has not enabled RHDC integration";
|
||||
case LPL2_ERR_RHDC_NETWORK_ERROR: return "A network error occurred while calling RHDC";
|
||||
case LPL2_ERR_RHDC_RATE_LIMIT: return "The emulator refused to run this command because you are making too many requests to RHDC too quickly";
|
||||
case LPL2_ERR_RHDC_AVATAR_NOT_FOUND: return "The user either does not exist or does not have an avatar";
|
||||
case LPL2_ERR_RHDC_AVATAR_INVALID: return "An image processing error occurred";
|
||||
|
||||
default: return "UNKNOWN: Error code does not match a known libpl2 error";
|
||||
}
|
||||
}
|
||||
62
lib/libpl2/libpl2-error.h
Normal file
62
lib/libpl2/libpl2-error.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef LIBPL2_ERROR_
|
||||
#define LIBPL2_ERROR_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! @defgroup page_error_codes Error Codes
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! libpl2 error codes
|
||||
* Almost all libpl2 functions take in an optional err pointer. When a non-NULL pointer is passed in, its value will be set to one
|
||||
* of the documented error codes.
|
||||
*/
|
||||
typedef enum {
|
||||
LPL2_ERR_OKAY = 0x0000, /*!< No error */
|
||||
LPL2_ERR_WAIT = 0x0001, /*!< Waiting on async result (not an error) */
|
||||
|
||||
LPL2_ERR_INVALID_ARGUMENTS = 0x0101, /*!< One or more arguments passed to the function are invalid */
|
||||
LPL2_ERR_MISALIGNED_POINTER_ARG = 0x0102, /*!< One or more pointer arguments passed to the function has incorrect alignment */
|
||||
LPL2_ERR_BROKEN_PIPE = 0x0103, /*!< The connection to Parallel Launcher has been lost */
|
||||
|
||||
LPL2_ERR_LIBPL_NOT_INITIALIZED = 0x0301, /*!< @ref lpl2_init has not been called yet */
|
||||
LPL2_ERR_LIBPL_NOT_SUPPORTED = 0x0302, /*!< The emulator does not support libpl */
|
||||
LPL2_ERR_LIBPL_OLD_ABI = 0x0303, /*!< The function you are trying to use is from a newer ABI than the one you provied in your @ref lpl2_init call */
|
||||
|
||||
LPL2_ERR_SD_CARD_ALREADY_LOADED = 0x0401, /*!< An SD card has already been loaded */
|
||||
LPL2_ERR_SD_CARD_ALREADY_EXISTS = 0x0402, /*!< An SD card with the given uid already exists */
|
||||
LPL2_ERR_SD_CARD_CORRUPTED = 0x0403, /*!< The emulator failed to load the SD card image */
|
||||
LPL2_ERR_SD_CARD_NOT_FOUND = 0x0404, /*!< An SD card with the given uid does not exist */
|
||||
LPL2_ERR_SD_CARD_CREATE_ERROR = 0x0405, /*!< An unknown error occurred creating the SD card image */
|
||||
|
||||
LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED = 0x0501, /*!< The user has not enabled RHDC integration */
|
||||
LPL2_ERR_RHDC_NETWORK_ERROR = 0x0502, /*!< A network error occurred while calling RHDC */
|
||||
LPL2_ERR_RHDC_RATE_LIMIT = 0x0503, /*!< The emulator refused to run this command because you are making too many requests to RHDC too quickly */
|
||||
LPL2_ERR_RHDC_AVATAR_NOT_FOUND = 0x0504, /*!< The user either does not exist or does not have an avatar */
|
||||
LPL2_ERR_RHDC_AVATAR_INVALID = 0x0505, /*!< An image processing error occurred */
|
||||
} lpl2_err;
|
||||
|
||||
/*! Returns a string containing the name of the enum value for the given error code. Useful for printing debug messages.
|
||||
*
|
||||
* @param error An error code set by libpl2 function
|
||||
* @return A pointer to a string in static memory containing the enum name (or LPL2_ERR_UNKNOWN for an unknown error code)
|
||||
*/
|
||||
const char *lpl2_get_error_enum_string( lpl2_err error ) __attribute__((pure, warn_unused_result, returns_nonnull));
|
||||
|
||||
/*! Returns a string containing a description of what the given error code means. Useful for printing debug messages.
|
||||
*
|
||||
* @param error An error code set by libpl2 function
|
||||
* @return A pointer to a string in static memory describing what the error code means
|
||||
*/
|
||||
const char *lpl2_get_error_description( lpl2_err error ) __attribute__((pure, warn_unused_result, returns_nonnull));
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
lib/libpl2/libpl2-init.c
Normal file
82
lib/libpl2/libpl2-init.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "libpl2-init.h"
|
||||
|
||||
#ifdef LIBDRAGON
|
||||
#include <libdragon.h>
|
||||
#else
|
||||
#include <ultra64.h>
|
||||
#endif
|
||||
|
||||
#include "libpl2-internal.h"
|
||||
#include "libpl2-launcher.h"
|
||||
#include "libpl2-emu.h"
|
||||
|
||||
struct lpl_abi_requirements {
|
||||
lpl2_version coreVersion;
|
||||
lpl2_version launcherVersion;
|
||||
};
|
||||
|
||||
static const struct lpl_abi_requirements sAbiReqs[] = {
|
||||
{ { 2, 13, 0 }, { 0, 0, 0 } }, // LIBPL_ABI_VERSION_2
|
||||
{ { 2, 13, 0 }, { 6, 20, 0 } }, // LIBPL_ABI_VERSION_3
|
||||
{ { 2, 14, 3 }, { 6, 22, 0 } }, // LIBPL_ABI_VERSION_4
|
||||
{ { 2, 15, 0 }, { 6, 22, 0 } }, // LIBPL_ABI_VERSION_5
|
||||
{ { 2, 16, 0 }, { 6, 22, 0 } }, // LIBPL_ABI_VERSION_6
|
||||
{ { 2, 16, 0 }, { 7, 10, 1 } }, // LIBPL_ABI_VERSION_7
|
||||
};
|
||||
|
||||
lpl2_bool lpl2_init( libpl_abi_version minimumAbiVersion, lpl2_err *err ) {
|
||||
if( __libpl2_status == __LPL2_INITIALIZED && minimumAbiVersion <= __libpl2_abi ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__libpl2_status = __LPL2_NOT_SUPPORTED;
|
||||
if( minimumAbiVersion < LIBPL_ABI_VERSION_1 || minimumAbiVersion > LIBPL_ABI_VERSION_CURRENT ) {
|
||||
if( err ) *err = LPL2_ERR_INVALID_ARGUMENTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
__libpl2_abi = (int)minimumAbiVersion;
|
||||
if( minimumAbiVersion == LIBPL_ABI_VERSION_1 ) {
|
||||
__libpl2_status = __LPL2_INITIALIZED;
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef LIBDRAGON
|
||||
io_write( 0x1ffb0000u, 0u );
|
||||
const unsigned int response = io_read( 0x1ffb0000u );
|
||||
#else
|
||||
unsigned int response = 0;
|
||||
osPiWriteIo( 0x1ffb0000u, 0u );
|
||||
osPiReadIo( 0x1ffb0000u, &response );
|
||||
#endif
|
||||
if( response != 0x00500000u ) {
|
||||
if( err ) *err = LPL2_ERR_LIBPL_NOT_SUPPORTED;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lpl2_version version;
|
||||
__libpl2_status = __LPL2_INITIALIZED;
|
||||
|
||||
if( !lpl2_get_core_version( &version, NULL ) || lpl2_compare_versions( &version, &sAbiReqs[(int)minimumAbiVersion - 2].coreVersion ) < 0 ) {
|
||||
__libpl2_status = __LPL2_NOT_SUPPORTED;
|
||||
if( err ) *err = LPL2_ERR_LIBPL_OLD_ABI;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if( minimumAbiVersion == LIBPL_ABI_VERSION_2 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
lpl2_err plErr;
|
||||
if( !lpl2_get_launcher_version( &version, &plErr ) || lpl2_compare_versions( &version, &sAbiReqs[(int)minimumAbiVersion - 2].launcherVersion ) < 0 ) {
|
||||
__libpl2_status = __LPL2_NOT_SUPPORTED;
|
||||
if( err ) *err = (plErr == LPL2_ERR_BROKEN_PIPE) ? LPL2_ERR_BROKEN_PIPE : LPL2_ERR_LIBPL_OLD_ABI;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
}
|
||||
49
lib/libpl2/libpl2-init.h
Normal file
49
lib/libpl2/libpl2-init.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef LIBPL2_INIT_
|
||||
#define LIBPL2_INIT_
|
||||
|
||||
#include "libpl2-stddef.h"
|
||||
#include "libpl2-error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! @defgroup page_init Initialization
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! libpl ABI versions */
|
||||
typedef enum {
|
||||
LIBPL_ABI_VERSION_1 = 1, /*!< initial libpl prototype (2023-07-17) */
|
||||
LIBPL_ABI_VERSION_2 = 2, /*!< revised prototype (2023-08-1) */
|
||||
LIBPL_ABI_VERSION_3 = 3, /*!< first advertised public release (2023-08-1) */
|
||||
LIBPL_ABI_VERSION_4 = 4, /*!< SD card update (2023-10-03) */
|
||||
LIBPL_ABI_VERSION_5 = 5, /*!< LLE RSP check (2024-02-16) */
|
||||
LIBPL_ABI_VERSION_6 = 6, /*!< Widescreen viewport check (2024-03-05) */
|
||||
LIBPL_ABI_VERSION_7 = 7, /*!< Variable size RHDC avatar fetching (2025-01-04) */
|
||||
LIBPL_ABI_VERSION_CURRENT = LIBPL_ABI_VERSION_7 /*!< the latest version */
|
||||
} libpl_abi_version;
|
||||
|
||||
/*! Initializes libpl and checks if it is supported by the emulator.
|
||||
* This function should be called before any other libpl function.
|
||||
*
|
||||
* @param[in] minimumAbiVersion The required libpl ABI version
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE if the emulator supports the requested version of libpl or later
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS minimumAbiVersion is invalid
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI the emulator does not support the requested ABI version. You may try calling lpl2_init again with a lower ABI version.
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the emulator core appears to support libpl, however, it failed to establish a connection with Parallel Launcher
|
||||
*/
|
||||
lpl2_bool lpl2_init( libpl_abi_version minimumAbiVersion, lpl2_err *err ) __attribute__((access(write_only, 2)));
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
52
lib/libpl2/libpl2-internal.c
Normal file
52
lib/libpl2/libpl2-internal.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "libpl2-internal.h"
|
||||
|
||||
enum __libpl2_status_t __libpl2_status = __LPL2_INITIALIZED;
|
||||
unsigned int __libpl2_abi = 0;
|
||||
|
||||
typedef struct {
|
||||
unsigned short commandId;
|
||||
unsigned short payloadSize;
|
||||
char payload[];
|
||||
} __lpl2_request;
|
||||
|
||||
static volatile __lpl2_request *g_request = (volatile __lpl2_request*)0xbffb0000u;
|
||||
|
||||
unsigned short __lpl2_strcpy( volatile char *dest, volatile const char *src, unsigned short maxChars ) {
|
||||
unsigned short len = 0;
|
||||
while( *src != '\0' && len < maxChars ) {
|
||||
dest[len++] = *(src++);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *__lpl2_query_basic( unsigned short commandId ) {
|
||||
g_request->payloadSize = 0;
|
||||
g_request->commandId = commandId;
|
||||
return (volatile __lpl2_response*)g_request;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *__lpl2_query_string( unsigned short commandId, const char *arg ) {
|
||||
g_request->payloadSize = __lpl2_strcpy( (char*)g_request->payload, arg, 0xFFFC );
|
||||
g_request->commandId = commandId;
|
||||
return (volatile __lpl2_response*)g_request;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *__lpl2_query_byte( unsigned short commandId, unsigned char arg ) {
|
||||
g_request->payloadSize = 1;
|
||||
g_request->payload[0] = (char)arg;
|
||||
g_request->commandId = commandId;
|
||||
return (volatile __lpl2_response*)g_request;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *__lpl2_query_uint( unsigned short commandId, unsigned int arg ) {
|
||||
g_request->payloadSize = 4;
|
||||
*((volatile unsigned int*)g_request->payload) = arg;
|
||||
g_request->commandId = commandId;
|
||||
return (volatile __lpl2_response*)g_request;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *__lpl2_payload_send( unsigned short commandId, unsigned short payloadSize ) {
|
||||
g_request->payloadSize = payloadSize;
|
||||
g_request->commandId = commandId;
|
||||
return (volatile __lpl2_response*)g_request;
|
||||
}
|
||||
66
lib/libpl2/libpl2-internal.h
Normal file
66
lib/libpl2/libpl2-internal.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef LIBPL2_INTERNAL_
|
||||
#define LIBPL2_INTERNAL_
|
||||
|
||||
#include "libpl2-error.h"
|
||||
#include "libpl2-stddef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern enum __libpl2_status_t {
|
||||
__LPL2_NOT_INITIALIZED = 2,
|
||||
__LPL2_NOT_SUPPORTED = 1,
|
||||
__LPL2_INITIALIZED = 0
|
||||
} __libpl2_status;
|
||||
|
||||
extern unsigned int __libpl2_abi;
|
||||
|
||||
#define LPL2_VERIFY_INITIALIZED( errPtr, returnValue ) \
|
||||
if( __libpl2_status != __LPL2_INITIALIZED ) { \
|
||||
if( errPtr ) *errPtr = (__libpl2_status == __LPL2_NOT_INITIALIZED) ? LPL2_ERR_LIBPL_NOT_INITIALIZED : LPL2_ERR_LIBPL_NOT_SUPPORTED; \
|
||||
return returnValue; \
|
||||
}
|
||||
|
||||
#define LPL2_VERIFY_ABI( minAbiVersion, errPtr, returnValue ) \
|
||||
if( __libpl2_abi < minAbiVersion ) { \
|
||||
if( errPtr ) *errPtr = LPL2_ERR_LIBPL_OLD_ABI; \
|
||||
return returnValue; \
|
||||
}
|
||||
|
||||
#define LPL2_VERIFY_NOTNULL( arg, errPtr, returnValue ) \
|
||||
if( arg == NULL ) { \
|
||||
if( errPtr ) *errPtr = LPL2_ERR_INVALID_ARGUMENTS; \
|
||||
return returnValue; \
|
||||
}
|
||||
|
||||
#define LPL2_UNEXPECTED_ERROR( status ) ((lpl2_err)((unsigned short)0x8000 | (unsigned short)status))
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
unsigned char protocolStatus;
|
||||
unsigned char commandStatus;
|
||||
};
|
||||
unsigned short status;
|
||||
};
|
||||
unsigned short payloadSize;
|
||||
char payload[];
|
||||
} __attribute__((aligned(8))) __lpl2_response;
|
||||
|
||||
// Copies a string up to but NOT INCLUDING the null terminator or until maxChars are copied
|
||||
unsigned short __lpl2_strcpy( volatile char *dest, volatile const char *src, unsigned short maxChars ) __attribute__((nonnull(1,2)));
|
||||
|
||||
volatile const __lpl2_response *__lpl2_query_basic( unsigned short commandId ) __attribute__((returns_nonnull));
|
||||
volatile const __lpl2_response *__lpl2_query_string( unsigned short commandId, const char *arg ) __attribute__((returns_nonnull, nonnull(2)));
|
||||
volatile const __lpl2_response *__lpl2_query_byte( unsigned short commandId, unsigned char arg ) __attribute__((returns_nonnull));
|
||||
volatile const __lpl2_response *__lpl2_query_uint( unsigned short commandId, unsigned int arg ) __attribute__((returns_nonnull));
|
||||
|
||||
inline __attribute__((always_inline, assume_aligned(4), const)) volatile char *__lpl2_payload_start() { return (volatile char*)0xbffb0004u; }
|
||||
volatile const __lpl2_response *__lpl2_payload_send( unsigned short commandId, unsigned short payloadSize ) __attribute__((returns_nonnull));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
152
lib/libpl2/libpl2-launcher.c
Normal file
152
lib/libpl2/libpl2-launcher.c
Normal file
@@ -0,0 +1,152 @@
|
||||
#include "libpl2-launcher.h"
|
||||
|
||||
#include "libpl2-internal.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
unsigned char format;
|
||||
char name[];
|
||||
} sdcard_internal_t;
|
||||
|
||||
lpl2_bool lpl2_get_launcher_version( lpl2_version *version, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 3, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( version, err, FALSE )
|
||||
volatile const __lpl2_response *response = __lpl2_query_basic( 0x0100 );
|
||||
volatile const lpl2_version *payload = (volatile const lpl2_version*)response->payload;
|
||||
if( response->status == 0 ) {
|
||||
version->major = payload->major;
|
||||
version->minor = payload->minor;
|
||||
version->patch = payload->patch;
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else {
|
||||
version->major = version->minor = version->patch = 0;
|
||||
if( err ) {
|
||||
switch( response->protocolStatus ) {
|
||||
case 3: case 4: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_get_sd_card_info( const char *uid, lpl2_sd_card_info *info, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 4, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( uid, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( info, err, FALSE )
|
||||
|
||||
volatile const __lpl2_response *response = __lpl2_query_string( 0x0101, uid );
|
||||
volatile const sdcard_internal_t *payload = (volatile const sdcard_internal_t*)response->payload;
|
||||
if( response->status == 0 ) {
|
||||
info->size = payload->size;
|
||||
info->format = (lpl2_sd_format)payload->format;
|
||||
info->name[__lpl2_strcpy( info->name, payload->name, response->payloadSize - 5 )] = '\0';
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 1: *err = LPL2_ERR_SD_CARD_CORRUPTED; break;
|
||||
case 4: *err = LPL2_ERR_SD_CARD_NOT_FOUND; break;
|
||||
case 0x200: case 0x600: *err = LPL2_ERR_INVALID_ARGUMENTS; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_create_sd_card( const char *uid, const char *name, lpl2_sd_format format, unsigned char sizeMiB, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 4, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( uid, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( name, err, FALSE )
|
||||
|
||||
volatile char *requestPayload = __lpl2_payload_start();
|
||||
requestPayload[0] = (char)sizeMiB;
|
||||
requestPayload[1] = (char)format;
|
||||
|
||||
const unsigned short nameLen = __lpl2_strcpy( &requestPayload[2], name, 12 );
|
||||
if( nameLen == 0 || nameLen > 11 ) {
|
||||
if( err ) *err = LPL2_ERR_INVALID_ARGUMENTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
requestPayload[nameLen + 2] = '\0';
|
||||
const unsigned short uidLen = __lpl2_strcpy( &requestPayload[nameLen + 3], uid, 37 );
|
||||
if( uidLen == 0 || uidLen > 36 ) {
|
||||
if( err ) *err = LPL2_ERR_INVALID_ARGUMENTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
requestPayload[nameLen + uidLen + 3] = '\0';
|
||||
volatile const __lpl2_response *response = __lpl2_payload_send( 0x0102, nameLen + uidLen + 4 );
|
||||
if( response->status == 0 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 1: *err = LPL2_ERR_SD_CARD_ALREADY_LOADED; break;
|
||||
case 2: *err = LPL2_ERR_SD_CARD_CORRUPTED; break;
|
||||
case 3: *err = LPL2_ERR_SD_CARD_CREATE_ERROR; break;
|
||||
case 5: case 6: *err = LPL2_ERR_SD_CARD_ALREADY_EXISTS; break;
|
||||
case 0x200: case 0x600: *err = LPL2_ERR_INVALID_ARGUMENTS; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_create_auto_sd_card( lpl2_sd_format format, unsigned char sizeMiB, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 4, err, FALSE )
|
||||
|
||||
volatile char *requestPayload = __lpl2_payload_start();
|
||||
requestPayload[0] = (char)sizeMiB;
|
||||
requestPayload[1] = (char)format;
|
||||
|
||||
volatile const __lpl2_response *response = __lpl2_payload_send( 0x0103, 2 );
|
||||
if( response->status == 0 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 1: *err = LPL2_ERR_SD_CARD_ALREADY_LOADED; break;
|
||||
case 2: *err = LPL2_ERR_SD_CARD_CORRUPTED; break;
|
||||
case 3: *err = LPL2_ERR_SD_CARD_CREATE_ERROR; break;
|
||||
case 0x600: *err = LPL2_ERR_INVALID_ARGUMENTS; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_load_sd_card( const char *uid, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 4, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( uid, err, FALSE )
|
||||
|
||||
volatile const __lpl2_response *response = __lpl2_query_string( 0x0104, uid );
|
||||
if( response->status == 0 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
return TRUE;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 1: *err = LPL2_ERR_SD_CARD_ALREADY_LOADED; break;
|
||||
case 2: *err = LPL2_ERR_SD_CARD_CORRUPTED; break;
|
||||
case 4: *err = LPL2_ERR_SD_CARD_NOT_FOUND; break;
|
||||
case 0x200: case 0x600: *err = LPL2_ERR_INVALID_ARGUMENTS; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
153
lib/libpl2/libpl2-launcher.h
Normal file
153
lib/libpl2/libpl2-launcher.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#ifndef LIBPL2_LAUNCHER_
|
||||
#define LIBPL2_LAUNCHER_
|
||||
|
||||
#include "libpl2-error.h"
|
||||
#include "libpl2-version.h"
|
||||
#include "libpl2-stddef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! @defgroup page_launcher Parallel Launcher Commands
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! SD card formats */
|
||||
typedef enum __attribute__((packed)) {
|
||||
LPL2_SD_UNFORMATTED = 0, /*!< Unformatted */
|
||||
LPL2_SD_FAT12 = 12, /*!< FAT-12 */
|
||||
LPL2_SD_FAT16 = 16, /*!< FAT-16 */
|
||||
LPL2_SD_FAT32 = 32, /*!< FAT-32 */
|
||||
} lpl2_sd_format;
|
||||
|
||||
/*! SD card info */
|
||||
typedef struct {
|
||||
unsigned int size; /*!< The size of the SD card in bytes */
|
||||
lpl2_sd_format format; /*!< The filesystem format of the SD card */
|
||||
char name[12]; /*< The name of the SD card */
|
||||
} lpl2_sd_card_info;
|
||||
|
||||
/*! Gets the emulator core version
|
||||
*
|
||||
* @param[out] version A pointer to an @ref lpl2_version struct where the Parallel Launcher version will be stored
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE on success, FALSE on an error.
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS version is NULL
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
*
|
||||
* @see ::lpl2_get_core_version
|
||||
*/
|
||||
lpl2_bool lpl2_get_launcher_version( lpl2_version *version, lpl2_err *err ) __attribute__((access(write_only, 1), access(write_only, 2)));
|
||||
|
||||
/*! Fetches info about an SD card created with @ref lpl2_create_sd_card. This can be used to check if a shared SD card exists and
|
||||
* has the expected size and format before loading it.
|
||||
*
|
||||
* @param[in] uid A unique string identifying the shared SD card (max 36 characters)
|
||||
* @param[out] info A pointer to a struct where the SD card information will be stored
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE on success, FALSE on an error.
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS info or uid is NULL or uid is empty or too long
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_SD_CARD_NOT_FOUND no SD card with the given uid was found
|
||||
* @exception LPL2_ERR_SD_CARD_CORRUPTED an SD card with the uid exists, but the file could not be accessed
|
||||
*
|
||||
* @since LPL_ABI_VERSION_4
|
||||
*/
|
||||
lpl2_bool lpl2_get_sd_card_info( const char *uid, lpl2_sd_card_info *info, lpl2_err *err ) __attribute__((access(write_only, 2), access(write_only, 3)));
|
||||
|
||||
/*! Creates a new SD card and loads it. This function can only be used to create an SD card when the user has not already selected
|
||||
* one in Parallel Launcher. If the user has already loaded an SD card, this function will do nothing and return FALSE.
|
||||
*
|
||||
* Unlike @ref lpl2_create_auto_sd_card, this function requires you to provide a unique identifier for the SD card. Any other
|
||||
* ROM can request this card by passing the same uid to @ref lpl2_load_sd_card. This allows collaborating romhacks to share a
|
||||
* common SD card.
|
||||
*
|
||||
* @param[in] uid A unique string that the shared SD card can be identified with (max 36 characters)
|
||||
* @param[in] name The filename of the SD card and the volume name for FAT formatted cards (max 11 characters)
|
||||
* @param[in] format The format of the SD card
|
||||
* @param[in] sizeMiB The desired size of the SD card in MiB (2^20 bytes). \n
|
||||
* For FAT12, sizeMiB must be between 1 and 32 \n
|
||||
* For FAT16 and FAT32, sizeMiB must be between 32 and 255
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE if an SD card was created and loaded; FALSE otherwise
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS info or uid is NULL, empty, or too long, format is invalid, or sizeMiB is out of range
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_SD_CARD_ALREADY_LOADED an SD card has already been loaded
|
||||
* @exception LPL2_ERR_SD_CARD_ALREADY_EXISTS an SD card with this uid or name already exists
|
||||
* @exception LPL2_ERR_SD_CARD_CREATE_ERROR an unknown error occurred when attempting to create the SD card image
|
||||
* @exception LPL2_ERR_SD_CARD_CORRUPTED the SD card was created, but then somehow could not be accessed
|
||||
*
|
||||
* @since LPL_ABI_VERSION_4
|
||||
*/
|
||||
lpl2_bool lpl2_create_sd_card( const char *uid, const char *name, lpl2_sd_format format, unsigned char sizeMiB, lpl2_err *err ) __attribute__((access(write_only, 5)));
|
||||
|
||||
/*! Creates a new SD card and loads it. This function can only be used to create an SD card when the user has not already selected
|
||||
* one in Parallel Launcher. If the user has already loaded an SD card, this function will do nothing and return FALSE.
|
||||
*
|
||||
* @param[in] format The format of the SD card
|
||||
* @param[in] sizeMiB The desired size of the SD card in MiB (2^20 bytes) \n
|
||||
* For FAT12, sizeMiB must be between 1 and 32 \n
|
||||
* For FAT16 and FAT32, sizeMiB must be between 32 and 255
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE if an SD card was created and loaded; FALSE otherwise
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS format is invalid or sizeMiB is out of range
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_SD_CARD_ALREADY_LOADED an SD card has already been loaded
|
||||
* @exception LPL2_ERR_SD_CARD_CREATE_ERROR an unknown error occurred when attempting to create the SD card image
|
||||
* @exception LPL2_ERR_SD_CARD_CORRUPTED the SD card was created, but then somehow could not be accessed
|
||||
*
|
||||
* @since LPL_ABI_VERSION_4
|
||||
*/
|
||||
lpl2_bool lpl2_create_auto_sd_card( lpl2_sd_format format, unsigned char sizeMiB, lpl2_err *err ) __attribute__((access(write_only, 3)));
|
||||
|
||||
/*! Loads an SD card that was created with @ref lpl2_create_sd_card. This function can only be used to load an SD card when the
|
||||
* the user has not already selected one in Parallel Launcher. If the user has already loaded an SD card, this function will do
|
||||
* nothing and return FALSE.
|
||||
*
|
||||
* @param[in] uid A unique string identifying the shared SD card (max 36 characters)
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE if an SD card was loaded; FALSE otherwise
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS uid is NULL, empty, or too long
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_SD_CARD_NOT_FOUND no SD card with the given uid was found
|
||||
* @exception LPL2_ERR_SD_CARD_ALREADY_LOADED an SD card has already been loaded
|
||||
* @exception LPL2_ERR_SD_CARD_CORRUPTED the SD card exists, but could not be read
|
||||
*
|
||||
* @note It would be wise to call @ref lpl2_get_sd_card_info first, to verify that the SD card has the expected size and format
|
||||
*
|
||||
* @since LPL_ABI_VERSION_4
|
||||
*/
|
||||
lpl2_bool lpl2_load_sd_card( const char *uid, lpl2_err *err ) __attribute__((access(write_only, 2)));
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
70
lib/libpl2/libpl2-rhdc.c
Normal file
70
lib/libpl2/libpl2-rhdc.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "libpl2-rhdc.h"
|
||||
|
||||
#include "libpl2-internal.h"
|
||||
|
||||
unsigned short lpl2_get_my_rhdc_username( char *username, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, 0 )
|
||||
LPL2_VERIFY_ABI( 3, err, 0 )
|
||||
LPL2_VERIFY_NOTNULL( username, err, 0 )
|
||||
|
||||
volatile const __lpl2_response *response = __lpl2_query_basic( 0x0200 );
|
||||
if( response->status == 0 && response->payloadSize <= 30 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
const unsigned short len = __lpl2_strcpy( username, response->payload, 30 );
|
||||
username[len] = '\0';
|
||||
return len;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 1: *err = LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lpl2_bool lpl2_get_rhdc_avatar_async( const char *username, lpl2_avatar_options options, void *avatar, lpl2_err *err ) {
|
||||
LPL2_VERIFY_INITIALIZED( err, FALSE )
|
||||
LPL2_VERIFY_ABI( 7, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( username, err, FALSE )
|
||||
LPL2_VERIFY_NOTNULL( avatar, err, FALSE )
|
||||
|
||||
if( ((unsigned int)avatar & 7) != 0 ) {
|
||||
if( err ) *err = LPL2_ERR_MISALIGNED_POINTER_ARG;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
avatar = __builtin_assume_aligned( avatar, 8 );
|
||||
|
||||
volatile char *requestPayload = __lpl2_payload_start();
|
||||
*((volatile unsigned int*)requestPayload) = (unsigned int)options;
|
||||
const unsigned short usernameLen = __lpl2_strcpy( &requestPayload[4], username, 31 );
|
||||
if( usernameLen == 0 || usernameLen > 30 ) {
|
||||
if( err ) *err = LPL2_ERR_INVALID_ARGUMENTS;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
volatile const __lpl2_response *response = __lpl2_payload_send( 0x0203, usernameLen + 4 );
|
||||
volatile const int *tempAvatar = (volatile const int*)__builtin_assume_aligned( (const void*)response->payload, 4 );
|
||||
if( response->status == 0 ) {
|
||||
if( err ) *err = LPL2_ERR_OKAY;
|
||||
for( unsigned short i = 0; i < (response->payloadSize >> 2); i++ ) {
|
||||
((unsigned int*)avatar)[i] = tempAvatar[i];
|
||||
}
|
||||
return TRUE;
|
||||
} else if( err ) {
|
||||
switch( response->status ) {
|
||||
case 0x500: *err = LPL2_ERR_WAIT; break;
|
||||
case 1: *err = LPL2_ERR_RHDC_AVATAR_NOT_FOUND; break;
|
||||
case 2: *err = LPL2_ERR_RHDC_NETWORK_ERROR; break;
|
||||
case 3: *err = LPL2_ERR_RHDC_AVATAR_INVALID; break;
|
||||
case 4: *err = LPL2_ERR_RHDC_RATE_LIMIT; break;
|
||||
case 0x200: case 0x201: case 0x600: *err = LPL2_ERR_INVALID_ARGUMENTS; break;
|
||||
case 0x300: case 0x400: *err = LPL2_ERR_BROKEN_PIPE; break;
|
||||
default: *err = LPL2_UNEXPECTED_ERROR( response->status ); break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
179
lib/libpl2/libpl2-rhdc.h
Normal file
179
lib/libpl2/libpl2-rhdc.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#ifndef LIBPL2_RHDC_
|
||||
#define LIBPL2_RHDC_
|
||||
|
||||
#include "libpl2-stddef.h"
|
||||
#include "libpl2-error.h"
|
||||
#include "libpl2-texture.h"
|
||||
|
||||
/*! @defgroup page_rhdc Romhacking.com Commands
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! Convenience struct for storing a 16x16 RHDC avatar in RGBA16 format. Alias of @ref lpl2_texture_16x16_rgba16 */
|
||||
typedef lpl2_texture_16x16_rgba16 lpl2_avatar_16x16_rgba16;
|
||||
|
||||
/*! Convenience struct for storing a 32x32 RHDC avatar in RGBA16 format. Alias of @ref lpl2_texture_32x32_rgba16 */
|
||||
typedef lpl2_texture_32x32_rgba16 lpl2_avatar_32x32_rgba16;
|
||||
|
||||
/*! Convenience struct for storing a 64x64 RHDC avatar in RGBA16 format. */
|
||||
typedef struct { lpl2_texture_64x32_rgba16 textures[2]; } lpl2_avatar_64x64_rgba16 __attribute__((aligned(8)));
|
||||
|
||||
/*! Convenience struct for storing a 16x16 RHDC avatar in RGBA32 format. Alias of @ref lpl2_texture_16x16_rgba32 */
|
||||
typedef lpl2_texture_16x16_rgba32 lpl2_avatar_16x16_rgba32;
|
||||
|
||||
/*! Convenience struct for storing a 32x32 RHDC avatar in RGBA32 format. Alias of @ref lpl2_texture_32x32_rgba32 */
|
||||
typedef lpl2_texture_32x32_rgba32 lpl2_avatar_32x32_rgba32;
|
||||
|
||||
/*! Convenience struct for storing a 64x64 RHDC avatar in RGBA32 format. */
|
||||
typedef struct { lpl2_texture_64x16_rgba32 textures[4]; } lpl2_avatar_64x64_rgba32 __attribute__((aligned(8)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! Image processing options for the avatar fetching calls */
|
||||
typedef enum {
|
||||
LPL2_AVATAR_16x16 = 0x10000000, /*!< Size Flag. Return a 16x16 image */
|
||||
LPL2_AVATAR_32x32 = 0x20000000, /*!< Size Flag. Return a 32x32 image */
|
||||
LPL2_AVATAR_64x64 = 0x40000000, /*!< Size Flag. Return a 64x64 image */
|
||||
|
||||
LPL2_AVATAR_RGBA16 = 0x100000, /*!< Format Flag. Return an image in RGBA16 (RGBA5551) format */
|
||||
LPL2_AVATAR_RGBA32 = 0x200000, /*!< Format Flag. Return an image in RGBA32 (RGBA8888) format */
|
||||
|
||||
/*! Optional Flag.
|
||||
* If this flag is provided, Floyd-Steinberg dithering will be used when converting the avatar to the RGBA16 format.
|
||||
* This flag has no effect if the LPL2_AVATAR_RGBA32 flag is also provided.
|
||||
*/
|
||||
LPL2_AVATAR_DITHER = 0x0001,
|
||||
|
||||
/*! Optional Flag.
|
||||
* If this flag is provided, the avatar will be resized to the requested size without using any filtering.
|
||||
* Otherwise, if this flag is not provided, the avatar will be scaled using bilinear filtering.
|
||||
*/
|
||||
LPL2_AVATAR_NO_FILTERING = 0x0002,
|
||||
|
||||
/*! Optional Flag.
|
||||
* If this flag is provided, any alpha transparency in the image will be removed and replaced with black.
|
||||
*/
|
||||
LPL2_AVATAR_NO_ALPHA = 0x0004,
|
||||
|
||||
/*! Optional Flag.
|
||||
* If this flag is provided, an avatar that is not square will be zoomed in and the sides cropped to fit in a square box.
|
||||
* Otherwise, if this flag is not provided, the avatar will be given a border of transparent (or black if the
|
||||
* LPL2_AVATAR_NO_ALPHA flag is provided) pixels on the sides.
|
||||
*/
|
||||
LPL2_AVATAR_ZOOM = 0x0008,
|
||||
} lpl2_avatar_options;
|
||||
|
||||
/*! Gets the username of the current RHDC user
|
||||
* @note RHDC usernames are at most 30 characters long as may contain alphanumeric ASCII characters, underscores, and hyphens
|
||||
*
|
||||
* @param[out] username A buffer at least 31 bytes large where the username will be stored
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return Returns the length of the username in bytes (not including the null terminator), or 0 on an error
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS username is NULL or not a valid RHDC username
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED the user has not enabled RHDC integration
|
||||
*
|
||||
* @since LPL_ABI_VERSION_3
|
||||
*/
|
||||
unsigned short lpl2_get_my_rhdc_username( char *username, lpl2_err *err ) __attribute__((access(write_only, 1), access(write_only, 2)));
|
||||
|
||||
/*! Asynchronously fetches the avatar for the given username in RHDC as a square image and stores it at the provided memory
|
||||
* address. If the operation failed or the user is not found, the provided memory buffer is not modified.
|
||||
*
|
||||
* @param[in] username A null-terminated string containing the username or userId
|
||||
* @param[in] options Flags for how the avatar should be processed. You must include a Size Flag and a Format Flag.
|
||||
* @param[out] avatar A buffer that the avatar will be written to. It is strongly recommended that you pass in a pointer to the
|
||||
* appropriate lpl2_avatar_* type, though you may also pass in an 8-byte-aligned pointer to an arbitrary buffer of the appropriate
|
||||
* size. The expected types and sizes are listed below:
|
||||
* - @ref lpl2_avatar_16x16_rgba16 (512 bytes) for LPL2_AVATAR_16x16 | LPL2_AVATAR_RGBA16
|
||||
* - @ref lpl2_avatar_16x16_rgba32 (1024 bytes) for LPL2_AVATAR_16x16 | LPL2_AVATAR_RGBA32
|
||||
* - @ref lpl2_avatar_32x32_rgba16 (2048 bytes) for LPL2_AVATAR_32x32 | LPL2_AVATAR_RGBA16
|
||||
* - @ref lpl2_avatar_32x32_rgba32 (4096 bytes) for LPL2_AVATAR_32x32 | LPL2_AVATAR_RGBA32
|
||||
* - @ref lpl2_avatar_64x64_rgba16 (8192 bytes) for LPL2_AVATAR_64x64 | LPL2_AVATAR_RGBA16 (contains 2 textures)
|
||||
* - @ref lpl2_avatar_64x64_rgba32 (16384 bytes) for LPL2_AVATAR_64x64 | LPL2_AVATAR_RGBA32 (contains 4 textures)
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL;
|
||||
* however, you likely want to at least check for an error code of LPL2_ERR_WAIT.
|
||||
* @return TRUE if the request has completed and the avatar has been copied. FALSE on an error or if the avatar has not been fully
|
||||
* downloaded yet.
|
||||
*
|
||||
* @exception LPL2_ERR_WAIT the web request to RHDC has not completed yet
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS username is NULL or not a valid RHDC username, avatar is NULL, or the options are invalid
|
||||
* @exception LPL2_ERR_MISALIGNED_POINTER_ARG avatar is not aligned to an 8-byte boundary
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED the user has not enabled RHDC integration
|
||||
* @exception LPL2_ERR_RHDC_NETWORK_ERROR could not connect to RHDC (can retry)
|
||||
* @exception LPL2_ERR_RHDC_RATE_LIMIT you are being rate limited (can retry later)
|
||||
* @exception LPL2_ERR_RHDC_AVATAR_NOT_FOUND the user does not exist or does not have an avatar
|
||||
* @exception LPL2_ERR_RHDC_AVATAR_INVALID an unexpected error occurred while processing the avatar image
|
||||
*
|
||||
* @note This is an asynchronous request. When called for the first time, or if the result of a prior request with the same
|
||||
* arguments is not yet ready, the function will return FALSE and @p err will be set to LPL2_ERR_WAIT. Once the asynchronous
|
||||
* request completes successfully, all future requests with the same arguments will return TRUE and copy the avatar. It is safe to
|
||||
* make multiple concurrent asynchronous requests-- you do NOT need to wait for it to complete before making another libpl2 call.
|
||||
*
|
||||
* @since LPL_ABI_VERSION_7
|
||||
*/
|
||||
lpl2_bool lpl2_get_rhdc_avatar_async( const char *username, lpl2_avatar_options options, void *avatar, lpl2_err *err ) __attribute__((access(write_only, 3), access(write_only, 4)));
|
||||
|
||||
/*! Fetches the avatar for the given username in RHDC as a square image and stores it at the provided memory address. If the
|
||||
* operation failed or the user is not found, the provided memory buffer is not modified. This operation blocks until the avatar
|
||||
* is fully downloaded or an error occurs.
|
||||
*
|
||||
* @param[in] username A null-terminated string containing the username or userId
|
||||
* @param[in] options Flags for how the avatar should be processed. You must include a Size Flag and a Format Flag.
|
||||
* @param[out] avatar A buffer that the avatar will be written to. It is strongly recommended that you pass in a pointer to the
|
||||
* appropriate lpl2_avatar_* type, though you may also pass in an 8-byte-aligned pointer to an arbitrary buffer of the appropriate
|
||||
* size. The expected types and sizes are listed below:
|
||||
* - @ref lpl2_avatar_16x16_rgba16 (512 bytes) for LPL2_AVATAR_16x16 | LPL2_AVATAR_RGBA16
|
||||
* - @ref lpl2_avatar_16x16_rgba32 (1024 bytes) for LPL2_AVATAR_16x16 | LPL2_AVATAR_RGBA32
|
||||
* - @ref lpl2_avatar_32x32_rgba16 (2048 bytes) for LPL2_AVATAR_32x32 | LPL2_AVATAR_RGBA16
|
||||
* - @ref lpl2_avatar_32x32_rgba32 (4096 bytes) for LPL2_AVATAR_32x32 | LPL2_AVATAR_RGBA32
|
||||
* - @ref lpl2_avatar_64x64_rgba16 (8192 bytes) for LPL2_AVATAR_64x64 | LPL2_AVATAR_RGBA16 (contains 2 textures)
|
||||
* - @ref lpl2_avatar_64x64_rgba32 (16384 bytes) for LPL2_AVATAR_64x64 | LPL2_AVATAR_RGBA32 (contains 4 textures)
|
||||
* @param[out] err On an error, this value (if non-NULL) is set to an error code (see listed "exceptions" below for possible error
|
||||
* codes). On success, the value is set to LPL2_ERR_OKAY. If you do not care about the specific error, you may pass in NULL.
|
||||
* @return TRUE if the user's avatar was successfully downloaded and copied. FALSE on an error or if the user has no avatar.
|
||||
*
|
||||
* @exception LPL2_ERR_INVALID_ARGUMENTS username is NULL or not a valid RHDC username, avatar is NULL, or the options are invalid
|
||||
* @exception LPL2_ERR_MISALIGNED_POINTER_ARG avatar is not aligned to an 8-byte boundary
|
||||
* @exception LPL2_ERR_LIBPL_NOT_INITIALIZED @ref lpl2_init has not been called
|
||||
* @exception LPL2_ERR_LIBPL_NOT_SUPPORTED the emulator does not support libpl
|
||||
* @exception LPL2_ERR_LIBPL_OLD_ABI @ref lpl2_init with an older ABI that does not support this function
|
||||
* @exception LPL2_ERR_BROKEN_PIPE the connection to Parallel Launcher has been lost
|
||||
* @exception LPL2_ERR_RHDC_INTEGRATION_NOT_ENABLED the user has not enabled RHDC integration
|
||||
* @exception LPL2_ERR_RHDC_NETWORK_ERROR could not connect to RHDC (can retry)
|
||||
* @exception LPL2_ERR_RHDC_RATE_LIMIT you are being rate limited (can retry later)
|
||||
* @exception LPL2_ERR_RHDC_AVATAR_NOT_FOUND the user does not exist or does not have an avatar
|
||||
* @exception LPL2_ERR_RHDC_AVATAR_INVALID an unexpected error occurred while processing the avatar image
|
||||
*
|
||||
* @attention This function will loop until the avatar is downloaded from RHDC, which may cause the emulator to stutter or freeze
|
||||
* during this time. For a better user expierence, use the @ref lpl2_get_rhdc_avatar_async function instead and handle the
|
||||
* LPL_ERR_WAIT error code.
|
||||
*
|
||||
* @since LPL_ABI_VERSION_7
|
||||
*/
|
||||
inline lpl2_bool __attribute__((warning("Use of blocking libpl call will likely cause the emulator to stutter. Use the async version of the libpl call for a better user experience."), access(write_only, 3), access(write_only, 4))) lpl2_get_rhdc_avatar_blocking( const char *username, lpl2_avatar_options options, void *avatar, lpl2_err *err ) {
|
||||
lpl2_err e = LPL2_ERR_WAIT;
|
||||
while( e == LPL2_ERR_WAIT ) lpl2_get_rhdc_avatar_async( username, options, avatar, &e );
|
||||
if( err ) *err = e;
|
||||
return e == LPL2_ERR_OKAY;
|
||||
}
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
46
lib/libpl2/libpl2-stddef.h
Normal file
46
lib/libpl2/libpl2-stddef.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef LIBPL2_STDDEF_
|
||||
#define LIBPL2_STDDEF_
|
||||
|
||||
#if __GNUC__ >= 14
|
||||
typedef int __attribute__((hardbool)) lpl2_bool;
|
||||
#else
|
||||
typedef int lpl2_bool;
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus >= 199711L
|
||||
#define NULL nullptr
|
||||
#else
|
||||
#define NULL 0
|
||||
#endif
|
||||
#else
|
||||
#if __STDC_VERSION__ >= 202311L
|
||||
#define NULL nullptr
|
||||
#else
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define lpl2_static_assert( expr ) static_assert( expr )
|
||||
#else
|
||||
#if __STDC_VERSION__ >= 202311L
|
||||
#define lpl2_static_assert( expr ) static_assert( expr )
|
||||
#elif __STDC_VERSION__ >= 201112L
|
||||
#define lpl2_static_assert( expr ) _Static_assert( expr )
|
||||
#else
|
||||
#define lpl2_static_assert( expr )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
84
lib/libpl2/libpl2-texture.h
Normal file
84
lib/libpl2/libpl2-texture.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef LIBPL2_TEXTURE_
|
||||
#define LIBPL2_TEXTURE_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "libpl2-stddef.h"
|
||||
|
||||
/*! @defgroup page_texture Texture Structs
|
||||
*
|
||||
* The structs on this page are provided for convenience and can be used for buffers that store textures.
|
||||
* They can be used for things outside of libpl2.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! An optional convenience struct for storing a single RGBA16 texel */
|
||||
typedef struct {
|
||||
unsigned short r: 5; /*!< The red component of the colour */
|
||||
unsigned short g: 5; /*!< The green component of the colour */
|
||||
unsigned short b: 5; /*!< The blue component of the colour */
|
||||
unsigned short a: 1; /*!< The alpha bit of the colour */
|
||||
} lpl2_texel_rgba16;
|
||||
lpl2_static_assert( sizeof( lpl2_texel_rgba16 ) == 2 );
|
||||
|
||||
/*! A convenience struct for storing a single RGBA32 texel */
|
||||
typedef struct {
|
||||
unsigned char r; /*!< The red component of the colour */
|
||||
unsigned char g; /*!< The green component of the colour */
|
||||
unsigned char b; /*!< The blue component of the colour */
|
||||
unsigned char a; /*!< The alpha component of the colour */
|
||||
} lpl2_texel_rgba32 __attribute__((aligned(4)));
|
||||
lpl2_static_assert( sizeof( lpl2_texel_rgba32 ) == 4 );
|
||||
|
||||
/*! A convenience struct for storing a 16x16 RGBA16 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba16 texels[256];
|
||||
lpl2_texel_rgba16 yx[16][16];
|
||||
} lpl2_texture_16x16_rgba16 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_16x16_rgba16 ) == 512 );
|
||||
|
||||
/*! A convenience struct for storing a 32x32 RGBA16 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba16 texels[1024];
|
||||
lpl2_texel_rgba16 yx[32][32];
|
||||
} lpl2_texture_32x32_rgba16 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_32x32_rgba16 ) == 2048 );
|
||||
|
||||
/*! A convenience struct for storing a 64x32 RGBA16 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba16 texels[2048];
|
||||
lpl2_texel_rgba16 yx[32][64];
|
||||
} lpl2_texture_64x32_rgba16 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_64x32_rgba16 ) == 4096 );
|
||||
|
||||
/*! A convenience struct for storing a 16x16 RGBA32 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba32 texels[256];
|
||||
lpl2_texel_rgba32 yx[16][16];
|
||||
} lpl2_texture_16x16_rgba32 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_16x16_rgba32 ) == 1024 );
|
||||
|
||||
/*! A convenience struct for storing a 32x32 RGBA32 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba32 texels[1024];
|
||||
lpl2_texel_rgba32 yx[32][32];
|
||||
} lpl2_texture_32x32_rgba32 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_32x32_rgba32 ) == 4096 );
|
||||
|
||||
/*! A convenience struct for storing a 64x16 RGBA32 texture. */
|
||||
typedef union {
|
||||
lpl2_texel_rgba32 texels[1024];
|
||||
lpl2_texel_rgba32 yx[16][64];
|
||||
} lpl2_texture_64x16_rgba32 __attribute__((aligned(8)));
|
||||
lpl2_static_assert( sizeof( lpl2_texture_64x16_rgba32 ) == 4096 );
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user