ctru/
mii.rs

1//! Mii data.
2//!
3//! This module contains the structs that represent all the data of a Mii.
4//!
5//! Have a look at the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) applet to learn how to ask the user for a specific Mii.
6
7/// Region lock of the Mii.
8#[derive(Copy, Clone, Debug, Eq, PartialEq)]
9pub enum RegionLock {
10    /// No region-lock.
11    None,
12    /// Japan region-lock.
13    Japan,
14    /// USA region-lock.
15    USA,
16    /// Europe region-lock.
17    Europe,
18}
19
20/// Charset of the Mii.
21#[derive(Copy, Clone, Debug, Eq, PartialEq)]
22pub enum Charset {
23    /// Japan-USA-Europe unified charset.
24    JapanUSAEurope,
25    /// China charset.
26    China,
27    /// Korea charset.
28    Korea,
29    /// Taiwan charset.
30    Taiwan,
31}
32
33/// Generic options of the Mii.
34#[derive(Copy, Clone, Debug)]
35pub struct Options {
36    /// Whether it is allowed to copy the Mii.
37    pub is_copying_allowed: bool,
38    /// Whether the profanity flag is active.
39    pub is_profanity_flag_enabled: bool,
40    /// The Mii's active region-lock.
41    pub region_lock: RegionLock,
42    /// The Mii's used charset.
43    pub charset: Charset,
44}
45
46/// Positional Index that the Mii has on the [`MiiSelector`](crate::applets::mii_selector::MiiSelector) window.
47#[derive(Copy, Clone, Debug)]
48pub struct SelectorPosition {
49    /// Index of the page where the Mii is found.
50    pub page_index: u8,
51    /// Index of the slot (relative to the page) where the Mii is found.
52    pub slot_index: u8,
53}
54
55/// Console model from which the Mii originated.
56#[derive(Copy, Clone, Debug, Eq, PartialEq)]
57pub enum OriginConsole {
58    /// Nintendo Wii.
59    Wii,
60    /// Nintendo DSi.
61    DSi,
62    /// Nintendo 3DS.
63    ///
64    /// This includes all consoles of the 3DS family (3DS, 2DS, and their respective "New" or "XL" variants).
65    N3DS,
66    /// Nintendo Wii U/Switch.
67    WiiUSwitch,
68}
69
70/// Identity of the origin console.
71#[derive(Copy, Clone, Debug)]
72pub struct ConsoleIdentity {
73    /// From which console the Mii originated from.
74    pub origin_console: OriginConsole,
75}
76
77/// Sex of the Mii.
78#[derive(Copy, Clone, Debug, Eq, PartialEq)]
79pub enum Sex {
80    /// Male sex.
81    Male,
82    /// Female sex.
83    Female,
84}
85
86/// Generic details of the Mii.
87#[derive(Copy, Clone, Debug)]
88pub struct Details {
89    /// Sex of the Mii.
90    pub sex: Sex,
91    /// Birthday month.
92    pub birthday_month: u8,
93    /// Birthday day.
94    pub birthday_day: u8,
95    /// Color of the Mii's shirt.
96    pub shirt_color: u8,
97    /// Whether the Mii is a favorite.
98    pub is_favorite: bool,
99    /// Whether the Mii can be shared.
100    pub is_sharing_enabled: bool,
101}
102
103/// Face style of the Mii.
104#[derive(Copy, Clone, Debug)]
105pub struct FaceStyle {
106    /// Face shape.
107    pub shape: u8,
108    /// Skin color.
109    pub skin_color: u8,
110}
111
112/// Face details of the Mii.
113#[derive(Copy, Clone, Debug)]
114pub struct FaceDetails {
115    /// Face style.
116    pub style: FaceStyle,
117    /// Wrinkles.
118    pub wrinkles: u8,
119    /// Makeup.
120    pub makeup: u8,
121}
122
123/// Hair details of the Mii.
124#[derive(Copy, Clone, Debug)]
125pub struct HairDetails {
126    /// Hair style.
127    pub style: u8,
128    /// Hair color.
129    pub color: u8,
130    /// Whether the Mii's hair is flipped.
131    pub is_flipped: bool,
132}
133
134/// Eye details of the Mii.
135#[derive(Copy, Clone, Debug)]
136pub struct EyeDetails {
137    /// Eye style.
138    pub style: u8,
139    /// Eye color.
140    pub color: u8,
141    /// Eye scale.
142    pub scale: u8,
143    /// Eye scale (y-axis).
144    pub y_scale: u8,
145    /// Eye rotation.
146    pub rotation: u8,
147    /// Spacing between the eyes.
148    pub x_spacing: u8,
149    /// Eye height.
150    pub y_position: u8,
151}
152
153/// Eyebrow details of the Mii.
154#[derive(Copy, Clone, Debug)]
155pub struct EyebrowDetails {
156    /// Eyebrow style.
157    pub style: u8,
158    /// Eyebrow color.
159    pub color: u8,
160    /// Eyebrow scale.
161    pub scale: u8,
162    /// Eyebrow scale (y-axis).
163    pub y_scale: u8,
164    /// Eyebrow rotation.
165    pub rotation: u8,
166    /// Spacing between the eyebrows
167    pub x_spacing: u8,
168    /// Eyebrow height.
169    pub y_position: u8,
170}
171
172/// Nose details of the Mii.
173#[derive(Copy, Clone, Debug)]
174pub struct NoseDetails {
175    /// Nose style.
176    pub style: u8,
177    /// Nose scale.
178    pub scale: u8,
179    /// Nose height.
180    pub y_position: u8,
181}
182
183/// Mouth details of the Mii.
184#[derive(Copy, Clone, Debug)]
185pub struct MouthDetails {
186    /// Mouth style.
187    pub style: u8,
188    /// Mouth color.
189    pub color: u8,
190    /// Mouth scale.
191    pub scale: u8,
192    /// Mouth scale (y-axis).
193    pub y_scale: u8,
194    /// Mouth height.
195    pub y_position: u8,
196}
197
198/// Mustache details of the Mii.
199#[derive(Copy, Clone, Debug)]
200pub struct MustacheDetails {
201    /// Mustache style.
202    pub mustache_style: u8,
203}
204
205/// Beard details of the Mii.
206#[derive(Copy, Clone, Debug)]
207pub struct BeardDetails {
208    /// Beard style
209    pub style: u8,
210    /// Beard color.
211    pub color: u8,
212    /// Beard scale.
213    pub scale: u8,
214    /// Beard height.
215    pub y_position: u8,
216}
217
218/// Glasses details of the Mii.
219#[derive(Copy, Clone, Debug)]
220pub struct GlassesDetails {
221    /// Glasses style.
222    pub style: u8,
223    /// Glasses color.
224    pub color: u8,
225    /// Glasses scale.
226    pub scale: u8,
227    /// Glasses height.
228    pub y_position: u8,
229}
230
231/// Mole details of the Mii.
232#[derive(Copy, Clone, Debug)]
233pub struct MoleDetails {
234    /// Whether the Mii has a mole.
235    pub is_enabled: bool,
236    /// Mole scale.
237    pub scale: u8,
238    /// Mole position (x-axis).
239    pub x_position: u8,
240    /// Mole position (y-axis).
241    pub y_position: u8,
242}
243
244/// Full Mii data representation.
245///
246/// Some values are not ordered *like* the Mii Editor UI. The mapped values can be seen [here](https://www.3dbrew.org/wiki/Mii#Mapped_Editor_.3C-.3E_Hex_values).
247///
248/// This struct can be retrieved by [`MiiSelector::launch()`](crate::applets::mii_selector::MiiSelector::launch).
249#[derive(Clone, Debug)]
250pub struct Mii {
251    /// Mii options.
252    pub options: Options,
253    /// Position taken by the Mii on the Mii Selector screen.
254    pub selector_position: SelectorPosition,
255    /// Console the Mii was created on.
256    pub console_identity: ConsoleIdentity,
257
258    /// Unique system ID, not dependant on the MAC address
259    pub system_id: u64,
260    /// Console's MAC address.
261    pub mac_address: [u8; 6],
262
263    /// General information about the Mii.
264    pub details: Details,
265    /// Mii name.
266    pub name: String,
267
268    /// Mii height.
269    pub height: u8,
270    /// Mii width.
271    pub width: u8,
272
273    /// Face details.
274    pub face_details: FaceDetails,
275    /// Hair details.
276    pub hair_details: HairDetails,
277    /// Eyes details.
278    pub eye_details: EyeDetails,
279    /// Eyebrow details.
280    pub eyebrow_details: EyebrowDetails,
281    /// Nose details.
282    pub nose_details: NoseDetails,
283    /// Mouth details.
284    pub mouth_details: MouthDetails,
285    /// Mustache details.
286    pub mustache_details: MustacheDetails,
287    /// Beard details.
288    pub beard_details: BeardDetails,
289    /// Glasses details.
290    pub glasses_details: GlassesDetails,
291    /// Mole details.
292    pub mole_details: MoleDetails,
293
294    /// Name of the Mii's original author.
295    pub author_name: String,
296}
297
298impl From<ctru_sys::MiiData> for Mii {
299    fn from(mii_data: ctru_sys::MiiData) -> Self {
300        // Source for the representation and what each thing means: https://www.3dbrew.org/wiki/Mii
301        let raw_options = mii_data.mii_options._bitfield_1;
302        let raw_position = mii_data.mii_pos._bitfield_1;
303        let raw_device = mii_data.console_identity._bitfield_1;
304        let system_id = mii_data.system_id;
305        let mac_address = mii_data.mac;
306        let raw_details = mii_data.mii_details._bitfield_1;
307        let raw_utf16_name = mii_data.mii_name;
308        let height = mii_data.height;
309        let width = mii_data.width;
310        let raw_face_style = mii_data.face_style._bitfield_1;
311        let raw_face_details = mii_data.face_details._bitfield_1;
312        let raw_hair_style = mii_data.hair_style;
313        let raw_hair_details = mii_data.hair_details._bitfield_1;
314        let raw_eye_details = mii_data.eye_details._bitfield_1;
315        let raw_eyebrow_details = mii_data.eyebrow_details._bitfield_1;
316        let raw_nose_details = mii_data.nose_details._bitfield_1;
317        let raw_mouth_details = mii_data.mouth_details._bitfield_1;
318        let raw_mustache_details = mii_data.mustache_details._bitfield_1;
319        let raw_beard_details = mii_data.beard_details._bitfield_1;
320        let raw_glasses_details = mii_data.glasses_details._bitfield_1;
321        let raw_mole_details = mii_data.mole_details._bitfield_1;
322        let raw_utf16_author = mii_data.author_name;
323
324        let name = String::from_utf16_lossy(&raw_utf16_name).replace('\0', "");
325        let author_name = String::from_utf16_lossy(&raw_utf16_author).replace('\0', "");
326
327        let options = Options {
328            is_copying_allowed: raw_options.get_bit(0),
329            is_profanity_flag_enabled: raw_options.get_bit(1),
330            region_lock: {
331                match (raw_options.get_bit(3), raw_options.get_bit(2)) {
332                    (false, false) => RegionLock::None,
333                    (false, true) => RegionLock::Japan,
334                    (true, false) => RegionLock::USA,
335                    (true, true) => RegionLock::Europe,
336                }
337            },
338            charset: {
339                match (raw_options.get_bit(5), raw_options.get_bit(4)) {
340                    (false, false) => Charset::JapanUSAEurope,
341                    (false, true) => Charset::China,
342                    (true, false) => Charset::Korea,
343                    (true, true) => Charset::Taiwan,
344                }
345            },
346        };
347
348        let selector_position = SelectorPosition {
349            page_index: raw_position.get(0, 4) as u8, // index 0 to 3
350            slot_index: raw_position.get(4, 4) as u8, // index 4 to 7
351        };
352
353        let console_identity = ConsoleIdentity {
354            origin_console: {
355                match (
356                    raw_device.get_bit(6),
357                    raw_device.get_bit(5),
358                    raw_device.get_bit(4),
359                ) {
360                    (false, false, true) => OriginConsole::Wii,
361                    (false, true, false) => OriginConsole::DSi,
362                    (false, true, true) => OriginConsole::N3DS,
363                    _ => OriginConsole::WiiUSwitch,
364                }
365            },
366        };
367
368        let details = Details {
369            sex: {
370                match raw_details.get_bit(0) {
371                    true => Sex::Female,
372                    false => Sex::Male,
373                }
374            },
375            birthday_month: raw_details.get(1, 4) as u8, // index 1 to 4
376            birthday_day: raw_details.get(5, 5) as u8,   // index 5 to 9
377            shirt_color: raw_details.get(10, 4) as u8,   // index 10 to 13
378            is_favorite: raw_details.get_bit(14),
379            is_sharing_enabled: !raw_face_style.get_bit(0),
380        };
381
382        let face_details = FaceDetails {
383            style: FaceStyle {
384                shape: raw_face_style.get(1, 4) as u8,      // index 1 to 4
385                skin_color: raw_face_style.get(5, 3) as u8, // index 5 to 7
386            },
387            wrinkles: raw_face_details.get(0, 4) as u8, // index 0 to 3
388            makeup: raw_face_details.get(4, 4) as u8,   // index 4 to 7
389        };
390
391        let hair_details = HairDetails {
392            style: raw_hair_style,
393            color: raw_hair_details.get(0, 3) as u8, // index 0 to 2
394            is_flipped: raw_hair_details.get_bit(3),
395        };
396
397        let eye_details = EyeDetails {
398            style: raw_eye_details.get(0, 6) as u8,       // index 0 to 5
399            color: raw_eye_details.get(6, 3) as u8,       // index 6 to 8
400            scale: raw_eye_details.get(9, 4) as u8,       // index 9 to 12
401            y_scale: raw_eye_details.get(13, 3) as u8,    // index 13 to 15
402            rotation: raw_eye_details.get(16, 5) as u8,   // index 16 to 20
403            x_spacing: raw_eye_details.get(21, 4) as u8,  // index 21 to 24
404            y_position: raw_eye_details.get(25, 5) as u8, // index 25 to 29
405        };
406
407        let eyebrow_details = EyebrowDetails {
408            style: raw_eyebrow_details.get(0, 5) as u8, // index 0 to 4
409            color: raw_eyebrow_details.get(5, 3) as u8, // index 5 to 7
410            scale: raw_eyebrow_details.get(8, 4) as u8, // index 8 to 11
411            y_scale: raw_eyebrow_details.get(12, 3) as u8, // index 12 to 14
412            // Bits are skipped here, following the 3dbrew wiki:
413            // https://www.3dbrew.org/wiki/Mii#Mii_format offset 0x38
414            rotation: raw_eyebrow_details.get(16, 4) as u8, // index 16 to 19
415            x_spacing: raw_eyebrow_details.get(21, 4) as u8, // index 21 to 24
416            y_position: raw_eyebrow_details.get(25, 5) as u8, // index 25 to 29
417        };
418
419        let nose_details = NoseDetails {
420            style: raw_nose_details.get(0, 5) as u8,      // index 0 to 4
421            scale: raw_nose_details.get(5, 4) as u8,      // index 5 to 8
422            y_position: raw_nose_details.get(9, 5) as u8, // index 9 to 13
423        };
424
425        let mouth_details = MouthDetails {
426            style: raw_mouth_details.get(0, 6) as u8,    // index 0 to 5
427            color: raw_mouth_details.get(6, 3) as u8,    // index 6 to 8
428            scale: raw_mouth_details.get(9, 4) as u8,    // index 9 to 12
429            y_scale: raw_mouth_details.get(13, 3) as u8, // index 13 to 15
430            y_position: raw_mustache_details.get(0, 5) as u8, // index 0 to 4
431        };
432
433        let mustache_details = MustacheDetails {
434            mustache_style: raw_mustache_details.get(5, 3) as u8, // index 5 to 7
435        };
436
437        let beard_details = BeardDetails {
438            style: raw_beard_details.get(0, 3) as u8, // index 0 to 2
439            color: raw_beard_details.get(3, 6) as u8, // index 3 to 5
440            scale: raw_beard_details.get(6, 4) as u8, // index 6 to 9
441            y_position: raw_beard_details.get(10, 5) as u8, // index 10 to 14
442        };
443
444        let glasses_details = GlassesDetails {
445            style: raw_glasses_details.get(0, 4) as u8, // index 0 to 3
446            color: raw_glasses_details.get(4, 3) as u8, // index 4 to 6
447            scale: raw_glasses_details.get(7, 4) as u8, // index 7 to 10
448            y_position: raw_glasses_details.get(11, 5) as u8, // index 11 to 15
449        };
450
451        let mole_details = MoleDetails {
452            is_enabled: raw_mole_details.get_bit(0),
453            scale: raw_mole_details.get(1, 4) as u8, // index 1 to 4
454            x_position: raw_mole_details.get(5, 5) as u8, // index 5 to 9
455            y_position: raw_mole_details.get(10, 5) as u8, // index 10 to 14
456        };
457
458        Mii {
459            options,
460            selector_position,
461            console_identity,
462            system_id,
463            mac_address,
464            details,
465            name,
466            height,
467            width,
468            face_details,
469            hair_details,
470            eye_details,
471            eyebrow_details,
472            nose_details,
473            mouth_details,
474            mustache_details,
475            beard_details,
476            glasses_details,
477            mole_details,
478            author_name,
479        }
480    }
481}