Просмотр исходного кода

service: mii: Implement figurine database

german77 2 лет назад
Родитель
Сommit
a50b50f8b4
3 измененных файлов с 210 добавлено и 0 удалено
  1. 2 0
      src/core/CMakeLists.txt
  2. 142 0
      src/core/hle/service/mii/mii_database.cpp
  3. 66 0
      src/core/hle/service/mii/mii_database.h

+ 2 - 0
src/core/CMakeLists.txt

@@ -596,6 +596,8 @@ add_library(core STATIC
     hle/service/mii/types/ver3_store_data.h
     hle/service/mii/types/ver3_store_data.h
     hle/service/mii/mii.cpp
     hle/service/mii/mii.cpp
     hle/service/mii/mii.h
     hle/service/mii/mii.h
+    hle/service/mii/mii_database.cpp
+    hle/service/mii/mii_database.h
     hle/service/mii/mii_manager.cpp
     hle/service/mii/mii_manager.cpp
     hle/service/mii/mii_manager.h
     hle/service/mii/mii_manager.h
     hle/service/mii/mii_result.h
     hle/service/mii/mii_result.h

+ 142 - 0
src/core/hle/service/mii/mii_database.cpp

@@ -0,0 +1,142 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/mii/mii_database.h"
+#include "core/hle/service/mii/mii_result.h"
+#include "core/hle/service/mii/mii_util.h"
+
+namespace Service::Mii {
+
+u8 NintendoFigurineDatabase::GetDatabaseLength() const {
+    return database_length;
+}
+
+bool NintendoFigurineDatabase::IsFull() const {
+    return database_length >= MaxDatabaseLength;
+}
+
+StoreData NintendoFigurineDatabase::Get(std::size_t index) const {
+    StoreData store_data = miis.at(index);
+
+    // This hack is to make external database dump compatible
+    store_data.SetDeviceChecksum();
+
+    return store_data;
+}
+
+u32 NintendoFigurineDatabase::GetCount(const DatabaseSessionMetadata& metadata) const {
+    if (magic == MiiMagic) {
+        return GetDatabaseLength();
+    }
+
+    u32 mii_count{};
+    for (std::size_t index = 0; index < mii_count; ++index) {
+        const auto& store_data = Get(index);
+        if (!store_data.IsSpecial()) {
+            mii_count++;
+        }
+    }
+
+    return mii_count;
+}
+
+bool NintendoFigurineDatabase::GetIndexByCreatorId(u32& out_index,
+                                                   const Common::UUID& create_id) const {
+    for (std::size_t index = 0; index < database_length; ++index) {
+        if (miis[index].GetCreateId() == create_id) {
+            out_index = static_cast<u32>(index);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+Result NintendoFigurineDatabase::Move(u32 current_index, u32 new_index) {
+    if (current_index == new_index) {
+        return ResultNotUpdated;
+    }
+
+    const StoreData store_data = miis[current_index];
+
+    if (new_index > current_index) {
+        // shift left
+        const u32 index_diff = new_index - current_index;
+        for (std::size_t i = 0; i < index_diff; i++) {
+            miis[current_index + i] = miis[current_index + i + 1];
+        }
+    } else {
+        // shift right
+        const u32 index_diff = current_index - new_index;
+        for (std::size_t i = 0; i < index_diff; i++) {
+            miis[current_index - i] = miis[current_index - i - 1];
+        }
+    }
+
+    miis[new_index] = store_data;
+    crc = GenerateDatabaseCrc();
+    return ResultSuccess;
+}
+
+void NintendoFigurineDatabase::Replace(u32 index, const StoreData& store_data) {
+    miis[index] = store_data;
+    crc = GenerateDatabaseCrc();
+}
+
+void NintendoFigurineDatabase::Add(const StoreData& store_data) {
+    miis[database_length] = store_data;
+    database_length++;
+    crc = GenerateDatabaseCrc();
+}
+
+void NintendoFigurineDatabase::Delete(u32 index) {
+    // shift left
+    s32 new_database_size = database_length - 1;
+    if (static_cast<s32>(index) < new_database_size) {
+        for (std::size_t i = index; i < static_cast<std::size_t>(new_database_size); i++) {
+            miis[i] = miis[i + 1];
+        }
+    }
+
+    database_length = static_cast<u8>(new_database_size);
+    crc = GenerateDatabaseCrc();
+}
+
+void NintendoFigurineDatabase::CleanDatabase() {
+    memset(miis.data(), 0, sizeof(miis));
+    version = 1;
+    magic = DatabaseMagic;
+    database_length = 0;
+    crc = GenerateDatabaseCrc();
+}
+
+void NintendoFigurineDatabase::CorruptCrc() {
+    crc = GenerateDatabaseCrc();
+    crc = ~crc;
+}
+
+Result NintendoFigurineDatabase::CheckIntegrity() {
+    if (magic != DatabaseMagic) {
+        return ResultInvalidDatabaseSignature;
+    }
+
+    if (version != 1) {
+        return ResultInvalidDatabaseVersion;
+    }
+
+    if (crc != GenerateDatabaseCrc()) {
+        return ResultInvalidDatabaseChecksum;
+    }
+
+    if (database_length >= MaxDatabaseLength) {
+        return ResultInvalidDatabaseLength;
+    }
+
+    return ResultSuccess;
+}
+
+u16 NintendoFigurineDatabase::GenerateDatabaseCrc() {
+    return MiiUtil::CalculateCrc16(&magic, sizeof(NintendoFigurineDatabase) - sizeof(crc));
+}
+
+} // namespace Service::Mii

+ 66 - 0
src/core/hle/service/mii/mii_database.h

@@ -0,0 +1,66 @@
+// 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/types/store_data.h"
+
+namespace Service::Mii {
+
+constexpr std::size_t MaxDatabaseLength{100};
+constexpr u32 MiiMagic{0xa523b78f};
+constexpr u32 DatabaseMagic{0x4244464e}; // NFDB
+
+class NintendoFigurineDatabase {
+public:
+    /// Returns the total mii count.
+    u8 GetDatabaseLength() const;
+
+    /// Returns full if database is full.
+    bool IsFull() const;
+
+    /// Returns the mii of the specified index.
+    StoreData Get(std::size_t index) const;
+
+    ///  Returns the total mii count. Ignoring special mii.
+    u32 GetCount(const DatabaseSessionMetadata& metadata) const;
+
+    /// Returns the index of a mii. If the mii isn't found returns false.
+    bool GetIndexByCreatorId(u32& out_index, const Common::UUID& create_id) const;
+
+    /// Moves the location of a specific mii.
+    Result Move(u32 current_index, u32 new_index);
+
+    /// Replaces mii with new data.
+    void Replace(u32 index, const StoreData& store_data);
+
+    /// Adds a new mii to the end of the database.
+    void Add(const StoreData& store_data);
+
+    /// Removes mii from database and shifts left the remainding data.
+    void Delete(u32 index);
+
+    /// Deletes all contents with a fresh database
+    void CleanDatabase();
+
+    /// Intentionally sets a bad checksum
+    void CorruptCrc();
+
+    /// Returns success if database is valid otherwise returns the corresponding error code.
+    Result CheckIntegrity();
+
+private:
+    /// Returns the checksum of the database
+    u16 GenerateDatabaseCrc();
+
+    u32 magic{}; // 'NFDB'
+    std::array<StoreData, MaxDatabaseLength> miis{};
+    u8 version{};
+    u8 database_length{};
+    u16 crc{};
+};
+static_assert(sizeof(NintendoFigurineDatabase) == 0x1A98,
+              "NintendoFigurineDatabase has incorrect size.");
+
+}; // namespace Service::Mii