Sorry, it's in Rust again. <<TODO KAITAI OR IMHEX>><syntaxhighlight lang="rust">
Sorry, it's in Rust again. <<TODO KAITAI OR IMHEX>><syntaxhighlight lang="c">
#[bitsize(4)]
typedef struct RFLiCharData {
#[repr(u8)]
// at 0x0
#[derive(FromBits, Debug, PartialEq)]
u16 padding0 : 1;
pub enum FavoriteColor {
u16 sex : 1;
Red = 0,
u16 birthMonth : 4;
Orange = 1,
u16 birthDay : 5;
Yellow = 2,
u16 favoriteColor : 4;
YellowGreen = 3,
u16 favorite : 1;
Green = 4,
Blue = 5,
SkyBlue = 6,
Pink = 7,
Purple = 8,
Brown = 9,
White = 10,
Black = 11,
#[fallback]
Invalid(u4),
}
impl FavoriteColor {
wchar_t name[RFL_NAME_LEN]; // at 0x2
fn as_u8(&self) -> u8 {
u8 height; // at 0x16
match self {
u8 build; // at 0x17
FavoriteColor::Red => 0,
RFLCreateID createID; // at 0x18
FavoriteColor::Orange => 1,
FavoriteColor::Yellow => 2,
FavoriteColor::YellowGreen => 3,
FavoriteColor::Green => 4,
FavoriteColor::Blue => 5,
FavoriteColor::SkyBlue => 6,
FavoriteColor::Pink => 7,
FavoriteColor::Purple => 8,
FavoriteColor::Brown => 9,
FavoriteColor::White => 10,
FavoriteColor::Black => 11,
FavoriteColor::Invalid(n) => n.as_u8(),
}
}
}
#[bitsize(1)]
// at 0x20
#[derive(FromBits, Debug, PartialEq)]
u16 faceType : 3;
pub enum Gender {
u16 faceColor : 3;
Male,
u16 faceTex : 4;
Female,
u16 padding2 : 3;
}
u16 localonly : 1;
u16 type : 2;
#[bitfield(16)]
// at 0x22
pub struct PersonalInfoField {
u16 hairType : 7;
pub padding: u1,
u16 hairColor : 3;
/// Originally named sex
u16 hairFlip : 1;
pub gender: Gender,
u16 padding3 : 5;
pub birth_month: u4,
/// 0 = unset, Counts from 1-31
// at 0x24
/// Birth month and day must be set together if set.
u16 eyebrowType : 5;
pub birth_day: u5,
u16 eyebrowRotate : 5;
pub favorite_color: FavoriteColor,
u16 padding4 : 6;
pub favorite: bool,
}
#[bitfield(16)]
// at 0x26
pub struct FaceField {
u16 eyebrowColor : 3;
pub face_type: u3,
u16 eyebrowScale : 4;
pub face_color: u3,
u16 eyebrowY : 5;
pub face_tex: u4,
u16 eyebrowX : 4;
pub padding2: u3,
pub localonly: u1,
/// Set to 1 if downloaded from "Check Mii Out Channel".
// at 0x28
pub type_: u2,
u16 eyeType : 6;
}
u16 eyeRotate : 5;
u16 eyeY : 5;
#[bitfield(16)]
// at 0x2A
pub struct HairField {
u16 eyeColor : 3;
pub hair_type: u7,
u16 eyeScale : 4;
pub hair_color: u3,
u16 eyeX : 4;
pub hair_flip: u1,
u16 padding5 : 5;
pub padding3: u5,
}
#[bitfield(32)]
// at 0x2C
pub struct EyebrowField {
u16 noseType : 4;
pub eyebrow_type: u5,
u16 noseScale : 4;
pub eyebrow_rotate: u5,
u16 noseY : 5;
pub padding4: u6,
u16 padding6 : 3;
pub eyebrow_color: u3,
pub eyebrow_scale: u4,
pub eyebrow_y: u5,
pub eyebrow_x: u4,
}
#[bitfield(32)]
// at 0x2E
pub struct EyeField {
u16 mouthType : 5;
pub eye_type: u6,
u16 mouthColor : 2;
pub eye_rotate: u5,
u16 mouthScale : 4;
pub eye_y: u5,
u16 mouthY : 5;
pub eye_color: u3,
pub eye_scale: u4,
pub eye_x: u4,
pub padding5: u5,
}
#[bitfield(16)]
// at 0x30
pub struct NoseField {
u16 glassType : 4;
pub nose_type: u4,
u16 glassColor : 3;
pub nose_scale: u4,
u16 glassScale : 4;
pub nose_y: u5,
u16 glassY : 5;
pub padding6: u3,
}
#[bitfield(16)]
// at 0x32
pub struct MouthField {
u16 mustacheType : 2;
pub mouth_type: u5,
u16 beardType : 2;
pub mouth_color: u2,
u16 beardColor : 3;
pub mouth_scale: u4,
u16 beardScale : 4;
pub mouth_y: u5,
u16 beardY : 5;
}
#[bitfield(16)]
// at 0x34
pub struct GlassField {
u16 moleType : 1;
pub glass_type: u4,
u16 moleScale : 4;
pub glass_color: u3,
u16 moleY : 5;
pub glass_scale: u4,
u16 moleX : 5;
pub glass_y: u5,
u16 padding8 : 1;
}
#[bitfield(16)]
wchar_t creatorName[RFL_CREATOR_LEN]; // at 0x36
pub struct FaceHairField {
} RFLiCharData;
pub mustache_type: u2,
pub beard_type: u2,
pub beard_color: u3,
pub beard_scale: u4,
pub beard_y: u5,
}
#[bitfield(16)]
pub struct MoleField {
pub mole_type: u1,
pub mole_scale: u4,
pub mole_y: u5,
pub mole_x: u5,
pub padding8: u1,
}
/// `flags` contain information about where the Char was created,
/// and some other miscellaneous state. See [RvlCreateIdFlags::platform].
///
/// `create_date_offset` contains an offset timestamp of creation date.
/// See [Self::create_date_timestamp]'s implementation for more information.
///
/// `addr_low` is built from the Mac address of the Rvl/Ntr console.
/// It contains a checksum of the first three bytes, and the last three bytes.
///
/// ```rust
/// fn build_addr_low(mac: &[u8; 6]) -> [u8; 4] {
/// let checksum = mac.iter().take(3).fold(0u8, |sum, &b| sum.wrapping_add(b)) & 0x7F;
/// [checksum, mac[3], mac[4], mac[5]]
/// }
/// ```
///
/// It is unknown how the checksum byte is calculated on Ntr targets.
///
/// In order for the Char to be considered as created from the
/// same console on Rvl (RFLiIsMyHomeID), the CreateId has to
/// be non-null, not from Ntr, and the `addr_low` has to match.
///
#[bitfield(64)]
pub struct CreateId {
pub flags: CreateIdFlags,
pub create_date_offset: u28,
pub addr_low: [u8; 4],
}
impl CreateId {
/// Outputs the creation date timestamp from the offset encoded.
/// It is not known if this implementation is accurate.
pub fn create_date_timestamp(&self) -> u32 {
const JAN_1_2006: u32 = 1136073600;
let offset = self.create_date_offset().as_u32();
(offset * 4) + JAN_1_2006
}
}
/// `Etc` can be either targets: Cafe, Nx, Miitomo
#[bitsize(2)]
#[derive(FromBits, Debug, PartialEq)]
pub enum CreateIdPlatform {
Rvl = 0b00,
Ctr = 0b01,
Ntr = 0b10,
Etc = 0b11,
}
/// These flags can be used to derive the creation platform,
/// see [Self::platform].
///
#[bitfield(4)]
pub struct CreateIdFlags {
/// Cleared = Special, Set = Normal
pub normal: bool,
/// Cleared on Wii and 3DS, set on DS and Wii U.
pub field_1: bool,
/// Given to random Miis and seen in some games' CPU Miis.
pub temporary: bool,
/// Cleared on Wii and DS, set on 3DS and Wii U.
pub field_3: bool,
}
impl CreateIdFlags {
/// Outputs the creation platform for the Char.
/// Uses `field_1` and `field_3`.
pub fn platform(&self) -> CreateIdPlatform {
let bits = u2::from_u8(match (self.field_1(), self.field_3()) {
(false, false) => 0b00_u8,
(true, false) => 0b10,
(false, true) => 0b01,
(true, true) => 0b11,
});
CreateIdPlatform::from(bits)
}
}
/// A packed character info format.
/// This structure has a lot of bitfields.
/// These fields have been given speculative names.
///
/// This format is commonly known as `.{r,n}cd`.
/// Rvl and Ntr only differ by endian-ness.
#[derive(Debug)]
#[brw(big)]
pub struct RvlCharData {
pub personal_info: PersonalInfoField,
pub name: FixedLengthWideString<10>,
pub height: u8,
pub build: u8,
pub create_id: CreateId,
pub face: FaceField,
pub hair: HairField,
pub eyebrow: EyebrowField,
pub eye: EyeField,
pub nose: NoseField,
pub mouth: MouthField,
pub glass: GlassField,
pub face_hair: FaceHairField,
pub mole: MoleField,
pub creator_name: FixedLengthWideString<10>,
}
</syntaxhighlight>{{Format-Navbox}}
</syntaxhighlight>{{Format-Navbox}}
Revision as of 11:33, 24 September 2025
RFLCharData is the Mii data format used on Wii. This format has big endianness, and it's little endian counterpart is used on DS.
Data format
Sorry, it's in Rust again. <<TODO KAITAI OR IMHEX>>
typedefstructRFLiCharData{// at 0x0u16padding0:1;u16sex:1;u16birthMonth:4;u16birthDay:5;u16favoriteColor:4;u16favorite:1;wchar_tname[RFL_NAME_LEN];// at 0x2u8height;// at 0x16u8build;// at 0x17RFLCreateIDcreateID;// at 0x18// at 0x20u16faceType:3;u16faceColor:3;u16faceTex:4;u16padding2:3;u16localonly:1;u16type:2;// at 0x22u16hairType:7;u16hairColor:3;u16hairFlip:1;u16padding3:5;// at 0x24u16eyebrowType:5;u16eyebrowRotate:5;u16padding4:6;// at 0x26u16eyebrowColor:3;u16eyebrowScale:4;u16eyebrowY:5;u16eyebrowX:4;// at 0x28u16eyeType:6;u16eyeRotate:5;u16eyeY:5;// at 0x2Au16eyeColor:3;u16eyeScale:4;u16eyeX:4;u16padding5:5;// at 0x2Cu16noseType:4;u16noseScale:4;u16noseY:5;u16padding6:3;// at 0x2Eu16mouthType:5;u16mouthColor:2;u16mouthScale:4;u16mouthY:5;// at 0x30u16glassType:4;u16glassColor:3;u16glassScale:4;u16glassY:5;// at 0x32u16mustacheType:2;u16beardType:2;u16beardColor:3;u16beardScale:4;u16beardY:5;// at 0x34u16moleType:1;u16moleScale:4;u16moleY:5;u16moleX:5;u16padding8:1;wchar_tcreatorName[RFL_CREATOR_LEN];// at 0x36}RFLiCharData;