Add miiSelector configuration functions (#429)

This commit is contained in:
Oreo639 2019-05-03 16:40:00 -07:00 committed by fincs
parent c550a22259
commit d3ea737071
3 changed files with 308 additions and 57 deletions

View File

@ -22,25 +22,25 @@
/// Parameter structure passed to AppletEd
typedef struct
{
char enable_cancel_button; ///< Enables canceling of selection if nonzero.
char enable_selecting_guests; ///< Makes Guets Miis selectable if nonzero.
char show_on_top_screen; ///< Shows applet on top screen if nonzero,
u8 enable_cancel_button; ///< Enables canceling of selection if nonzero.
u8 enable_selecting_guests; ///< Makes Guets Miis selectable if nonzero.
u8 show_on_top_screen; ///< Shows applet on top screen if nonzero,
///< otherwise show it on the bottom screen.
char _unk0x3[5]; ///< @private
u8 _unk0x3[5]; ///< @private
u16 title[MIISELECTOR_TITLE_LEN]; ///< UTF16-LE string displayed at the top of the applet. If
///< set to the empty string, a default title is displayed.
char _unk0x88[4]; ///< @private
char show_guest_page; ///< If nonzero, the applet shows a page with Guest
u8 _unk0x88[4]; ///< @private
u8 show_guest_page; ///< If nonzero, the applet shows a page with Guest
///< Miis on launch.
char _unk0x8D[3]; ///< @private
u8 _unk0x8D[3]; ///< @private
u32 initial_index; ///< Index of the initially selected Mii. If
///< @ref MiiSelectorConf.show_guest_page is
///< set, this is the index of a Guest Mii,
///< otherwise that of a user Mii.
char mii_guest_whitelist[MIISELECTOR_GUESTMII_SLOTS]; ///< Each byte set to a nonzero value
u8 mii_guest_whitelist[MIISELECTOR_GUESTMII_SLOTS]; ///< Each byte set to a nonzero value
///< enables its corresponding Guest
///< Mii to be enabled for selection.
char mii_whitelist[MIISELECTOR_USERMII_SLOTS]; ///< Each byte set to a nonzero value enables
u8 mii_whitelist[MIISELECTOR_USERMII_SLOTS]; ///< Each byte set to a nonzero value enables
///< its corresponding user Mii to be enabled
///< for selection.
u16 _unk0xFE; ///< @private
@ -48,9 +48,6 @@ typedef struct
///< applet.
} MiiSelectorConf;
/// Size of the data describing a single Mii
#define MIISELECTOR_MIIDATA_SIZE 0x5c
/// Maximum length of the localized name of a Guest Mii
#define MIISELECTOR_GUESTMII_NAME_LEN 12
@ -73,6 +70,21 @@ typedef struct
///< string). Zeroed otherwise.
} MiiSelectorReturn;
/// AppletEd options
enum
{
MIISELECTOR_CANCEL = BIT(0), ///< Show the cancel button
MIISELECTOR_GUESTS = BIT(1), ///< Make Guets Miis selectable
MIISELECTOR_TOP = BIT(2), ///< Show AppletEd on top screen
MIISELECTOR_GUESTSTART = BIT(3), ///< Start on guest page
};
/**
* @brief Initialize Mii selector config
* @param conf Pointer to Miiselector config.
*/
void miiSelectorInit(MiiSelectorConf *conf);
/**
* @brief Launch the Mii selector library applet
*
@ -81,12 +93,97 @@ typedef struct
*/
Result miiSelectorLaunch(const MiiSelectorConf *conf, MiiSelectorReturn* returnbuf);
/**
* @brief Sets title of the Mii selector library applet
*
* @param conf Pointer to miiSelector configuration
* @param text Title text of Mii selector
*/
void miiSelectorSetTitle(MiiSelectorConf *conf, const char* text);
/**
* @brief Specifies which special options are enabled in the Mii selector
*
* @param conf Pointer to miiSelector configuration
* @param options Options bitmask
*/
void miiSelectorSetOptions(MiiSelectorConf *conf, u32 options);
/**
* @brief Specifies which guest Miis will be selectable
*
* @param conf Pointer to miiSelector configuration
* @param index Index of the guest Miis that will be whitelisted.
* @ref MIISELECTOR_GUESTMII_SLOTS can be used to whitelist all the guest Miis.
*/
void miiSelectorWhitelistGuestMii(MiiSelectorConf *conf, u32 index);
/**
* @brief Specifies which guest Miis will be unselectable
*
* @param conf Pointer to miiSelector configuration
* @param index Index of the guest Miis that will be blacklisted.
* @ref MIISELECTOR_GUESTMII_SLOTS can be used to blacklist all the guest Miis.
*/
void miiSelectorBlacklistGuestMii(MiiSelectorConf *conf, u32 index);
/**
* @brief Specifies which user Miis will be selectable
*
* @param conf Pointer to miiSelector configuration
* @param index Index of the user Miis that will be whitelisted.
* @ref MIISELECTOR_USERMII_SLOTS can be used to whitlist all the user Miis
*/
void miiSelectorWhitelistUserMii(MiiSelectorConf *conf, u32 index);
/**
* @brief Specifies which user Miis will be selectable
*
* @param conf Pointer to miiSelector configuration
* @param index Index of the user Miis that will be blacklisted.
* @ref MIISELECTOR_USERMII_SLOTS can be used to blacklist all the user Miis
*/
void miiSelectorBlacklistUserMii(MiiSelectorConf *conf, u32 index);
/**
* @brief Specifies which Mii the cursor should start from
*
* @param conf Pointer to miiSelector configuration
* @param index Indexed number of the Mii that the cursor will start on.
* If there is no mii with that index, the the cursor will start at the Mii
* with the index 0 (the personal Mii).
*/
static inline void miiSelectorSetInitialIndex(MiiSelectorConf *conf, u32 index)
{
conf->initial_index = index;
}
/**
* @brief Get Mii name
*
* @param returnbuf Pointer to miiSelector return
* @param out String containing a Mii's name
* @param max_size Size of string. Since UTF8 characters range in size from 1-3 bytes
* (assuming that no non-BMP characters are used), this value should be 36 (or 30 if you are not
* dealing with guest miis).
*/
void miiSelectorReturnGetName(const MiiSelectorReturn *returnbuf, char* out, size_t max_size);
/**
* @brief Get Mii Author
*
* @param returnbuf Pointer to miiSelector return
* @param out String containing a Mii's author
* @param max_size Size of string. Since UTF8 characters range in size from 1-3 bytes
* (assuming that no non-BMP characters are used), this value should be 30.
*/
void miiSelectorReturnGetAuthor(const MiiSelectorReturn *returnbuf, char* out, size_t max_size);
/**
* @brief Verifies that the Mii data returned from the applet matches its
* checksum
*
* @param returnbuffer Buffer filled by Mii selector applet
*
* @param returnbuf Buffer filled by Mii selector applet
* @return `true` if `returnbuf->checksum` is the same as the one computed from `returnbuf`
*/
bool miiSelectorChecksumIsValid(const MiiSelectorReturn *returnbuf);

View File

@ -1,56 +1,84 @@
/**
* @file mii.h
* @brief Shared Mii struct.
*
* @see https://www.3dbrew.org/wiki/Mii#Mii_format
*/
#pragma once
#include <3ds/types.h>
/// Shared Mii struct
typedef struct
{
u8 magic;
u8 magic; ///< Always 3?
/// Mii options
struct
{
bool allow_copying : 1;
bool is_private_name : 1;
u8 region_lock : 2;
u8 char_set : 2;
bool allow_copying : 1; ///< True if copying is allowed
bool is_private_name : 1; ///< Private name?
u8 region_lock : 2; ///< Region lock (0=no lock, 1=JPN, 2=USA, 3=EUR)
u8 char_set : 2; ///< Character set (0=JPN+USA+EUR, 1=CHN, 2=KOR, 3=TWN)
} mii_options;
/// Mii position in Mii selector or Mii maker
struct
{
u8 page_index : 4;
u8 slot_index : 4;
u8 page_index : 4; ///< Page index of Mii
u8 slot_index : 4; ///< Slot offset of Mii on its Page
} mii_pos;
u8 console_identity;
u64 system_id;
u32 mii_id;
u8 mac[6];
u8 pad[2];
u16 mii_details;
u16 mii_name[10];
u8 height;
u8 width;
/// Console Identity
struct
{
bool disable_sharing : 1;
u8 shape : 4;
u8 skinColor : 3;
u8 unknown0 : 4; ///< Mabye padding (always seems to be 0)?
u8 origin_console : 3; ///< Console that the Mii was created on (1=WII, 2=DSI, 3=3DS)
} console_identity;
u64 system_id; ///< Identifies the system that the Mii was created on (Determines pants)
u32 mii_id; ///< ID of Mii
u8 mac[6]; ///< Creator's system's full MAC address
u8 pad[2]; ///< Padding
/// Mii details
struct {
bool sex : 1; ///< Sex of Mii (False=Male, True=Female)
u16 bday_month : 4; ///< Month of Mii's birthday
u16 bday_day : 5; ///< Day of Mii's birthday
u16 shirt_color : 4; ///< Color of Mii's shirt
bool favorite : 1; ///< Whether the Mii is one of your 10 favorite Mii's
} mii_details;
u16 mii_name[10]; ///< Name of Mii (Encoded using UTF16)
u8 height; ///< How tall the Mii is
u8 width; ///< How wide the Mii is
/// Face style
struct
{
bool disable_sharing : 1; ///< Whether or not Sharing of the Mii is allowed
u8 shape : 4; ///< Face shape
u8 skinColor : 3; ///< Color of skin
} face_style;
/// Face details
struct
{
u8 wrinkles : 4;
u8 makeup : 4;
} face_details;
u8 hair_style;
/// Hair details
struct
{
u8 color : 3;
bool flip : 1;
} hair_details;
/// Eye details
struct
{
u32 style : 6;
@ -61,18 +89,21 @@ typedef struct
u32 xspacing : 4;
u32 yposition : 5;
} eye_details;
/// Eyebrow details
struct
{
u32 style : 6;
u32 style : 5;
u32 color : 3;
u32 scale : 4;
u32 yscale : 3;
u32 pad : 1;
u32 rotation : 5;
u32 xspacing : 4;
u32 yposition : 5;
} eyebrow_details;
/// Nose details
struct
{
u16 style : 5;
@ -80,21 +111,24 @@ typedef struct
u16 yposition : 5;
} nose_details;
/// Mouth details
struct
{
u16 style : 6;
u16 color : 3;
u16 scale : 4;
u16 yscale : 3;
} mouse_details;
} mouth_details;
/// Mustache details
struct
{
u16 mouse_yposition : 5;
u16 mouth_yposition : 5;
u16 mustach_style : 3;
u16 pad : 2;
} mustache_details;
/// Beard details
struct
{
u16 style : 3;
@ -103,6 +137,7 @@ typedef struct
u16 ypos : 5;
} beard_details;
/// Glasses details
struct
{
u16 style : 4;
@ -111,6 +146,7 @@ typedef struct
u16 ypos : 5;
} glasses_details;
/// Mole details
struct
{
bool enable : 1;
@ -119,5 +155,5 @@ typedef struct
u16 ypos : 5;
} mole_details;
u16 author_name[10];
u16 author_name[10]; ///< Name of Mii's author (Encoded using UTF16)
} PACKED MiiData;

View File

@ -1,11 +1,23 @@
#include <3ds/types.h>
#include <3ds/result.h>
#include <3ds/services/apt.h>
#include <3ds/util/utf.h>
#include <3ds/applets/miiselector.h>
#include <string.h> // for memcpy
void miiSelectorInit(MiiSelectorConf *conf)
{
memset(conf, 0, sizeof(*conf));
for (int i = 0; i < MIISELECTOR_GUESTMII_SLOTS; i ++)
conf->mii_guest_whitelist[i] = 1;
for (int i = 0; i < MIISELECTOR_USERMII_SLOTS; i ++)
conf->mii_whitelist[i] = 1;
}
Result miiSelectorLaunch(const MiiSelectorConf *conf, MiiSelectorReturn *returnbuf)
{
union {
@ -17,33 +29,139 @@ Result miiSelectorLaunch(const MiiSelectorConf *conf, MiiSelectorReturn *returnb
ctx.config.magic = MIISELECTOR_MAGIC;
Result ret = aptLaunchLibraryApplet(APPID_APPLETED, &ctx.config, sizeof(MiiSelectorConf), 0);
if(R_SUCCEEDED(ret) && returnbuf) {
if(R_SUCCEEDED(ret) && returnbuf)
memcpy(returnbuf, &ctx.ret, sizeof(MiiSelectorReturn));
}
return ret;
}
static void miiSelectorConvertToUTF8(char* out, const u16* in, int max)
{
if (!in || !*in)
{
out[0] = 0;
return;
}
ssize_t units = utf16_to_utf8((uint8_t*)out, in, max);
if (units < 0)
{
out[0] = 0;
return;
}
out[units] = 0;
}
static void miiSelectorConvertToUTF16(u16* out, const char* in, int max)
{
if (!in || !*in)
{
out[0] = 0;
return;
}
ssize_t units = utf8_to_utf16(out, (const uint8_t*)in, max);
if (units < 0)
{
out[0] = 0;
return;
}
out[units] = 0;
}
void miiSelectorSetTitle(MiiSelectorConf *conf, const char* text)
{
miiSelectorConvertToUTF16(conf->title, text, MIISELECTOR_TITLE_LEN);
}
void miiSelectorSetOptions(MiiSelectorConf *conf, u32 options)
{
static const u8 miiSelectorOptions[] =
{
offsetof(MiiSelectorConf, enable_cancel_button),
offsetof(MiiSelectorConf, enable_selecting_guests),
offsetof(MiiSelectorConf, show_on_top_screen),
offsetof(MiiSelectorConf, show_guest_page),
};
for (int i = 0; i < sizeof(miiSelectorOptions); i ++)
*((u8*)conf + miiSelectorOptions[i]) = (options & BIT(i)) ? 1 : 0;
}
void miiSelectorWhitelistGuestMii(MiiSelectorConf *conf, u32 index)
{
if (index < MIISELECTOR_GUESTMII_SLOTS)
conf->mii_guest_whitelist[index] = 1;
else if (index == MIISELECTOR_GUESTMII_SLOTS)
for (int i = 0; i < MIISELECTOR_GUESTMII_SLOTS; i ++)
conf->mii_guest_whitelist[i] = 1;
}
void miiSelectorBlacklistGuestMii(MiiSelectorConf *conf, u32 index)
{
if (index < MIISELECTOR_GUESTMII_SLOTS)
conf->mii_guest_whitelist[index] = 0;
else if (index == MIISELECTOR_GUESTMII_SLOTS)
for (int i = 0; i < MIISELECTOR_GUESTMII_SLOTS; i ++)
conf->mii_guest_whitelist[i] = 0;
}
void miiSelectorWhitelistUserMii(MiiSelectorConf *conf, u32 index)
{
if (index < MIISELECTOR_USERMII_SLOTS)
conf->mii_whitelist[index] = 1;
else if (index == MIISELECTOR_USERMII_SLOTS)
for (int i = 0; i < MIISELECTOR_USERMII_SLOTS; i ++)
conf->mii_whitelist[i] = 1;
}
void miiSelectorBlacklistUserMii(MiiSelectorConf *conf, u32 index)
{
if (index < MIISELECTOR_USERMII_SLOTS)
conf->mii_whitelist[index] = 0;
else if (index == MIISELECTOR_USERMII_SLOTS)
for (int i = 0; i < MIISELECTOR_USERMII_SLOTS; i ++)
conf->mii_whitelist[i] = 0;
}
void miiSelectorReturnGetName(const MiiSelectorReturn *returnbuf, char* out, size_t max_size)
{
if (!out)
return;
if (returnbuf->guest_mii_was_selected)
miiSelectorConvertToUTF8(out, returnbuf->guest_mii_name, max_size);
else
miiSelectorConvertToUTF8(out, returnbuf->mii.mii_name, max_size);
}
void miiSelectorReturnGetAuthor(const MiiSelectorReturn *returnbuf, char* out, size_t max_size)
{
if (!out)
return;
miiSelectorConvertToUTF8(out, returnbuf->mii.author_name, max_size);
}
static u16 crc16_ccitt(void const *buf, size_t len, uint32_t starting_val)
{
if(buf == NULL) {
if (!buf)
return -1;
}
u8 const *cbuf = buf;
u32 crc = starting_val;
static const u16 POLY = 0x1021;
for(size_t i = 0; i < len; i++) {
for(int bit = 7; bit >= 0; bit--) {
for (size_t i = 0; i < len; i++)
{
for (int bit = 7; bit >= 0; bit--)
crc = ((crc << 1) | ((cbuf[i] >> bit) & 0x1)) ^ (crc & 0x8000 ? POLY : 0);
}
}
for(int _ = 0; _ < 16; _++) {
for (int _ = 0; _ < 16; _++)
crc = (crc << 1) ^ (crc & 0x8000 ? POLY : 0);
}
return (u16)(crc & 0xffff);
}