code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/assert.h"
#include "core/hle/service/mii/mii_util.h"
#include "core/hle/service/mii/types/char_info.h"
#include "core/hle/service/mii/types/core_data.h"
#include "core/hle/service/mii/types/raw_data.h"

namespace Service::Mii {

void CoreData::SetDefault() {
    data = {};
    name = GetDefaultNickname();
}

void CoreData::BuildRandom(Age age, Gender gender, Race race) {
    if (gender == Gender::All) {
        gender = MiiUtil::GetRandomValue(Gender::Max);
    }

    if (age == Age::All) {
        const auto random{MiiUtil::GetRandomValue<int>(10)};
        if (random >= 8) {
            age = Age::Old;
        } else if (random >= 4) {
            age = Age::Normal;
        } else {
            age = Age::Young;
        }
    }

    if (race == Race::All) {
        const auto random{MiiUtil::GetRandomValue<int>(10)};
        if (random >= 8) {
            race = Race::Black;
        } else if (random >= 4) {
            race = Race::White;
        } else {
            race = Race::Asian;
        }
    }

    SetDefault();
    SetGender(gender);
    SetFavoriteColor(MiiUtil::GetRandomValue(FavoriteColor::Max));
    SetRegionMove(0);
    SetFontRegion(FontRegion::Standard);
    SetType(0);
    SetHeight(64);
    SetBuild(64);

    u32 axis_y{};
    if (gender == Gender::Female && age == Age::Young) {
        axis_y = MiiUtil::GetRandomValue<u32>(3);
    }

    const std::size_t index{3 * static_cast<std::size_t>(age) +
                            9 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race)};

    const auto& faceline_type_info{RawData::RandomMiiFaceline.at(index)};
    const auto& faceline_color_info{RawData::RandomMiiFacelineColor.at(
        3 * static_cast<std::size_t>(gender) + static_cast<std::size_t>(race))};
    const auto& faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)};
    const auto& faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)};
    const auto& hair_type_info{RawData::RandomMiiHairType.at(index)};
    const auto& hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast<std::size_t>(race) +
                                                               static_cast<std::size_t>(age))};
    const auto& eye_type_info{RawData::RandomMiiEyeType.at(index)};
    const auto& eye_color_info{RawData::RandomMiiEyeColor.at(static_cast<std::size_t>(race))};
    const auto& eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)};
    const auto& nose_type_info{RawData::RandomMiiNoseType.at(index)};
    const auto& mouth_type_info{RawData::RandomMiiMouthType.at(index)};
    const auto& glasses_type_info{RawData::RandomMiiGlassType.at(static_cast<std::size_t>(age))};

    data.faceline_type.Assign(
        faceline_type_info
            .values[MiiUtil::GetRandomValue<std::size_t>(faceline_type_info.values_count)]);
    data.faceline_color.Assign(
        faceline_color_info
            .values[MiiUtil::GetRandomValue<std::size_t>(faceline_color_info.values_count)]);
    data.faceline_wrinkle.Assign(
        faceline_wrinkle_info
            .values[MiiUtil::GetRandomValue<std::size_t>(faceline_wrinkle_info.values_count)]);
    data.faceline_makeup.Assign(
        faceline_makeup_info
            .values[MiiUtil::GetRandomValue<std::size_t>(faceline_makeup_info.values_count)]);

    data.hair_type.Assign(
        hair_type_info.values[MiiUtil::GetRandomValue<std::size_t>(hair_type_info.values_count)]);
    SetHairColor(RawData::GetHairColorFromVer3(
        hair_color_info
            .values[MiiUtil::GetRandomValue<std::size_t>(hair_color_info.values_count)]));
    SetHairFlip(MiiUtil::GetRandomValue(HairFlip::Max));

    data.eye_type.Assign(
        eye_type_info.values[MiiUtil::GetRandomValue<std::size_t>(eye_type_info.values_count)]);

    const auto eye_rotate_1{gender != Gender::Male ? 4 : 2};
    const auto eye_rotate_2{gender != Gender::Male ? 3 : 4};
    const auto eye_rotate_offset{32 - RawData::EyeRotateLookup[eye_rotate_1] + eye_rotate_2};
    const auto eye_rotate{32 - RawData::EyeRotateLookup[data.eye_type]};

    SetEyeColor(RawData::GetEyeColorFromVer3(
        eye_color_info.values[MiiUtil::GetRandomValue<std::size_t>(eye_color_info.values_count)]));
    SetEyeScale(4);
    SetEyeAspect(3);
    SetEyeRotate(static_cast<u8>(eye_rotate_offset - eye_rotate));
    SetEyeX(2);
    SetEyeY(static_cast<u8>(axis_y + 12));

    data.eyebrow_type.Assign(
        eyebrow_type_info
            .values[MiiUtil::GetRandomValue<std::size_t>(eyebrow_type_info.values_count)]);

    const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0};
    const auto eyebrow_y{race == Race::Asian ? 6 : 7};
    const auto eyebrow_rotate_offset{32 - RawData::EyebrowRotateLookup[eyebrow_rotate_1] + 6};
    const auto eyebrow_rotate{
        32 - RawData::EyebrowRotateLookup[static_cast<std::size_t>(data.eyebrow_type.Value())]};

    SetEyebrowColor(GetHairColor());
    SetEyebrowScale(4);
    SetEyebrowAspect(3);
    SetEyebrowRotate(static_cast<u8>(eyebrow_rotate_offset - eyebrow_rotate));
    SetEyebrowX(2);
    SetEyebrowY(static_cast<u8>(axis_y + eyebrow_y));

    data.nose_type.Assign(
        nose_type_info.values[MiiUtil::GetRandomValue<std::size_t>(nose_type_info.values_count)]);
    SetNoseScale(gender == Gender::Female ? 3 : 4);
    SetNoseY(static_cast<u8>(axis_y + 9));

    const auto mouth_color{gender == Gender::Female ? MiiUtil::GetRandomValue<int>(4) : 0};

    data.mouth_type.Assign(
        mouth_type_info.values[MiiUtil::GetRandomValue<std::size_t>(mouth_type_info.values_count)]);
    SetMouthColor(RawData::GetMouthColorFromVer3(mouth_color));
    SetMouthScale(4);
    SetMouthAspect(3);
    SetMouthY(static_cast<u8>(axis_y + 13));

    SetBeardColor(GetHairColor());
    SetMustacheScale(4);

    if (gender == Gender::Male && age != Age::Young && MiiUtil::GetRandomValue<int>(10) < 2) {
        const auto mustache_and_beard_flag{MiiUtil::GetRandomValue(BeardAndMustacheFlag::All)};

        auto beard_type{BeardType::None};
        auto mustache_type{MustacheType::None};

        if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) ==
            BeardAndMustacheFlag::Beard) {
            beard_type = MiiUtil::GetRandomValue(BeardType::Min, BeardType::Max);
        }

        if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) ==
            BeardAndMustacheFlag::Mustache) {
            mustache_type = MiiUtil::GetRandomValue(MustacheType::Min, MustacheType::Max);
        }

        SetMustacheType(mustache_type);
        SetBeardType(beard_type);
        SetMustacheY(10);
    } else {
        SetMustacheType(MustacheType::None);
        SetBeardType(BeardType::None);
        SetMustacheY(static_cast<u8>(axis_y + 10));
    }

    const auto glasses_type_start{MiiUtil::GetRandomValue<std::size_t>(100)};
    u8 glasses_type{};
    while (glasses_type_start < glasses_type_info.values[glasses_type]) {
        if (++glasses_type >= glasses_type_info.values_count) {
            glasses_type = 0;
            break;
        }
    }

    SetGlassType(static_cast<GlassType>(glasses_type));
    SetGlassColor(RawData::GetGlassColorFromVer3(0));
    SetGlassScale(4);
    SetGlassY(static_cast<u8>(axis_y + 10));

    SetMoleType(MoleType::None);
    SetMoleScale(4);
    SetMoleX(2);
    SetMoleY(20);
}

void CoreData::BuildFromCharInfo(const CharInfo& char_info) {
    name = char_info.GetNickname();
    SetFontRegion(char_info.GetFontRegion());
    SetFavoriteColor(char_info.GetFavoriteColor());
    SetGender(char_info.GetGender());
    SetHeight(char_info.GetHeight());
    SetBuild(char_info.GetBuild());
    SetType(char_info.GetType());
    SetRegionMove(char_info.GetRegionMove());
    SetFacelineType(char_info.GetFacelineType());
    SetFacelineColor(char_info.GetFacelineColor());
    SetFacelineWrinkle(char_info.GetFacelineWrinkle());
    SetFacelineMake(char_info.GetFacelineMake());
    SetHairType(char_info.GetHairType());
    SetHairColor(char_info.GetHairColor());
    SetHairFlip(char_info.GetHairFlip());
    SetEyeType(char_info.GetEyeType());
    SetEyeColor(char_info.GetEyeColor());
    SetEyeScale(char_info.GetEyeScale());
    SetEyeAspect(char_info.GetEyeAspect());
    SetEyeRotate(char_info.GetEyeRotate());
    SetEyeX(char_info.GetEyeX());
    SetEyeY(char_info.GetEyeY());
    SetEyebrowType(char_info.GetEyebrowType());
    SetEyebrowColor(char_info.GetEyebrowColor());
    SetEyebrowScale(char_info.GetEyebrowScale());
    SetEyebrowAspect(char_info.GetEyebrowAspect());
    SetEyebrowRotate(char_info.GetEyebrowRotate());
    SetEyebrowX(char_info.GetEyebrowX());
    SetEyebrowY(char_info.GetEyebrowY() - 3);
    SetNoseType(char_info.GetNoseType());
    SetNoseScale(char_info.GetNoseScale());
    SetNoseY(char_info.GetNoseY());
    SetMouthType(char_info.GetMouthType());
    SetMouthColor(char_info.GetMouthColor());
    SetMouthScale(char_info.GetMouthScale());
    SetMouthAspect(char_info.GetMouthAspect());
    SetMouthY(char_info.GetMouthY());
    SetBeardColor(char_info.GetBeardColor());
    SetBeardType(char_info.GetBeardType());
    SetMustacheType(char_info.GetMustacheType());
    SetMustacheScale(char_info.GetMustacheScale());
    SetMustacheY(char_info.GetMustacheY());
    SetGlassType(char_info.GetGlassType());
    SetGlassColor(char_info.GetGlassColor());
    SetGlassScale(char_info.GetGlassScale());
    SetGlassY(char_info.GetGlassY());
    SetMoleType(char_info.GetMoleType());
    SetMoleScale(char_info.GetMoleScale());
    SetMoleX(char_info.GetMoleX());
    SetMoleY(char_info.GetMoleY());
}

ValidationResult CoreData::IsValid() const {
    if (!name.IsValid()) {
        return ValidationResult::InvalidName;
    }
    if (GetFontRegion() > FontRegion::Max) {
        return ValidationResult::InvalidFont;
    }
    if (GetFavoriteColor() > FavoriteColor::Max) {
        return ValidationResult::InvalidColor;
    }
    if (GetGender() > Gender::Max) {
        return ValidationResult::InvalidGender;
    }
    if (GetHeight() > MaxHeight) {
        return ValidationResult::InvalidHeight;
    }
    if (GetBuild() > MaxBuild) {
        return ValidationResult::InvalidBuild;
    }
    if (GetType() > MaxType) {
        return ValidationResult::InvalidType;
    }
    if (GetRegionMove() > MaxRegionMove) {
        return ValidationResult::InvalidRegionMove;
    }
    if (GetFacelineType() > FacelineType::Max) {
        return ValidationResult::InvalidFacelineType;
    }
    if (GetFacelineColor() > FacelineColor::Max) {
        return ValidationResult::InvalidFacelineColor;
    }
    if (GetFacelineWrinkle() > FacelineWrinkle::Max) {
        return ValidationResult::InvalidFacelineWrinkle;
    }
    if (GetFacelineMake() > FacelineMake::Max) {
        return ValidationResult::InvalidFacelineMake;
    }
    if (GetHairType() > HairType::Max) {
        return ValidationResult::InvalidHairType;
    }
    if (GetHairColor() > CommonColor::Max) {
        return ValidationResult::InvalidHairColor;
    }
    if (GetHairFlip() > HairFlip::Max) {
        return ValidationResult::InvalidHairFlip;
    }
    if (GetEyeType() > EyeType::Max) {
        return ValidationResult::InvalidEyeType;
    }
    if (GetEyeColor() > CommonColor::Max) {
        return ValidationResult::InvalidEyeColor;
    }
    if (GetEyeScale() > MaxEyeScale) {
        return ValidationResult::InvalidEyeScale;
    }
    if (GetEyeAspect() > MaxEyeAspect) {
        return ValidationResult::InvalidEyeAspect;
    }
    if (GetEyeRotate() > MaxEyeRotate) {
        return ValidationResult::InvalidEyeRotate;
    }
    if (GetEyeX() > MaxEyeX) {
        return ValidationResult::InvalidEyeX;
    }
    if (GetEyeY() > MaxEyeY) {
        return ValidationResult::InvalidEyeY;
    }
    if (GetEyebrowType() > EyebrowType::Max) {
        return ValidationResult::InvalidEyebrowType;
    }
    if (GetEyebrowColor() > CommonColor::Max) {
        return ValidationResult::InvalidEyebrowColor;
    }
    if (GetEyebrowScale() > MaxEyebrowScale) {
        return ValidationResult::InvalidEyebrowScale;
    }
    if (GetEyebrowAspect() > MaxEyebrowAspect) {
        return ValidationResult::InvalidEyebrowAspect;
    }
    if (GetEyebrowRotate() > MaxEyebrowRotate) {
        return ValidationResult::InvalidEyebrowRotate;
    }
    if (GetEyebrowX() > MaxEyebrowX) {
        return ValidationResult::InvalidEyebrowX;
    }
    if (GetEyebrowY() > MaxEyebrowY) {
        return ValidationResult::InvalidEyebrowY;
    }
    if (GetNoseType() > NoseType::Max) {
        return ValidationResult::InvalidNoseType;
    }
    if (GetNoseScale() > MaxNoseScale) {
        return ValidationResult::InvalidNoseScale;
    }
    if (GetNoseY() > MaxNoseY) {
        return ValidationResult::InvalidNoseY;
    }
    if (GetMouthType() > MouthType::Max) {
        return ValidationResult::InvalidMouthType;
    }
    if (GetMouthColor() > CommonColor::Max) {
        return ValidationResult::InvalidMouthColor;
    }
    if (GetMouthScale() > MaxMouthScale) {
        return ValidationResult::InvalidMouthScale;
    }
    if (GetMouthAspect() > MaxMoutAspect) {
        return ValidationResult::InvalidMouthAspect;
    }
    if (GetMouthY() > MaxMouthY) {
        return ValidationResult::InvalidMouthY;
    }
    if (GetBeardColor() > CommonColor::Max) {
        return ValidationResult::InvalidBeardColor;
    }
    if (GetBeardType() > BeardType::Max) {
        return ValidationResult::InvalidBeardType;
    }
    if (GetMustacheType() > MustacheType::Max) {
        return ValidationResult::InvalidMustacheType;
    }
    if (GetMustacheScale() > MaxMustacheScale) {
        return ValidationResult::InvalidMustacheScale;
    }
    if (GetMustacheY() > MaxMustacheY) {
        return ValidationResult::InvalidMustacheY;
    }
    if (GetGlassType() > GlassType::Max) {
        return ValidationResult::InvalidGlassType;
    }
    if (GetGlassColor() > CommonColor::Max) {
        return ValidationResult::InvalidGlassColor;
    }
    if (GetGlassScale() > MaxGlassScale) {
        return ValidationResult::InvalidGlassScale;
    }
    if (GetGlassY() > MaxGlassY) {
        return ValidationResult::InvalidGlassY;
    }
    if (GetMoleType() > MoleType::Max) {
        return ValidationResult::InvalidMoleType;
    }
    if (GetMoleScale() > MaxMoleScale) {
        return ValidationResult::InvalidMoleScale;
    }
    if (GetMoleX() > MaxMoleX) {
        return ValidationResult::InvalidMoleX;
    }
    if (GetMoleY() > MaxMoleY) {
        return ValidationResult::InvalidMoleY;
    }
    return ValidationResult::NoErrors;
}

void CoreData::SetFontRegion(FontRegion value) {
    data.font_region.Assign(static_cast<u32>(value));
}

void CoreData::SetFavoriteColor(FavoriteColor value) {
    data.favorite_color.Assign(static_cast<u32>(value));
}

void CoreData::SetGender(Gender value) {
    data.gender.Assign(static_cast<u32>(value));
}

void CoreData::SetHeight(u8 value) {
    data.height.Assign(value);
}

void CoreData::SetBuild(u8 value) {
    data.build.Assign(value);
}

void CoreData::SetType(u8 value) {
    data.type.Assign(value);
}

void CoreData::SetRegionMove(u8 value) {
    data.region_move.Assign(value);
}

void CoreData::SetFacelineType(FacelineType value) {
    data.faceline_type.Assign(static_cast<u32>(value));
}

void CoreData::SetFacelineColor(FacelineColor value) {
    data.faceline_color.Assign(static_cast<u32>(value));
}

void CoreData::SetFacelineWrinkle(FacelineWrinkle value) {
    data.faceline_wrinkle.Assign(static_cast<u32>(value));
}

void CoreData::SetFacelineMake(FacelineMake value) {
    data.faceline_makeup.Assign(static_cast<u32>(value));
}

void CoreData::SetHairType(HairType value) {
    data.hair_type.Assign(static_cast<u32>(value));
}

void CoreData::SetHairColor(CommonColor value) {
    data.hair_color.Assign(static_cast<u32>(value));
}

void CoreData::SetHairFlip(HairFlip value) {
    data.hair_flip.Assign(static_cast<u32>(value));
}

void CoreData::SetEyeType(EyeType value) {
    data.eye_type.Assign(static_cast<u32>(value));
}

void CoreData::SetEyeColor(CommonColor value) {
    data.eye_color.Assign(static_cast<u32>(value));
}

void CoreData::SetEyeScale(u8 value) {
    data.eye_scale.Assign(value);
}

void CoreData::SetEyeAspect(u8 value) {
    data.eye_aspect.Assign(value);
}

void CoreData::SetEyeRotate(u8 value) {
    data.eye_rotate.Assign(value);
}

void CoreData::SetEyeX(u8 value) {
    data.eye_x.Assign(value);
}

void CoreData::SetEyeY(u8 value) {
    data.eye_y.Assign(value);
}

void CoreData::SetEyebrowType(EyebrowType value) {
    data.eyebrow_type.Assign(static_cast<u32>(value));
}

void CoreData::SetEyebrowColor(CommonColor value) {
    data.eyebrow_color.Assign(static_cast<u32>(value));
}

void CoreData::SetEyebrowScale(u8 value) {
    data.eyebrow_scale.Assign(value);
}

void CoreData::SetEyebrowAspect(u8 value) {
    data.eyebrow_aspect.Assign(value);
}

void CoreData::SetEyebrowRotate(u8 value) {
    data.eyebrow_rotate.Assign(value);
}

void CoreData::SetEyebrowX(u8 value) {
    data.eyebrow_x.Assign(value);
}

void CoreData::SetEyebrowY(u8 value) {
    data.eyebrow_y.Assign(value);
}

void CoreData::SetNoseType(NoseType value) {
    data.nose_type.Assign(static_cast<u32>(value));
}

void CoreData::SetNoseScale(u8 value) {
    data.nose_scale.Assign(value);
}

void CoreData::SetNoseY(u8 value) {
    data.nose_y.Assign(value);
}

void CoreData::SetMouthType(MouthType value) {
    data.mouth_type.Assign(static_cast<u32>(value));
}

void CoreData::SetMouthColor(CommonColor value) {
    data.mouth_color.Assign(static_cast<u32>(value));
}

void CoreData::SetMouthScale(u8 value) {
    data.mouth_scale.Assign(value);
}

void CoreData::SetMouthAspect(u8 value) {
    data.mouth_aspect.Assign(value);
}

void CoreData::SetMouthY(u8 value) {
    data.mouth_y.Assign(value);
}

void CoreData::SetBeardColor(CommonColor value) {
    data.beard_color.Assign(static_cast<u32>(value));
}

void CoreData::SetBeardType(BeardType value) {
    data.beard_type.Assign(static_cast<u32>(value));
}

void CoreData::SetMustacheType(MustacheType value) {
    data.mustache_type.Assign(static_cast<u32>(value));
}

void CoreData::SetMustacheScale(u8 value) {
    data.mustache_scale.Assign(value);
}

void CoreData::SetMustacheY(u8 value) {
    data.mustache_y.Assign(value);
}

void CoreData::SetGlassType(GlassType value) {
    data.glasses_type.Assign(static_cast<u32>(value));
}

void CoreData::SetGlassColor(CommonColor value) {
    data.glasses_color.Assign(static_cast<u32>(value));
}

void CoreData::SetGlassScale(u8 value) {
    data.glasses_scale.Assign(value);
}

void CoreData::SetGlassY(u8 value) {
    data.glasses_y.Assign(value);
}

void CoreData::SetMoleType(MoleType value) {
    data.mole_type.Assign(static_cast<u32>(value));
}

void CoreData::SetMoleScale(u8 value) {
    data.mole_scale.Assign(value);
}

void CoreData::SetMoleX(u8 value) {
    data.mole_x.Assign(value);
}

void CoreData::SetMoleY(u8 value) {
    data.mole_y.Assign(value);
}

void CoreData::SetNickname(Nickname nickname) {
    name = nickname;
}

FontRegion CoreData::GetFontRegion() const {
    return static_cast<FontRegion>(data.font_region.Value());
}

FavoriteColor CoreData::GetFavoriteColor() const {
    return static_cast<FavoriteColor>(data.favorite_color.Value());
}

Gender CoreData::GetGender() const {
    return static_cast<Gender>(data.gender.Value());
}

u8 CoreData::GetHeight() const {
    return static_cast<u8>(data.height.Value());
}

u8 CoreData::GetBuild() const {
    return static_cast<u8>(data.build.Value());
}

u8 CoreData::GetType() const {
    return static_cast<u8>(data.type.Value());
}

u8 CoreData::GetRegionMove() const {
    return static_cast<u8>(data.region_move.Value());
}

FacelineType CoreData::GetFacelineType() const {
    return static_cast<FacelineType>(data.faceline_type.Value());
}

FacelineColor CoreData::GetFacelineColor() const {
    return static_cast<FacelineColor>(data.faceline_color.Value());
}

FacelineWrinkle CoreData::GetFacelineWrinkle() const {
    return static_cast<FacelineWrinkle>(data.faceline_wrinkle.Value());
}

FacelineMake CoreData::GetFacelineMake() const {
    return static_cast<FacelineMake>(data.faceline_makeup.Value());
}

HairType CoreData::GetHairType() const {
    return static_cast<HairType>(data.hair_type.Value());
}

CommonColor CoreData::GetHairColor() const {
    return static_cast<CommonColor>(data.hair_color.Value());
}

HairFlip CoreData::GetHairFlip() const {
    return static_cast<HairFlip>(data.hair_flip.Value());
}

EyeType CoreData::GetEyeType() const {
    return static_cast<EyeType>(data.eye_type.Value());
}

CommonColor CoreData::GetEyeColor() const {
    return static_cast<CommonColor>(data.eye_color.Value());
}

u8 CoreData::GetEyeScale() const {
    return static_cast<u8>(data.eye_scale.Value());
}

u8 CoreData::GetEyeAspect() const {
    return static_cast<u8>(data.eye_aspect.Value());
}

u8 CoreData::GetEyeRotate() const {
    return static_cast<u8>(data.eye_rotate.Value());
}

u8 CoreData::GetEyeX() const {
    return static_cast<u8>(data.eye_x.Value());
}

u8 CoreData::GetEyeY() const {
    return static_cast<u8>(data.eye_y.Value());
}

EyebrowType CoreData::GetEyebrowType() const {
    return static_cast<EyebrowType>(data.eyebrow_type.Value());
}

CommonColor CoreData::GetEyebrowColor() const {
    return static_cast<CommonColor>(data.eyebrow_color.Value());
}

u8 CoreData::GetEyebrowScale() const {
    return static_cast<u8>(data.eyebrow_scale.Value());
}

u8 CoreData::GetEyebrowAspect() const {
    return static_cast<u8>(data.eyebrow_aspect.Value());
}

u8 CoreData::GetEyebrowRotate() const {
    return static_cast<u8>(data.eyebrow_rotate.Value());
}

u8 CoreData::GetEyebrowX() const {
    return static_cast<u8>(data.eyebrow_x.Value());
}

u8 CoreData::GetEyebrowY() const {
    return static_cast<u8>(data.eyebrow_y.Value());
}

NoseType CoreData::GetNoseType() const {
    return static_cast<NoseType>(data.nose_type.Value());
}

u8 CoreData::GetNoseScale() const {
    return static_cast<u8>(data.nose_scale.Value());
}

u8 CoreData::GetNoseY() const {
    return static_cast<u8>(data.nose_y.Value());
}

MouthType CoreData::GetMouthType() const {
    return static_cast<MouthType>(data.mouth_type.Value());
}

CommonColor CoreData::GetMouthColor() const {
    return static_cast<CommonColor>(data.mouth_color.Value());
}

u8 CoreData::GetMouthScale() const {
    return static_cast<u8>(data.mouth_scale.Value());
}

u8 CoreData::GetMouthAspect() const {
    return static_cast<u8>(data.mouth_aspect.Value());
}

u8 CoreData::GetMouthY() const {
    return static_cast<u8>(data.mouth_y.Value());
}

CommonColor CoreData::GetBeardColor() const {
    return static_cast<CommonColor>(data.beard_color.Value());
}

BeardType CoreData::GetBeardType() const {
    return static_cast<BeardType>(data.beard_type.Value());
}

MustacheType CoreData::GetMustacheType() const {
    return static_cast<MustacheType>(data.mustache_type.Value());
}

u8 CoreData::GetMustacheScale() const {
    return static_cast<u8>(data.mustache_scale.Value());
}

u8 CoreData::GetMustacheY() const {
    return static_cast<u8>(data.mustache_y.Value());
}

GlassType CoreData::GetGlassType() const {
    return static_cast<GlassType>(data.glasses_type.Value());
}

CommonColor CoreData::GetGlassColor() const {
    return static_cast<CommonColor>(data.glasses_color.Value());
}

u8 CoreData::GetGlassScale() const {
    return static_cast<u8>(data.glasses_scale.Value());
}

u8 CoreData::GetGlassY() const {
    return static_cast<u8>(data.glasses_y.Value());
}

MoleType CoreData::GetMoleType() const {
    return static_cast<MoleType>(data.mole_type.Value());
}

u8 CoreData::GetMoleScale() const {
    return static_cast<u8>(data.mole_scale.Value());
}

u8 CoreData::GetMoleX() const {
    return static_cast<u8>(data.mole_x.Value());
}

u8 CoreData::GetMoleY() const {
    return static_cast<u8>(data.mole_y.Value());
}

Nickname CoreData::GetNickname() const {
    return name;
}

Nickname CoreData::GetDefaultNickname() const {
    return {u'n', u'o', u' ', u'n', u'a', u'm', u'e'};
}

Nickname CoreData::GetInvalidNickname() const {
    return {u'?', u'?', u'?'};
}

} // namespace Service::Mii


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/mii/mii_types.h"

namespace Service::Mii {
class CharInfo;

struct StoreDataBitFields {
    union {
        u32 word_0{};

        BitField<0, 8, u32> hair_type;
        BitField<8, 7, u32> height;
        BitField<15, 1, u32> mole_type;
        BitField<16, 7, u32> build;
        BitField<23, 1, u32> hair_flip;
        BitField<24, 7, u32> hair_color;
        BitField<31, 1, u32> type;
    };

    union {
        u32 word_1{};

        BitField<0, 7, u32> eye_color;
        BitField<7, 1, u32> gender;
        BitField<8, 7, u32> eyebrow_color;
        BitField<16, 7, u32> mouth_color;
        BitField<24, 7, u32> beard_color;
    };

    union {
        u32 word_2{};

        BitField<0, 7, u32> glasses_color;
        BitField<8, 6, u32> eye_type;
        BitField<14, 2, u32> region_move;
        BitField<16, 6, u32> mouth_type;
        BitField<22, 2, u32> font_region;
        BitField<24, 5, u32> eye_y;
        BitField<29, 3, u32> glasses_scale;
    };

    union {
        u32 word_3{};

        BitField<0, 5, u32> eyebrow_type;
        BitField<5, 3, u32> mustache_type;
        BitField<8, 5, u32> nose_type;
        BitField<13, 3, u32> beard_type;
        BitField<16, 5, u32> nose_y;
        BitField<21, 3, u32> mouth_aspect;
        BitField<24, 5, u32> mouth_y;
        BitField<29, 3, u32> eyebrow_aspect;
    };

    union {
        u32 word_4{};

        BitField<0, 5, u32> mustache_y;
        BitField<5, 3, u32> eye_rotate;
        BitField<8, 5, u32> glasses_y;
        BitField<13, 3, u32> eye_aspect;
        BitField<16, 5, u32> mole_x;
        BitField<21, 3, u32> eye_scale;
        BitField<24, 5, u32> mole_y;
    };

    union {
        u32 word_5{};

        BitField<0, 5, u32> glasses_type;
        BitField<8, 4, u32> favorite_color;
        BitField<12, 4, u32> faceline_type;
        BitField<16, 4, u32> faceline_color;
        BitField<20, 4, u32> faceline_wrinkle;
        BitField<24, 4, u32> faceline_makeup;
        BitField<28, 4, u32> eye_x;
    };

    union {
        u32 word_6{};

        BitField<0, 4, u32> eyebrow_scale;
        BitField<4, 4, u32> eyebrow_rotate;
        BitField<8, 4, u32> eyebrow_x;
        BitField<12, 4, u32> eyebrow_y;
        BitField<16, 4, u32> nose_scale;
        BitField<20, 4, u32> mouth_scale;
        BitField<24, 4, u32> mustache_scale;
        BitField<28, 4, u32> mole_scale;
    };
};
static_assert(sizeof(StoreDataBitFields) == 0x1c, "StoreDataBitFields has incorrect size.");
static_assert(std::is_trivially_copyable_v<StoreDataBitFields>,
              "StoreDataBitFields is not trivially copyable.");

class CoreData {
public:
    void SetDefault();
    void BuildRandom(Age age, Gender gender, Race race);
    void BuildFromCharInfo(const CharInfo& char_info);

    ValidationResult IsValid() const;

    void SetFontRegion(FontRegion value);
    void SetFavoriteColor(FavoriteColor value);
    void SetGender(Gender value);
    void SetHeight(u8 value);
    void SetBuild(u8 value);
    void SetType(u8 value);
    void SetRegionMove(u8 value);
    void SetFacelineType(FacelineType value);
    void SetFacelineColor(FacelineColor value);
    void SetFacelineWrinkle(FacelineWrinkle value);
    void SetFacelineMake(FacelineMake value);
    void SetHairType(HairType value);
    void SetHairColor(CommonColor value);
    void SetHairFlip(HairFlip value);
    void SetEyeType(EyeType value);
    void SetEyeColor(CommonColor value);
    void SetEyeScale(u8 value);
    void SetEyeAspect(u8 value);
    void SetEyeRotate(u8 value);
    void SetEyeX(u8 value);
    void SetEyeY(u8 value);
    void SetEyebrowType(EyebrowType value);
    void SetEyebrowColor(CommonColor value);
    void SetEyebrowScale(u8 value);
    void SetEyebrowAspect(u8 value);
    void SetEyebrowRotate(u8 value);
    void SetEyebrowX(u8 value);
    void SetEyebrowY(u8 value);
    void SetNoseType(NoseType value);
    void SetNoseScale(u8 value);
    void SetNoseY(u8 value);
    void SetMouthType(MouthType value);
    void SetMouthColor(CommonColor value);
    void SetMouthScale(u8 value);
    void SetMouthAspect(u8 value);
    void SetMouthY(u8 value);
    void SetBeardColor(CommonColor value);
    void SetBeardType(BeardType value);
    void SetMustacheType(MustacheType value);
    void SetMustacheScale(u8 value);
    void SetMustacheY(u8 value);
    void SetGlassType(GlassType value);
    void SetGlassColor(CommonColor value);
    void SetGlassScale(u8 value);
    void SetGlassY(u8 value);
    void SetMoleType(MoleType value);
    void SetMoleScale(u8 value);
    void SetMoleX(u8 value);
    void SetMoleY(u8 value);
    void SetNickname(Nickname nickname);

    FontRegion GetFontRegion() const;
    FavoriteColor GetFavoriteColor() const;
    Gender GetGender() const;
    u8 GetHeight() const;
    u8 GetBuild() const;
    u8 GetType() const;
    u8 GetRegionMove() const;
    FacelineType GetFacelineType() const;
    FacelineColor GetFacelineColor() const;
    FacelineWrinkle GetFacelineWrinkle() const;
    FacelineMake GetFacelineMake() const;
    HairType GetHairType() const;
    CommonColor GetHairColor() const;
    HairFlip GetHairFlip() const;
    EyeType GetEyeType() const;
    CommonColor GetEyeColor() const;
    u8 GetEyeScale() const;
    u8 GetEyeAspect() const;
    u8 GetEyeRotate() const;
    u8 GetEyeX() const;
    u8 GetEyeY() const;
    EyebrowType GetEyebrowType() const;
    CommonColor GetEyebrowColor() const;
    u8 GetEyebrowScale() const;
    u8 GetEyebrowAspect() const;
    u8 GetEyebrowRotate() const;
    u8 GetEyebrowX() const;
    u8 GetEyebrowY() const;
    NoseType GetNoseType() const;
    u8 GetNoseScale() const;
    u8 GetNoseY() const;
    MouthType GetMouthType() const;
    CommonColor GetMouthColor() const;
    u8 GetMouthScale() const;
    u8 GetMouthAspect() const;
    u8 GetMouthY() const;
    CommonColor GetBeardColor() const;
    BeardType GetBeardType() const;
    MustacheType GetMustacheType() const;
    u8 GetMustacheScale() const;
    u8 GetMustacheY() const;
    GlassType GetGlassType() const;
    CommonColor GetGlassColor() const;
    u8 GetGlassScale() const;
    u8 GetGlassY() const;
    MoleType GetMoleType() const;
    u8 GetMoleScale() const;
    u8 GetMoleX() const;
    u8 GetMoleY() const;
    Nickname GetNickname() const;
    Nickname GetDefaultNickname() const;
    Nickname GetInvalidNickname() const;

private:
    StoreDataBitFields data{};
    Nickname name{};
};
static_assert(sizeof(CoreData) == 0x30, "CoreData has incorrect size.");
static_assert(std::is_trivially_copyable_v<CoreData>, "CoreData type must be trivially copyable.");

}; // namespace Service::Mii

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

#include "core/hle/service/mii/mii_types.h"

namespace Service::Mii::RawData {

struct RandomMiiValues {
    std::array<u8, 188> values{};
};
static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size.");

struct RandomMiiData4 {
    u32 gender{};
    u32 age{};
    u32 race{};
    u32 values_count{};
    std::array<u32, 47> values{};
};
static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size.");

struct RandomMiiData3 {
    u32 arg_1;
    u32 arg_2;
    u32 values_count;
    std::array<u32, 47> values{};
};
static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size.");

struct RandomMiiData2 {
    u32 arg_1;
    u32 values_count;
    std::array<u32, 47> values{};
};
static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size.");

extern const std::array<Service::Mii::DefaultMii, 2> BaseMii;
extern const std::array<Service::Mii::DefaultMii, 6> DefaultMii;

extern const std::array<u8, 62> EyeRotateLookup;
extern const std::array<u8, 24> EyebrowRotateLookup;

extern const std::array<RandomMiiData4, 18> RandomMiiFaceline;
extern const std::array<RandomMiiData3, 6> RandomMiiFacelineColor;
extern const std::array<RandomMiiData4, 18> RandomMiiFacelineWrinkle;
extern const std::array<RandomMiiData4, 18> RandomMiiFacelineMakeup;
extern const std::array<RandomMiiData4, 18> RandomMiiHairType;
extern const std::array<RandomMiiData3, 9> RandomMiiHairColor;
extern const std::array<RandomMiiData4, 18> RandomMiiEyeType;
extern const std::array<RandomMiiData2, 3> RandomMiiEyeColor;
extern const std::array<RandomMiiData4, 18> RandomMiiEyebrowType;
extern const std::array<RandomMiiData4, 18> RandomMiiNoseType;
extern const std::array<RandomMiiData4, 18> RandomMiiMouthType;
extern const std::array<RandomMiiData2, 3> RandomMiiGlassType;

u8 FromVer3GetFacelineColor(u8 color);
u8 FromVer3GetHairColor(u8 color);
u8 FromVer3GetEyeColor(u8 color);
u8 FromVer3GetMouthlineColor(u8 color);
u8 FromVer3GetGlassColor(u8 color);
u8 FromVer3GetGlassType(u8 type);

FacelineColor GetFacelineColorFromVer3(u32 color);
CommonColor GetHairColorFromVer3(u32 color);
CommonColor GetEyeColorFromVer3(u32 color);
CommonColor GetMouthColorFromVer3(u32 color);
CommonColor GetGlassColorFromVer3(u32 color);

} // namespace Service::Mii::RawData


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/mii/mii_result.h"
#include "core/hle/service/mii/mii_util.h"
#include "core/hle/service/mii/types/raw_data.h"
#include "core/hle/service/mii/types/store_data.h"

namespace Service::Mii {

void StoreData::BuildDefault(u32 mii_index) {
    const auto& default_mii = RawData::DefaultMii[mii_index];
    core_data.SetDefault();

    core_data.SetFacelineType(static_cast<FacelineType>(default_mii.face_type));
    core_data.SetFacelineColor(
        RawData::GetFacelineColorFromVer3(static_cast<u8>(default_mii.face_color)));
    core_data.SetFacelineWrinkle(static_cast<FacelineWrinkle>(default_mii.face_wrinkle));
    core_data.SetFacelineMake(static_cast<FacelineMake>(default_mii.face_makeup));

    core_data.SetHairType(static_cast<HairType>(default_mii.hair_type));
    core_data.SetHairColor(RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.hair_color)));
    core_data.SetHairFlip(static_cast<HairFlip>(default_mii.hair_flip));
    core_data.SetEyeType(static_cast<EyeType>(default_mii.eye_type));
    core_data.SetEyeColor(RawData::GetEyeColorFromVer3(static_cast<u8>(default_mii.eye_color)));
    core_data.SetEyeScale(static_cast<u8>(default_mii.eye_scale));
    core_data.SetEyeAspect(static_cast<u8>(default_mii.eye_aspect));
    core_data.SetEyeRotate(static_cast<u8>(default_mii.eye_rotate));
    core_data.SetEyeX(static_cast<u8>(default_mii.eye_x));
    core_data.SetEyeY(static_cast<u8>(default_mii.eye_y));

    core_data.SetEyebrowType(static_cast<EyebrowType>(default_mii.eyebrow_type));
    core_data.SetEyebrowColor(
        RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.eyebrow_color)));
    core_data.SetEyebrowScale(static_cast<u8>(default_mii.eyebrow_scale));
    core_data.SetEyebrowAspect(static_cast<u8>(default_mii.eyebrow_aspect));
    core_data.SetEyebrowRotate(static_cast<u8>(default_mii.eyebrow_rotate));
    core_data.SetEyebrowX(static_cast<u8>(default_mii.eyebrow_x));
    core_data.SetEyebrowY(static_cast<u8>(default_mii.eyebrow_y - 3));

    core_data.SetNoseType(static_cast<NoseType>(default_mii.nose_type));
    core_data.SetNoseScale(static_cast<u8>(default_mii.nose_scale));
    core_data.SetNoseY(static_cast<u8>(default_mii.nose_y));

    core_data.SetMouthType(static_cast<MouthType>(default_mii.mouth_type));
    core_data.SetMouthColor(
        RawData::GetMouthColorFromVer3(static_cast<u8>(default_mii.mouth_color)));
    core_data.SetMouthScale(static_cast<u8>(default_mii.mouth_scale));
    core_data.SetMouthAspect(static_cast<u8>(default_mii.mouth_aspect));
    core_data.SetMouthY(static_cast<u8>(default_mii.mouth_y));

    core_data.SetMustacheType(static_cast<MustacheType>(default_mii.mustache_type));
    core_data.SetBeardType(static_cast<BeardType>(default_mii.beard_type));
    core_data.SetBeardColor(
        RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.beard_color)));
    core_data.SetMustacheScale(static_cast<u8>(default_mii.mustache_scale));
    core_data.SetMustacheY(static_cast<u8>(default_mii.mustache_y));

    core_data.SetGlassType(static_cast<GlassType>(default_mii.glasses_type));
    core_data.SetGlassColor(
        RawData::GetGlassColorFromVer3(static_cast<u8>(default_mii.glasses_color)));
    core_data.SetGlassScale(static_cast<u8>(default_mii.glasses_scale));
    core_data.SetGlassY(static_cast<u8>(default_mii.glasses_y));

    core_data.SetMoleType(static_cast<MoleType>(default_mii.mole_type));
    core_data.SetMoleScale(static_cast<u8>(default_mii.mole_scale));
    core_data.SetMoleX(static_cast<u8>(default_mii.mole_x));
    core_data.SetMoleY(static_cast<u8>(default_mii.mole_y));

    core_data.SetHeight(static_cast<u8>(default_mii.height));
    core_data.SetBuild(static_cast<u8>(default_mii.weight));
    core_data.SetGender(static_cast<Gender>(default_mii.gender));
    core_data.SetFavoriteColor(static_cast<FavoriteColor>(default_mii.favorite_color));
    core_data.SetRegionMove(static_cast<u8>(default_mii.region_move));
    core_data.SetFontRegion(static_cast<FontRegion>(default_mii.font_region));
    core_data.SetType(static_cast<u8>(default_mii.type));
    core_data.SetNickname(default_mii.nickname);

    create_id = MiiUtil::MakeCreateId();
    SetChecksum();
}

void StoreData::BuildBase(Gender gender) {
    const auto& default_mii = RawData::BaseMii[gender == Gender::Female ? 1 : 0];
    core_data.SetDefault();

    core_data.SetFacelineType(static_cast<FacelineType>(default_mii.face_type));
    core_data.SetFacelineColor(
        RawData::GetFacelineColorFromVer3(static_cast<u8>(default_mii.face_color)));
    core_data.SetFacelineWrinkle(static_cast<FacelineWrinkle>(default_mii.face_wrinkle));
    core_data.SetFacelineMake(static_cast<FacelineMake>(default_mii.face_makeup));

    core_data.SetHairType(static_cast<HairType>(default_mii.hair_type));
    core_data.SetHairColor(RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.hair_color)));
    core_data.SetHairFlip(static_cast<HairFlip>(default_mii.hair_flip));
    core_data.SetEyeType(static_cast<EyeType>(default_mii.eye_type));
    core_data.SetEyeColor(RawData::GetEyeColorFromVer3(static_cast<u8>(default_mii.eye_color)));
    core_data.SetEyeScale(static_cast<u8>(default_mii.eye_scale));
    core_data.SetEyeAspect(static_cast<u8>(default_mii.eye_aspect));
    core_data.SetEyeRotate(static_cast<u8>(default_mii.eye_rotate));
    core_data.SetEyeX(static_cast<u8>(default_mii.eye_x));
    core_data.SetEyeY(static_cast<u8>(default_mii.eye_y));

    core_data.SetEyebrowType(static_cast<EyebrowType>(default_mii.eyebrow_type));
    core_data.SetEyebrowColor(
        RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.eyebrow_color)));
    core_data.SetEyebrowScale(static_cast<u8>(default_mii.eyebrow_scale));
    core_data.SetEyebrowAspect(static_cast<u8>(default_mii.eyebrow_aspect));
    core_data.SetEyebrowRotate(static_cast<u8>(default_mii.eyebrow_rotate));
    core_data.SetEyebrowX(static_cast<u8>(default_mii.eyebrow_x));
    core_data.SetEyebrowY(static_cast<u8>(default_mii.eyebrow_y - 3));

    core_data.SetNoseType(static_cast<NoseType>(default_mii.nose_type));
    core_data.SetNoseScale(static_cast<u8>(default_mii.nose_scale));
    core_data.SetNoseY(static_cast<u8>(default_mii.nose_y));

    core_data.SetMouthType(static_cast<MouthType>(default_mii.mouth_type));
    core_data.SetMouthColor(
        RawData::GetMouthColorFromVer3(static_cast<u8>(default_mii.mouth_color)));
    core_data.SetMouthScale(static_cast<u8>(default_mii.mouth_scale));
    core_data.SetMouthAspect(static_cast<u8>(default_mii.mouth_aspect));
    core_data.SetMouthY(static_cast<u8>(default_mii.mouth_y));

    core_data.SetMustacheType(static_cast<MustacheType>(default_mii.mustache_type));
    core_data.SetBeardType(static_cast<BeardType>(default_mii.beard_type));
    core_data.SetBeardColor(
        RawData::GetHairColorFromVer3(static_cast<u8>(default_mii.beard_color)));
    core_data.SetMustacheScale(static_cast<u8>(default_mii.mustache_scale));
    core_data.SetMustacheY(static_cast<u8>(default_mii.mustache_y));

    core_data.SetGlassType(static_cast<GlassType>(default_mii.glasses_type));
    core_data.SetGlassColor(
        RawData::GetGlassColorFromVer3(static_cast<u8>(default_mii.glasses_color)));
    core_data.SetGlassScale(static_cast<u8>(default_mii.glasses_scale));
    core_data.SetGlassY(static_cast<u8>(default_mii.glasses_y));

    core_data.SetMoleType(static_cast<MoleType>(default_mii.mole_type));
    core_data.SetMoleScale(static_cast<u8>(default_mii.mole_scale));
    core_data.SetMoleX(static_cast<u8>(default_mii.mole_x));
    core_data.SetMoleY(static_cast<u8>(default_mii.mole_y));

    core_data.SetHeight(static_cast<u8>(default_mii.height));
    core_data.SetBuild(static_cast<u8>(default_mii.weight));
    core_data.SetGender(static_cast<Gender>(default_mii.gender));
    core_data.SetFavoriteColor(static_cast<FavoriteColor>(default_mii.favorite_color));
    core_data.SetRegionMove(static_cast<u8>(default_mii.region_move));
    core_data.SetFontRegion(static_cast<FontRegion>(default_mii.font_region));
    core_data.SetType(static_cast<u8>(default_mii.type));
    core_data.SetNickname(default_mii.nickname);

    create_id = MiiUtil::MakeCreateId();
    SetChecksum();
}

void StoreData::BuildRandom(Age age, Gender gender, Race race) {
    core_data.BuildRandom(age, gender, race);
    create_id = MiiUtil::MakeCreateId();
    SetChecksum();
}

void StoreData::BuildWithCharInfo(const CharInfo& char_info) {
    core_data.BuildFromCharInfo(char_info);
    create_id = MiiUtil::MakeCreateId();
    SetChecksum();
}

void StoreData::BuildWithCoreData(const CoreData& in_core_data) {
    core_data = in_core_data;
    create_id = MiiUtil::MakeCreateId();
    SetChecksum();
}

Result StoreData::Restore() {
    // TODO: Implement this
    return ResultNotUpdated;
}

ValidationResult StoreData::IsValid() const {
    if (core_data.IsValid() != ValidationResult::NoErrors) {
        return core_data.IsValid();
    }
    if (data_crc != MiiUtil::CalculateCrc16(&core_data, sizeof(CoreData) + sizeof(Common::UUID))) {
        return ValidationResult::InvalidChecksum;
    }
    const auto device_id = MiiUtil::GetDeviceId();
    if (device_crc != MiiUtil::CalculateDeviceCrc16(device_id, sizeof(StoreData))) {
        return ValidationResult::InvalidChecksum;
    }
    return ValidationResult::NoErrors;
}

bool StoreData::IsSpecial() const {
    return GetType() == 1;
}

void StoreData::SetFontRegion(FontRegion value) {
    core_data.SetFontRegion(value);
}

void StoreData::SetFavoriteColor(FavoriteColor value) {
    core_data.SetFavoriteColor(value);
}

void StoreData::SetGender(Gender value) {
    core_data.SetGender(value);
}

void StoreData::SetHeight(u8 value) {
    core_data.SetHeight(value);
}

void StoreData::SetBuild(u8 value) {
    core_data.SetBuild(value);
}

void StoreData::SetType(u8 value) {
    core_data.SetType(value);
}

void StoreData::SetRegionMove(u8 value) {
    core_data.SetRegionMove(value);
}

void StoreData::SetFacelineType(FacelineType value) {
    core_data.SetFacelineType(value);
}

void StoreData::SetFacelineColor(FacelineColor value) {
    core_data.SetFacelineColor(value);
}

void StoreData::SetFacelineWrinkle(FacelineWrinkle value) {
    core_data.SetFacelineWrinkle(value);
}

void StoreData::SetFacelineMake(FacelineMake value) {
    core_data.SetFacelineMake(value);
}

void StoreData::SetHairType(HairType value) {
    core_data.SetHairType(value);
}

void StoreData::SetHairColor(CommonColor value) {
    core_data.SetHairColor(value);
}

void StoreData::SetHairFlip(HairFlip value) {
    core_data.SetHairFlip(value);
}

void StoreData::SetEyeType(EyeType value) {
    core_data.SetEyeType(value);
}

void StoreData::SetEyeColor(CommonColor value) {
    core_data.SetEyeColor(value);
}

void StoreData::SetEyeScale(u8 value) {
    core_data.SetEyeScale(value);
}

void StoreData::SetEyeAspect(u8 value) {
    core_data.SetEyeAspect(value);
}

void StoreData::SetEyeRotate(u8 value) {
    core_data.SetEyeRotate(value);
}

void StoreData::SetEyeX(u8 value) {
    core_data.SetEyeX(value);
}

void StoreData::SetEyeY(u8 value) {
    core_data.SetEyeY(value);
}

void StoreData::SetEyebrowType(EyebrowType value) {
    core_data.SetEyebrowType(value);
}

void StoreData::SetEyebrowColor(CommonColor value) {
    core_data.SetEyebrowColor(value);
}

void StoreData::SetEyebrowScale(u8 value) {
    core_data.SetEyebrowScale(value);
}

void StoreData::SetEyebrowAspect(u8 value) {
    core_data.SetEyebrowAspect(value);
}

void StoreData::SetEyebrowRotate(u8 value) {
    core_data.SetEyebrowRotate(value);
}

void StoreData::SetEyebrowX(u8 value) {
    core_data.SetEyebrowX(value);
}

void StoreData::SetEyebrowY(u8 value) {
    core_data.SetEyebrowY(value);
}

void StoreData::SetNoseType(NoseType value) {
    core_data.SetNoseType(value);
}

void StoreData::SetNoseScale(u8 value) {
    core_data.SetNoseScale(value);
}

void StoreData::SetNoseY(u8 value) {
    core_data.SetNoseY(value);
}

void StoreData::SetMouthType(MouthType value) {
    core_data.SetMouthType(value);
}

void StoreData::SetMouthColor(CommonColor value) {
    core_data.SetMouthColor(value);
}

void StoreData::SetMouthScale(u8 value) {
    core_data.SetMouthScale(value);
}

void StoreData::SetMouthAspect(u8 value) {
    core_data.SetMouthAspect(value);
}

void StoreData::SetMouthY(u8 value) {
    core_data.SetMouthY(value);
}

void StoreData::SetBeardColor(CommonColor value) {
    core_data.SetBeardColor(value);
}

void StoreData::SetBeardType(BeardType value) {
    core_data.SetBeardType(value);
}

void StoreData::SetMustacheType(MustacheType value) {
    core_data.SetMustacheType(value);
}

void StoreData::SetMustacheScale(u8 value) {
    core_data.SetMustacheScale(value);
}

void StoreData::SetMustacheY(u8 value) {
    core_data.SetMustacheY(value);
}

void StoreData::SetGlassType(GlassType value) {
    core_data.SetGlassType(value);
}

void StoreData::SetGlassColor(CommonColor value) {
    core_data.SetGlassColor(value);
}

void StoreData::SetGlassScale(u8 value) {
    core_data.SetGlassScale(value);
}

void StoreData::SetGlassY(u8 value) {
    core_data.SetGlassY(value);
}

void StoreData::SetMoleType(MoleType value) {
    core_data.SetMoleType(value);
}

void StoreData::SetMoleScale(u8 value) {
    core_data.SetMoleScale(value);
}

void StoreData::SetMoleX(u8 value) {
    core_data.SetMoleX(value);
}

void StoreData::SetMoleY(u8 value) {
    core_data.SetMoleY(value);
}

void StoreData::SetNickname(Nickname value) {
    core_data.SetNickname(value);
}

void StoreData::SetInvalidName() {
    const auto& invalid_name = core_data.GetInvalidNickname();
    core_data.SetNickname(invalid_name);
    SetChecksum();
}

void StoreData::SetChecksum() {
    SetDataChecksum();
    SetDeviceChecksum();
}

void StoreData::SetDataChecksum() {
    data_crc = MiiUtil::CalculateCrc16(&core_data, sizeof(CoreData) + sizeof(Common::UUID));
}

void StoreData::SetDeviceChecksum() {
    const auto device_id = MiiUtil::GetDeviceId();
    device_crc = MiiUtil::CalculateDeviceCrc16(device_id, sizeof(StoreData));
}

Common::UUID StoreData::GetCreateId() const {
    return create_id;
}

FontRegion StoreData::GetFontRegion() const {
    return static_cast<FontRegion>(core_data.GetFontRegion());
}

FavoriteColor StoreData::GetFavoriteColor() const {
    return core_data.GetFavoriteColor();
}

Gender StoreData::GetGender() const {
    return core_data.GetGender();
}

u8 StoreData::GetHeight() const {
    return core_data.GetHeight();
}

u8 StoreData::GetBuild() const {
    return core_data.GetBuild();
}

u8 StoreData::GetType() const {
    return core_data.GetType();
}

u8 StoreData::GetRegionMove() const {
    return core_data.GetRegionMove();
}

FacelineType StoreData::GetFacelineType() const {
    return core_data.GetFacelineType();
}

FacelineColor StoreData::GetFacelineColor() const {
    return core_data.GetFacelineColor();
}

FacelineWrinkle StoreData::GetFacelineWrinkle() const {
    return core_data.GetFacelineWrinkle();
}

FacelineMake StoreData::GetFacelineMake() const {
    return core_data.GetFacelineMake();
}

HairType StoreData::GetHairType() const {
    return core_data.GetHairType();
}

CommonColor StoreData::GetHairColor() const {
    return core_data.GetHairColor();
}

HairFlip StoreData::GetHairFlip() const {
    return core_data.GetHairFlip();
}

EyeType StoreData::GetEyeType() const {
    return core_data.GetEyeType();
}

CommonColor StoreData::GetEyeColor() const {
    return core_data.GetEyeColor();
}

u8 StoreData::GetEyeScale() const {
    return core_data.GetEyeScale();
}

u8 StoreData::GetEyeAspect() const {
    return core_data.GetEyeAspect();
}

u8 StoreData::GetEyeRotate() const {
    return core_data.GetEyeRotate();
}

u8 StoreData::GetEyeX() const {
    return core_data.GetEyeX();
}

u8 StoreData::GetEyeY() const {
    return core_data.GetEyeY();
}

EyebrowType StoreData::GetEyebrowType() const {
    return core_data.GetEyebrowType();
}

CommonColor StoreData::GetEyebrowColor() const {
    return core_data.GetEyebrowColor();
}

u8 StoreData::GetEyebrowScale() const {
    return core_data.GetEyebrowScale();
}

u8 StoreData::GetEyebrowAspect() const {
    return core_data.GetEyebrowAspect();
}

u8 StoreData::GetEyebrowRotate() const {
    return core_data.GetEyebrowRotate();
}

u8 StoreData::GetEyebrowX() const {
    return core_data.GetEyebrowX();
}

u8 StoreData::GetEyebrowY() const {
    return core_data.GetEyebrowY();
}

NoseType StoreData::GetNoseType() const {
    return core_data.GetNoseType();
}

u8 StoreData::GetNoseScale() const {
    return core_data.GetNoseScale();
}

u8 StoreData::GetNoseY() const {
    return core_data.GetNoseY();
}

MouthType StoreData::GetMouthType() const {
    return core_data.GetMouthType();
}

CommonColor StoreData::GetMouthColor() const {
    return core_data.GetMouthColor();
}

u8 StoreData::GetMouthScale() const {
    return core_data.GetMouthScale();
}

u8 StoreData::GetMouthAspect() const {
    return core_data.GetMouthAspect();
}

u8 StoreData::GetMouthY() const {
    return core_data.GetMouthY();
}

CommonColor StoreData::GetBeardColor() const {
    return core_data.GetBeardColor();
}

BeardType StoreData::GetBeardType() const {
    return core_data.GetBeardType();
}

MustacheType StoreData::GetMustacheType() const {
    return core_data.GetMustacheType();
}

u8 StoreData::GetMustacheScale() const {
    return core_data.GetMustacheScale();
}

u8 StoreData::GetMustacheY() const {
    return core_data.GetMustacheY();
}

GlassType StoreData::GetGlassType() const {
    return core_data.GetGlassType();
}

CommonColor StoreData::GetGlassColor() const {
    return core_data.GetGlassColor();
}

u8 StoreData::GetGlassScale() const {
    return core_data.GetGlassScale();
}

u8 StoreData::GetGlassY() const {
    return core_data.GetGlassY();
}

MoleType StoreData::GetMoleType() const {
    return core_data.GetMoleType();
}

u8 StoreData::GetMoleScale() const {
    return core_data.GetMoleScale();
}

u8 StoreData::GetMoleX() const {
    return core_data.GetMoleX();
}

u8 StoreData::GetMoleY() const {
    return core_data.GetMoleY();
}

Nickname StoreData::GetNickname() const {
    return core_data.GetNickname();
}

bool StoreData::operator==(const StoreData& data) {
    bool is_identical = data.core_data.IsValid() == ValidationResult::NoErrors;
    is_identical &= core_data.GetNickname().data == data.core_data.GetNickname().data;
    is_identical &= GetCreateId() == data.GetCreateId();
    is_identical &= GetFontRegion() == data.GetFontRegion();
    is_identical &= GetFavoriteColor() == data.GetFavoriteColor();
    is_identical &= GetGender() == data.GetGender();
    is_identical &= GetHeight() == data.GetHeight();
    is_identical &= GetBuild() == data.GetBuild();
    is_identical &= GetType() == data.GetType();
    is_identical &= GetRegionMove() == data.GetRegionMove();
    is_identical &= GetFacelineType() == data.GetFacelineType();
    is_identical &= GetFacelineColor() == data.GetFacelineColor();
    is_identical &= GetFacelineWrinkle() == data.GetFacelineWrinkle();
    is_identical &= GetFacelineMake() == data.GetFacelineMake();
    is_identical &= GetHairType() == data.GetHairType();
    is_identical &= GetHairColor() == data.GetHairColor();
    is_identical &= GetHairFlip() == data.GetHairFlip();
    is_identical &= GetEyeType() == data.GetEyeType();
    is_identical &= GetEyeColor() == data.GetEyeColor();
    is_identical &= GetEyeScale() == data.GetEyeScale();
    is_identical &= GetEyeAspect() == data.GetEyeAspect();
    is_identical &= GetEyeRotate() == data.GetEyeRotate();
    is_identical &= GetEyeX() == data.GetEyeX();
    is_identical &= GetEyeY() == data.GetEyeY();
    is_identical &= GetEyebrowType() == data.GetEyebrowType();
    is_identical &= GetEyebrowColor() == data.GetEyebrowColor();
    is_identical &= GetEyebrowScale() == data.GetEyebrowScale();
    is_identical &= GetEyebrowAspect() == data.GetEyebrowAspect();
    is_identical &= GetEyebrowRotate() == data.GetEyebrowRotate();
    is_identical &= GetEyebrowX() == data.GetEyebrowX();
    is_identical &= GetEyebrowY() == data.GetEyebrowY();
    is_identical &= GetNoseType() == data.GetNoseType();
    is_identical &= GetNoseScale() == data.GetNoseScale();
    is_identical &= GetNoseY() == data.GetNoseY();
    is_identical &= GetMouthType() == data.GetMouthType();
    is_identical &= GetMouthColor() == data.GetMouthColor();
    is_identical &= GetMouthScale() == data.GetMouthScale();
    is_identical &= GetMouthAspect() == data.GetMouthAspect();
    is_identical &= GetMouthY() == data.GetMouthY();
    is_identical &= GetBeardColor() == data.GetBeardColor();
    is_identical &= GetBeardType() == data.GetBeardType();
    is_identical &= GetMustacheType() == data.GetMustacheType();
    is_identical &= GetMustacheScale() == data.GetMustacheScale();
    is_identical &= GetMustacheY() == data.GetMustacheY();
    is_identical &= GetGlassType() == data.GetGlassType();
    is_identical &= GetGlassColor() == data.GetGlassColor();
    is_identical &= GetGlassScale() == data.GetGlassScale();
    is_identical &= GetGlassY() == data.GetGlassY();
    is_identical &= GetMoleType() == data.GetMoleType();
    is_identical &= GetMoleScale() == data.GetMoleScale();
    is_identical &= GetMoleX() == data.GetMoleX();
    is_identical &= data.GetMoleY() == data.GetMoleY();
    return is_identical;
}

} // namespace Service::Mii


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/result.h"
#include "core/hle/service/mii/mii_types.h"
#include "core/hle/service/mii/types/core_data.h"

namespace Service::Mii {

class StoreData {
public:
    void BuildDefault(u32 mii_index);
    void BuildBase(Gender gender);
    void BuildRandom(Age age, Gender gender, Race race);
    void BuildWithCharInfo(const CharInfo& char_info);
    void BuildWithCoreData(const CoreData& in_core_data);
    Result Restore();

    ValidationResult IsValid() const;

    bool IsSpecial() const;

    void SetFontRegion(FontRegion value);
    void SetFavoriteColor(FavoriteColor value);
    void SetGender(Gender value);
    void SetHeight(u8 value);
    void SetBuild(u8 value);
    void SetType(u8 value);
    void SetRegionMove(u8 value);
    void SetFacelineType(FacelineType value);
    void SetFacelineColor(FacelineColor value);
    void SetFacelineWrinkle(FacelineWrinkle value);
    void SetFacelineMake(FacelineMake value);
    void SetHairType(HairType value);
    void SetHairColor(CommonColor value);
    void SetHairFlip(HairFlip value);
    void SetEyeType(EyeType value);
    void SetEyeColor(CommonColor value);
    void SetEyeScale(u8 value);
    void SetEyeAspect(u8 value);
    void SetEyeRotate(u8 value);
    void SetEyeX(u8 value);
    void SetEyeY(u8 value);
    void SetEyebrowType(EyebrowType value);
    void SetEyebrowColor(CommonColor value);
    void SetEyebrowScale(u8 value);
    void SetEyebrowAspect(u8 value);
    void SetEyebrowRotate(u8 value);
    void SetEyebrowX(u8 value);
    void SetEyebrowY(u8 value);
    void SetNoseType(NoseType value);
    void SetNoseScale(u8 value);
    void SetNoseY(u8 value);
    void SetMouthType(MouthType value);
    void SetMouthColor(CommonColor value);
    void SetMouthScale(u8 value);
    void SetMouthAspect(u8 value);
    void SetMouthY(u8 value);
    void SetBeardColor(CommonColor value);
    void SetBeardType(BeardType value);
    void SetMustacheType(MustacheType value);
    void SetMustacheScale(u8 value);
    void SetMustacheY(u8 value);
    void SetGlassType(GlassType value);
    void SetGlassColor(CommonColor value);
    void SetGlassScale(u8 value);
    void SetGlassY(u8 value);
    void SetMoleType(MoleType value);
    void SetMoleScale(u8 value);
    void SetMoleX(u8 value);
    void SetMoleY(u8 value);
    void SetNickname(Nickname nickname);
    void SetInvalidName();
    void SetChecksum();
    void SetDataChecksum();
    void SetDeviceChecksum();

    Common::UUID GetCreateId() const;
    FontRegion GetFontRegion() const;
    FavoriteColor GetFavoriteColor() const;
    Gender GetGender() const;
    u8 GetHeight() const;
    u8 GetBuild() const;
    u8 GetType() const;
    u8 GetRegionMove() const;
    FacelineType GetFacelineType() const;
    FacelineColor GetFacelineColor() const;
    FacelineWrinkle GetFacelineWrinkle() const;
    FacelineMake GetFacelineMake() const;
    HairType GetHairType() const;
    CommonColor GetHairColor() const;
    HairFlip GetHairFlip() const;
    EyeType GetEyeType() const;
    CommonColor GetEyeColor() const;
    u8 GetEyeScale() const;
    u8 GetEyeAspect() const;
    u8 GetEyeRotate() const;
    u8 GetEyeX() const;
    u8 GetEyeY() const;
    EyebrowType GetEyebrowType() const;
    CommonColor GetEyebrowColor() const;
    u8 GetEyebrowScale() const;
    u8 GetEyebrowAspect() const;
    u8 GetEyebrowRotate() const;
    u8 GetEyebrowX() const;
    u8 GetEyebrowY() const;
    NoseType GetNoseType() const;
    u8 GetNoseScale() const;
    u8 GetNoseY() const;
    MouthType GetMouthType() const;
    CommonColor GetMouthColor() const;
    u8 GetMouthScale() const;
    u8 GetMouthAspect() const;
    u8 GetMouthY() const;
    CommonColor GetBeardColor() const;
    BeardType GetBeardType() const;
    MustacheType GetMustacheType() const;
    u8 GetMustacheScale() const;
    u8 GetMustacheY() const;
    GlassType GetGlassType() const;
    CommonColor GetGlassColor() const;
    u8 GetGlassScale() const;
    u8 GetGlassY() const;
    MoleType GetMoleType() const;
    u8 GetMoleScale() const;
    u8 GetMoleX() const;
    u8 GetMoleY() const;
    Nickname GetNickname() const;

    bool operator==(const StoreData& data);

private:
    CoreData core_data{};
    Common::UUID create_id{};
    u16 data_crc{};
    u16 device_crc{};
};
static_assert(sizeof(StoreData) == 0x44, "StoreData has incorrect size.");
static_assert(std::is_trivially_copyable_v<StoreData>,
              "StoreData type must be trivially copyable.");

struct StoreDataElement {
    StoreData store_data{};
    Source source{};
};
static_assert(sizeof(StoreDataElement) == 0x48, "StoreDataElement has incorrect size.");

}; // namespace Service::Mii


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/mii/mii_util.h"
#include "core/hle/service/mii/types/raw_data.h"
#include "core/hle/service/mii/types/store_data.h"
#include "core/hle/service/mii/types/ver3_store_data.h"

namespace Service::Mii {

void NfpStoreDataExtension::SetFromStoreData(const StoreData& store_data) {
    faceline_color = static_cast<u8>(store_data.GetFacelineColor()) & 0xf;
    hair_color = static_cast<u8>(store_data.GetHairColor()) & 0x7f;
    eye_color = static_cast<u8>(store_data.GetEyeColor()) & 0x7f;
    eyebrow_color = static_cast<u8>(store_data.GetEyebrowColor()) & 0x7f;
    mouth_color = static_cast<u8>(store_data.GetMouthColor()) & 0x7f;
    beard_color = static_cast<u8>(store_data.GetBeardColor()) & 0x7f;
    glass_color = static_cast<u8>(store_data.GetGlassColor()) & 0x7f;
    glass_type = static_cast<u8>(store_data.GetGlassType()) & 0x1f;
}

void Ver3StoreData::BuildToStoreData(StoreData& out_store_data) const {
    out_store_data.BuildBase(Gender::Male);

    out_store_data.SetGender(static_cast<Gender>(mii_information.gender.Value()));
    out_store_data.SetFavoriteColor(
        static_cast<FavoriteColor>(mii_information.favorite_color.Value()));
    out_store_data.SetHeight(height);
    out_store_data.SetBuild(build);

    out_store_data.SetNickname(mii_name);
    out_store_data.SetFontRegion(
        static_cast<FontRegion>(static_cast<u8>(region_information.font_region.Value())));

    out_store_data.SetFacelineType(
        static_cast<FacelineType>(appearance_bits1.faceline_type.Value()));
    out_store_data.SetFacelineColor(
        RawData::GetFacelineColorFromVer3(appearance_bits1.faceline_color.Value()));
    out_store_data.SetFacelineWrinkle(
        static_cast<FacelineWrinkle>(appearance_bits2.faceline_wrinkle.Value()));
    out_store_data.SetFacelineMake(
        static_cast<FacelineMake>(appearance_bits2.faceline_make.Value()));

    out_store_data.SetHairType(static_cast<HairType>(hair_type));
    out_store_data.SetHairColor(RawData::GetHairColorFromVer3(appearance_bits3.hair_color.Value()));
    out_store_data.SetHairFlip(static_cast<HairFlip>(appearance_bits3.hair_flip.Value()));

    out_store_data.SetEyeType(static_cast<EyeType>(appearance_bits4.eye_type.Value()));
    out_store_data.SetEyeColor(RawData::GetEyeColorFromVer3(appearance_bits4.eye_color.Value()));
    out_store_data.SetEyeScale(static_cast<u8>(appearance_bits4.eye_scale.Value()));
    out_store_data.SetEyeAspect(static_cast<u8>(appearance_bits4.eye_aspect.Value()));
    out_store_data.SetEyeRotate(static_cast<u8>(appearance_bits4.eye_rotate.Value()));
    out_store_data.SetEyeX(static_cast<u8>(appearance_bits4.eye_x.Value()));
    out_store_data.SetEyeY(static_cast<u8>(appearance_bits4.eye_y.Value()));

    out_store_data.SetEyebrowType(static_cast<EyebrowType>(appearance_bits5.eyebrow_type.Value()));
    out_store_data.SetEyebrowColor(
        RawData::GetHairColorFromVer3(appearance_bits5.eyebrow_color.Value()));
    out_store_data.SetEyebrowScale(static_cast<u8>(appearance_bits5.eyebrow_scale.Value()));
    out_store_data.SetEyebrowAspect(static_cast<u8>(appearance_bits5.eyebrow_aspect.Value()));
    out_store_data.SetEyebrowRotate(static_cast<u8>(appearance_bits5.eyebrow_rotate.Value()));
    out_store_data.SetEyebrowX(static_cast<u8>(appearance_bits5.eyebrow_x.Value()));
    out_store_data.SetEyebrowY(static_cast<u8>(appearance_bits5.eyebrow_y.Value() - 3));

    out_store_data.SetNoseType(static_cast<NoseType>(appearance_bits6.nose_type.Value()));
    out_store_data.SetNoseScale(static_cast<u8>(appearance_bits6.nose_scale.Value()));
    out_store_data.SetNoseY(static_cast<u8>(appearance_bits6.nose_y.Value()));

    out_store_data.SetMouthType(static_cast<MouthType>(appearance_bits7.mouth_type.Value()));
    out_store_data.SetMouthColor(
        RawData::GetMouthColorFromVer3(appearance_bits7.mouth_color.Value()));
    out_store_data.SetMouthScale(static_cast<u8>(appearance_bits7.mouth_scale.Value()));
    out_store_data.SetMouthAspect(static_cast<u8>(appearance_bits7.mouth_aspect.Value()));
    out_store_data.SetMouthY(static_cast<u8>(appearance_bits8.mouth_y.Value()));

    out_store_data.SetMustacheType(
        static_cast<MustacheType>(appearance_bits8.mustache_type.Value()));
    out_store_data.SetMustacheScale(static_cast<u8>(appearance_bits9.mustache_scale.Value()));
    out_store_data.SetMustacheY(static_cast<u8>(appearance_bits9.mustache_y.Value()));

    out_store_data.SetBeardType(static_cast<BeardType>(appearance_bits9.beard_type.Value()));
    out_store_data.SetBeardColor(
        RawData::GetHairColorFromVer3(appearance_bits9.beard_color.Value()));

    // Glass type is compatible as it is. It doesn't need a table
    out_store_data.SetGlassType(static_cast<GlassType>(appearance_bits10.glass_type.Value()));
    out_store_data.SetGlassColor(
        RawData::GetGlassColorFromVer3(appearance_bits10.glass_color.Value()));
    out_store_data.SetGlassScale(static_cast<u8>(appearance_bits10.glass_scale.Value()));
    out_store_data.SetGlassY(static_cast<u8>(appearance_bits10.glass_y.Value()));

    out_store_data.SetMoleType(static_cast<MoleType>(appearance_bits11.mole_type.Value()));
    out_store_data.SetMoleScale(static_cast<u8>(appearance_bits11.mole_scale.Value()));
    out_store_data.SetMoleX(static_cast<u8>(appearance_bits11.mole_x.Value()));
    out_store_data.SetMoleY(static_cast<u8>(appearance_bits11.mole_y.Value()));

    out_store_data.SetChecksum();
}

void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) {
    version = 3;
    mii_information.gender.Assign(static_cast<u8>(store_data.GetGender()));
    mii_information.favorite_color.Assign(static_cast<u8>(store_data.GetFavoriteColor()));
    height = store_data.GetHeight();
    build = store_data.GetBuild();

    mii_name = store_data.GetNickname();
    region_information.font_region.Assign(static_cast<u8>(store_data.GetFontRegion()));

    appearance_bits1.faceline_type.Assign(static_cast<u8>(store_data.GetFacelineType()));
    appearance_bits2.faceline_wrinkle.Assign(static_cast<u8>(store_data.GetFacelineWrinkle()));
    appearance_bits2.faceline_make.Assign(static_cast<u8>(store_data.GetFacelineMake()));

    hair_type = static_cast<u8>(store_data.GetHairType());
    appearance_bits3.hair_flip.Assign(static_cast<u8>(store_data.GetHairFlip()));

    appearance_bits4.eye_type.Assign(static_cast<u8>(store_data.GetEyeType()));
    appearance_bits4.eye_scale.Assign(store_data.GetEyeScale());
    appearance_bits4.eye_aspect.Assign(store_data.GetEyebrowAspect());
    appearance_bits4.eye_rotate.Assign(store_data.GetEyeRotate());
    appearance_bits4.eye_x.Assign(store_data.GetEyeX());
    appearance_bits4.eye_y.Assign(store_data.GetEyeY());

    appearance_bits5.eyebrow_type.Assign(static_cast<u8>(store_data.GetEyebrowType()));
    appearance_bits5.eyebrow_scale.Assign(store_data.GetEyebrowScale());
    appearance_bits5.eyebrow_aspect.Assign(store_data.GetEyebrowAspect());
    appearance_bits5.eyebrow_rotate.Assign(store_data.GetEyebrowRotate());
    appearance_bits5.eyebrow_x.Assign(store_data.GetEyebrowX());
    appearance_bits5.eyebrow_y.Assign(store_data.GetEyebrowY());

    appearance_bits6.nose_type.Assign(static_cast<u8>(store_data.GetNoseType()));
    appearance_bits6.nose_scale.Assign(store_data.GetNoseScale());
    appearance_bits6.nose_y.Assign(store_data.GetNoseY());

    appearance_bits7.mouth_type.Assign(static_cast<u8>(store_data.GetMouthType()));
    appearance_bits7.mouth_scale.Assign(store_data.GetMouthScale());
    appearance_bits7.mouth_aspect.Assign(store_data.GetMouthAspect());
    appearance_bits8.mouth_y.Assign(store_data.GetMouthY());

    appearance_bits8.mustache_type.Assign(static_cast<u8>(store_data.GetMustacheType()));
    appearance_bits9.mustache_scale.Assign(store_data.GetMustacheScale());
    appearance_bits9.mustache_y.Assign(store_data.GetMustacheY());

    appearance_bits9.beard_type.Assign(static_cast<u8>(store_data.GetBeardType()));

    appearance_bits10.glass_scale.Assign(store_data.GetGlassScale());
    appearance_bits10.glass_y.Assign(store_data.GetGlassY());

    appearance_bits11.mole_type.Assign(static_cast<u8>(store_data.GetMoleType()));
    appearance_bits11.mole_scale.Assign(store_data.GetMoleScale());
    appearance_bits11.mole_x.Assign(store_data.GetMoleX());
    appearance_bits11.mole_y.Assign(store_data.GetMoleY());

    // These types are converted to V3 from a table
    appearance_bits1.faceline_color.Assign(
        RawData::FromVer3GetFacelineColor(static_cast<u8>(store_data.GetFacelineColor())));
    appearance_bits3.hair_color.Assign(
        RawData::FromVer3GetHairColor(static_cast<u8>(store_data.GetHairColor())));
    appearance_bits4.eye_color.Assign(
        RawData::FromVer3GetEyeColor(static_cast<u8>(store_data.GetEyeColor())));
    appearance_bits5.eyebrow_color.Assign(
        RawData::FromVer3GetHairColor(static_cast<u8>(store_data.GetEyebrowColor())));
    appearance_bits7.mouth_color.Assign(
        RawData::FromVer3GetMouthlineColor(static_cast<u8>(store_data.GetMouthColor())));
    appearance_bits9.beard_color.Assign(
        RawData::FromVer3GetHairColor(static_cast<u8>(store_data.GetBeardColor())));
    appearance_bits10.glass_color.Assign(
        RawData::FromVer3GetGlassColor(static_cast<u8>(store_data.GetGlassColor())));
    appearance_bits10.glass_type.Assign(
        RawData::FromVer3GetGlassType(static_cast<u8>(store_data.GetGlassType())));

    crc = MiiUtil::CalculateCrc16(&version, sizeof(Ver3StoreData) - sizeof(u16));
}

u32 Ver3StoreData::IsValid() const {
    bool is_valid = version == 0 || version == 3;

    is_valid = is_valid && (mii_name.data[0] != '\0');

    is_valid = is_valid && (mii_information.birth_month < 13);
    is_valid = is_valid && (mii_information.birth_day < 32);
    is_valid = is_valid && (mii_information.favorite_color <= static_cast<u8>(FavoriteColor::Max));
    is_valid = is_valid && (height <= MaxHeight);
    is_valid = is_valid && (build <= MaxBuild);

    is_valid = is_valid && (appearance_bits1.faceline_type <= static_cast<u8>(FacelineType::Max));
    is_valid = is_valid && (appearance_bits1.faceline_color <= MaxVer3CommonColor - 2);
    is_valid =
        is_valid && (appearance_bits2.faceline_wrinkle <= static_cast<u8>(FacelineWrinkle::Max));
    is_valid = is_valid && (appearance_bits2.faceline_make <= static_cast<u8>(FacelineMake::Max));

    is_valid = is_valid && (hair_type <= static_cast<u8>(HairType::Max));
    is_valid = is_valid && (appearance_bits3.hair_color <= MaxVer3CommonColor);

    is_valid = is_valid && (appearance_bits4.eye_type <= static_cast<u8>(EyeType::Max));
    is_valid = is_valid && (appearance_bits4.eye_color <= MaxVer3CommonColor - 2);
    is_valid = is_valid && (appearance_bits4.eye_scale <= MaxEyeScale);
    is_valid = is_valid && (appearance_bits4.eye_aspect <= MaxEyeAspect);
    is_valid = is_valid && (appearance_bits4.eye_rotate <= MaxEyeRotate);
    is_valid = is_valid && (appearance_bits4.eye_x <= MaxEyeX);
    is_valid = is_valid && (appearance_bits4.eye_y <= MaxEyeY);

    is_valid = is_valid && (appearance_bits5.eyebrow_type <= static_cast<u8>(EyebrowType::Max));
    is_valid = is_valid && (appearance_bits5.eyebrow_color <= MaxVer3CommonColor);
    is_valid = is_valid && (appearance_bits5.eyebrow_scale <= MaxEyebrowScale);
    is_valid = is_valid && (appearance_bits5.eyebrow_aspect <= MaxEyebrowAspect);
    is_valid = is_valid && (appearance_bits5.eyebrow_rotate <= MaxEyebrowRotate);
    is_valid = is_valid && (appearance_bits5.eyebrow_x <= MaxEyebrowX);
    is_valid = is_valid && (appearance_bits5.eyebrow_y <= MaxEyebrowY);

    is_valid = is_valid && (appearance_bits6.nose_type <= static_cast<u8>(NoseType::Max));
    is_valid = is_valid && (appearance_bits6.nose_scale <= MaxNoseScale);
    is_valid = is_valid && (appearance_bits6.nose_y <= MaxNoseY);

    is_valid = is_valid && (appearance_bits7.mouth_type <= static_cast<u8>(MouthType::Max));
    is_valid = is_valid && (appearance_bits7.mouth_color <= MaxVer3CommonColor - 3);
    is_valid = is_valid && (appearance_bits7.mouth_scale <= MaxMouthScale);
    is_valid = is_valid && (appearance_bits7.mouth_aspect <= MaxMoutAspect);
    is_valid = is_valid && (appearance_bits8.mouth_y <= MaxMouthY);

    is_valid = is_valid && (appearance_bits8.mustache_type <= static_cast<u8>(MustacheType::Max));
    is_valid = is_valid && (appearance_bits9.mustache_scale < MaxMustacheScale);
    is_valid = is_valid && (appearance_bits9.mustache_y <= MaxMustacheY);

    is_valid = is_valid && (appearance_bits9.beard_type <= static_cast<u8>(BeardType::Max));
    is_valid = is_valid && (appearance_bits9.beard_color <= MaxVer3CommonColor);

    is_valid = is_valid && (appearance_bits10.glass_type <= MaxVer3GlassType);
    is_valid = is_valid && (appearance_bits10.glass_color <= MaxVer3CommonColor - 2);
    is_valid = is_valid && (appearance_bits10.glass_scale <= MaxGlassScale);
    is_valid = is_valid && (appearance_bits10.glass_y <= MaxGlassY);

    is_valid = is_valid && (appearance_bits11.mole_type <= static_cast<u8>(MoleType::Max));
    is_valid = is_valid && (appearance_bits11.mole_scale <= MaxMoleScale);
    is_valid = is_valid && (appearance_bits11.mole_x <= MaxMoleX);
    is_valid = is_valid && (appearance_bits11.mole_y <= MaxMoleY);

    return is_valid;
}

} // namespace Service::Mii


code:
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/mii/mii_types.h"

namespace Service::Mii {
class StoreData;

// This is nn::mii::Ver3StoreData
// Based on citra HLE::Applets::MiiData and PretendoNetwork.
// https://github.com/citra-emu/citra/blob/master/src/core/hle/applets/mii_selector.h#L48
// https://github.com/PretendoNetwork/mii-js/blob/master/mii.js#L299

struct NfpStoreDataExtension {
    void SetFromStoreData(const StoreData& store_data);

    u8 faceline_color;
    u8 hair_color;
    u8 eye_color;
    u8 eyebrow_color;
    u8 mouth_color;
    u8 beard_color;
    u8 glass_color;
    u8 glass_type;
};
static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size");

#pragma pack(push, 4)
class Ver3StoreData {
public:
    void BuildToStoreData(StoreData& out_store_data) const;
    void BuildFromStoreData(const StoreData& store_data);

    u32 IsValid() const;

    u8 version;
    union {
        u8 raw;

        BitField<0, 1, u8> allow_copying;
        BitField<1, 1, u8> profanity_flag;
        BitField<2, 2, u8> region_lock;
        BitField<4, 2, u8> font_region;
    } region_information;
    u16_be mii_id;
    u64_be system_id;
    u32_be specialness_and_creation_date;
    std::array<u8, 6> creator_mac;
    u16_be padding;
    union {
        u16 raw;

        BitField<0, 1, u16> gender;
        BitField<1, 4, u16> birth_month;
        BitField<5, 5, u16> birth_day;
        BitField<10, 4, u16> favorite_color;
        BitField<14, 1, u16> favorite;
    } mii_information;
    Nickname mii_name;
    u8 height;
    u8 build;
    union {
        u8 raw;

        BitField<0, 1, u8> disable_sharing;
        BitField<1, 4, u8> faceline_type;
        BitField<5, 3, u8> faceline_color;
    } appearance_bits1;
    union {
        u8 raw;

        BitField<0, 4, u8> faceline_wrinkle;
        BitField<4, 4, u8> faceline_make;
    } appearance_bits2;
    u8 hair_type;
    union {
        u8 raw;

        BitField<0, 3, u8> hair_color;
        BitField<3, 1, u8> hair_flip;
    } appearance_bits3;
    union {
        u32 raw;

        BitField<0, 6, u32> eye_type;
        BitField<6, 3, u32> eye_color;
        BitField<9, 4, u32> eye_scale;
        BitField<13, 3, u32> eye_aspect;
        BitField<16, 5, u32> eye_rotate;
        BitField<21, 4, u32> eye_x;
        BitField<25, 5, u32> eye_y;
    } appearance_bits4;
    union {
        u32 raw;

        BitField<0, 5, u32> eyebrow_type;
        BitField<5, 3, u32> eyebrow_color;
        BitField<8, 4, u32> eyebrow_scale;
        BitField<12, 3, u32> eyebrow_aspect;
        BitField<16, 4, u32> eyebrow_rotate;
        BitField<21, 4, u32> eyebrow_x;
        BitField<25, 5, u32> eyebrow_y;
    } appearance_bits5;
    union {
        u16 raw;

        BitField<0, 5, u16> nose_type;
        BitField<5, 4, u16> nose_scale;
        BitField<9, 5, u16> nose_y;
    } appearance_bits6;
    union {
        u16 raw;

        BitField<0, 6, u16> mouth_type;
        BitField<6, 3, u16> mouth_color;
        BitField<9, 4, u16> mouth_scale;
        BitField<13, 3, u16> mouth_aspect;
    } appearance_bits7;
    union {
        u8 raw;

        BitField<0, 5, u8> mouth_y;
        BitField<5, 3, u8> mustache_type;
    } appearance_bits8;
    u8 allow_copying;
    union {
        u16 raw;

        BitField<0, 3, u16> beard_type;
        BitField<3, 3, u16> beard_color;
        BitField<6, 4, u16> mustache_scale;
        BitField<10, 5, u16> mustache_y;
    } appearance_bits9;
    union {
        u16 raw;

        BitField<0, 4, u16> glass_type;
        BitField<4, 3, u16> glass_color;
        BitField<7, 4, u16> glass_scale;
        BitField<11, 5, u16> glass_y;
    } appearance_bits10;
    union {
        u16 raw;

        BitField<0, 1, u16> mole_type;
        BitField<1, 4, u16> mole_scale;
        BitField<5, 5, u16> mole_x;
        BitField<10, 5, u16> mole_y;
    } appearance_bits11;

    Nickname author_name;
    INSERT_PADDING_BYTES(0x2);
    u16_be crc;
};
static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size");
#pragma pack(pop)

}; // namespace Service::Mii


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mm/mm_u.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"

namespace Service::MM {

class MM_U final : public ServiceFramework<MM_U> {
public:
    explicit MM_U(Core::System& system_) : ServiceFramework{system_, "mm:u"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, &MM_U::InitializeOld, "InitializeOld"},
            {1, &MM_U::FinalizeOld, "FinalizeOld"},
            {2, &MM_U::SetAndWaitOld, "SetAndWaitOld"},
            {3, &MM_U::GetOld, "GetOld"},
            {4, &MM_U::Initialize, "Initialize"},
            {5, &MM_U::Finalize, "Finalize"},
            {6, &MM_U::SetAndWait, "SetAndWait"},
            {7, &MM_U::Get, "Get"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    void InitializeOld(HLERequestContext& ctx) {
        LOG_WARNING(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void FinalizeOld(HLERequestContext& ctx) {
        LOG_WARNING(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void SetAndWaitOld(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        min = rp.Pop<u32>();
        max = rp.Pop<u32>();
        LOG_DEBUG(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);

        current = min;
        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void GetOld(HLERequestContext& ctx) {
        LOG_DEBUG(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.Push(current);
    }

    void Initialize(HLERequestContext& ctx) {
        LOG_WARNING(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.Push<u32>(id); // Any non zero value
    }

    void Finalize(HLERequestContext& ctx) {
        LOG_WARNING(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void SetAndWait(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        u32 input_id = rp.Pop<u32>();
        min = rp.Pop<u32>();
        max = rp.Pop<u32>();
        LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id,
                  min, max);

        current = min;
        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void Get(HLERequestContext& ctx) {
        LOG_DEBUG(Service_MM, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.Push(current);
    }

    u32 min{0};
    u32 max{0};
    u32 current{0};
    u32 id{1};
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::MM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::MM {

void LoopProcess(Core::System& system);

} // namespace Service::MM


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mnpp/mnpp_app.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::MNPP {

class MNPP_APP final : public ServiceFramework<MNPP_APP> {
public:
    explicit MNPP_APP(Core::System& system_) : ServiceFramework{system_, "mnpp:app"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, &MNPP_APP::Unknown0, "unknown0"},
            {1, &MNPP_APP::Unknown1, "unknown1"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    void Unknown0(HLERequestContext& ctx) {
        LOG_WARNING(Service_MNPP, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void Unknown1(HLERequestContext& ctx) {
        LOG_WARNING(Service_MNPP, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("mnpp:app", std::make_shared<MNPP_APP>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::MNPP


code:
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::MNPP {

void LoopProcess(Core::System& system);

} // namespace Service::MNPP


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <memory>

#include "core/file_sys/romfs_factory.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ncm/ncm.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::NCM {

class ILocationResolver final : public ServiceFramework<ILocationResolver> {
public:
    explicit ILocationResolver(Core::System& system_, FileSys::StorageId id)
        : ServiceFramework{system_, "ILocationResolver"}, storage{id} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "ResolveProgramPath"},
            {1, nullptr, "RedirectProgramPath"},
            {2, nullptr, "ResolveApplicationControlPath"},
            {3, nullptr, "ResolveApplicationHtmlDocumentPath"},
            {4, nullptr, "ResolveDataPath"},
            {5, nullptr, "RedirectApplicationControlPath"},
            {6, nullptr, "RedirectApplicationHtmlDocumentPath"},
            {7, nullptr, "ResolveApplicationLegalInformationPath"},
            {8, nullptr, "RedirectApplicationLegalInformationPath"},
            {9, nullptr, "Refresh"},
            {10, nullptr, "RedirectApplicationProgramPath"},
            {11, nullptr, "ClearApplicationRedirection"},
            {12, nullptr, "EraseProgramRedirection"},
            {13, nullptr, "EraseApplicationControlRedirection"},
            {14, nullptr, "EraseApplicationHtmlDocumentRedirection"},
            {15, nullptr, "EraseApplicationLegalInformationRedirection"},
            {16, nullptr, "ResolveProgramPathForDebug"},
            {17, nullptr, "RedirectProgramPathForDebug"},
            {18, nullptr, "RedirectApplicationProgramPathForDebug"},
            {19, nullptr, "EraseProgramRedirectionForDebug"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    [[maybe_unused]] FileSys::StorageId storage;
};

class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> {
public:
    explicit IRegisteredLocationResolver(Core::System& system_)
        : ServiceFramework{system_, "IRegisteredLocationResolver"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "ResolveProgramPath"},
            {1, nullptr, "RegisterProgramPath"},
            {2, nullptr, "UnregisterProgramPath"},
            {3, nullptr, "RedirectProgramPath"},
            {4, nullptr, "ResolveHtmlDocumentPath"},
            {5, nullptr, "RegisterHtmlDocumentPath"},
            {6, nullptr, "UnregisterHtmlDocumentPath"},
            {7, nullptr, "RedirectHtmlDocumentPath"},
            {8, nullptr, "Refresh"},
            {9, nullptr, "RefreshExcluding"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> {
public:
    explicit IAddOnContentLocationResolver(Core::System& system_)
        : ServiceFramework{system_, "IAddOnContentLocationResolver"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "ResolveAddOnContentPath"},
            {1, nullptr, "RegisterAddOnContentStorage"},
            {2, nullptr, "UnregisterAllAddOnContentPath"},
            {3, nullptr, "RefreshApplicationAddOnContent"},
            {4, nullptr, "UnregisterApplicationAddOnContent"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class LR final : public ServiceFramework<LR> {
public:
    explicit LR(Core::System& system_) : ServiceFramework{system_, "lr"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "OpenLocationResolver"},
            {1, nullptr, "OpenRegisteredLocationResolver"},
            {2, nullptr, "RefreshLocationResolver"},
            {3, nullptr, "OpenAddOnContentLocationResolver"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class NCM final : public ServiceFramework<NCM> {
public:
    explicit NCM(Core::System& system_) : ServiceFramework{system_, "ncm"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "CreateContentStorage"},
            {1, nullptr, "CreateContentMetaDatabase"},
            {2, nullptr, "VerifyContentStorage"},
            {3, nullptr, "VerifyContentMetaDatabase"},
            {4, nullptr, "OpenContentStorage"},
            {5, nullptr, "OpenContentMetaDatabase"},
            {6, nullptr, "CloseContentStorageForcibly"},
            {7, nullptr, "CloseContentMetaDatabaseForcibly"},
            {8, nullptr, "CleanupContentMetaDatabase"},
            {9, nullptr, "ActivateContentStorage"},
            {10, nullptr, "InactivateContentStorage"},
            {11, nullptr, "ActivateContentMetaDatabase"},
            {12, nullptr, "InactivateContentMetaDatabase"},
            {13, nullptr, "InvalidateRightsIdCache"},
            {14, nullptr, "GetMemoryReport"},
            {15, nullptr, "ActivateFsContentStorage"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("lr", std::make_shared<LR>(system));
    server_manager->RegisterNamedService("ncm", std::make_shared<NCM>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::NCM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::NCM {

void LoopProcess(Core::System& system);

} // namespace Service::NCM