From b7d7f9f3524f227fe4bbf99e87d3925da5b40fee Mon Sep 17 00:00:00 2001 From: Gericom Date: Sun, 15 Mar 2026 13:28:59 +0100 Subject: [PATCH] Change cheat implementation to show cheats in database order, fix some bugs - AdvancedPaletteManager incorrectly handled negative y positions - FocusManager still had a pointer to a view that was destroyed in the cheats panel. After changing focus, memory got corrupted. --- arm9/source/cheats/Cheat.h | 63 ------ arm9/source/cheats/CheatCategory.h | 93 --------- arm9/source/cheats/CheatEntry.h | 190 ++++++++++++++++++ arm9/source/cheats/GameCheats.h | 61 +----- arm9/source/cheats/ICheatCategory.h | 32 --- .../cheats/PicoLoaderCheatDataFactory.cpp | 93 ++++----- .../cheats/PicoLoaderCheatDataFactory.h | 6 +- arm9/source/cheats/UsrCheatRepository.cpp | 46 ++--- arm9/source/cheats/UsrCheatRepository.h | 4 +- arm9/source/gui/AdvancedPaletteManager.cpp | 10 +- .../romBrowser/viewModels/CheatsViewModel.cpp | 54 ++--- .../romBrowser/viewModels/CheatsViewModel.h | 6 +- .../views/cheats/CheatListItemView.cpp | 4 +- .../views/cheats/CheatListItemView.h | 22 +- .../romBrowser/views/cheats/CheatsAdapter.h | 31 +-- .../views/cheats/CheatsBottomSheetView.cpp | 22 +- 16 files changed, 313 insertions(+), 424 deletions(-) delete mode 100644 arm9/source/cheats/Cheat.h delete mode 100644 arm9/source/cheats/CheatCategory.h create mode 100644 arm9/source/cheats/CheatEntry.h delete mode 100644 arm9/source/cheats/ICheatCategory.h diff --git a/arm9/source/cheats/Cheat.h b/arm9/source/cheats/Cheat.h deleted file mode 100644 index 7ca5983..0000000 --- a/arm9/source/cheats/Cheat.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -/// @brief Class representing a single cheat. -class Cheat -{ -public: - Cheat() { } - - Cheat(const char* name, const char* description, u32* flagsPointer, const void* cheatData, u32 cheatDataLength) - : _name(name), _description(description), _flagsPointer(flagsPointer) - , _cheatData(cheatData), _cheatDataLength(cheatDataLength) { } - - /// @brief Gets the name of this cheat. - /// @return A pointer to the name of this cheat. - const char* GetName() const - { - return _name; - } - - /// @brief Gets the description of this cheat. - /// @return A pointer to the description of this cheat. - const char* GetDescription() const - { - return _description; - } - - /// @brief Gets a pointer to the data of this cheat. - /// @param cheatDataLength The length of the cheat data is returned in this reference. - /// @return A pointer to the cheat data. - /// This pointer is only valid for the lifetime of the \see GameCheats instance this cheat belongs to. - const void* GetCheatData(u32& cheatDataLength) const - { - cheatDataLength = _cheatDataLength; - return _cheatData; - } - - /// @brief Gets whether this cheat is active (enabled) or not. - /// @return \c true when this cheat is active, or \c false when not active. - bool GetIsCheatActive() const - { - return ((*_flagsPointer >> 24) & 1) == 1; - } - - /// @brief Sets whether this cheat is active (enabled) or not. - /// @param isCheatActive \c true to enable this cheat, or \c false to disable this cheat. - void SetIsCheatActive(bool isCheatActive) const - { - u32 flags = *_flagsPointer; - flags &= ~(1 << 24); - if (isCheatActive) - { - flags |= 1 << 24; - } - *_flagsPointer = flags; - } - -private: - const char* _name = nullptr; - const char* _description = nullptr; - u32* _flagsPointer = nullptr; - const void* _cheatData = nullptr; - u32 _cheatDataLength = 0; -}; diff --git a/arm9/source/cheats/CheatCategory.h b/arm9/source/cheats/CheatCategory.h deleted file mode 100644 index e8d858d..0000000 --- a/arm9/source/cheats/CheatCategory.h +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once -#include -#include "ICheatCategory.h" - -/// @brief Class representing a cheat category, containing sub-categories and cheats. -class CheatCategory : public ICheatCategory -{ -public: - CheatCategory() { } - - CheatCategory(const char* name, const char* description, bool isMaxOneCheatActive, - CheatCategory* subCategories, u32 numberOfSubCategories, Cheat* cheats, u32 numberOfCheats) - : _name(name), _description(description), _isMaxOneCheatActive(isMaxOneCheatActive) - , _subCategories(subCategories), _numberOfSubCategories(numberOfSubCategories) - , _cheats(cheats), _numberOfCheats(numberOfCheats) { } - - CheatCategory(CheatCategory& other) = delete; - CheatCategory& operator=(CheatCategory& other) = delete; - - CheatCategory(CheatCategory&& other) - { - *this = std::move(other); - } - - CheatCategory& operator=(CheatCategory&& other) - { - _name = other._name; - other._name = nullptr; - _description = other._description; - other._description = nullptr; - _isMaxOneCheatActive = other._isMaxOneCheatActive; - other._isMaxOneCheatActive = false; - _subCategories = other._subCategories; - other._subCategories = nullptr; - _numberOfSubCategories = other._numberOfSubCategories; - other._numberOfSubCategories = 0; - _cheats = other._cheats; - other._cheats = nullptr; - _numberOfCheats = other._numberOfCheats; - other._numberOfCheats = 0; - return *this; - } - - ~CheatCategory() - { - if (_subCategories != nullptr) - { - free(_subCategories); - } - if (_cheats != nullptr) - { - free(_cheats); - } - } - - const char* GetName() const override - { - return _name; - } - - /// @brief Gets the description of this cheat category. - /// @return A pointer to the description of this cheat category. - const char* GetDescription() const - { - return _description; - } - - bool GetIsMaxOneCheatActive() const override - { - return _isMaxOneCheatActive; - } - - const CheatCategory* GetCategories(u32& numberOfCategories) const override - { - numberOfCategories = _numberOfSubCategories; - return _subCategories; - } - - const Cheat* GetCheats(u32& numberOfCheats) const override - { - numberOfCheats = _numberOfCheats; - return _cheats; - } - -private: - const char* _name = nullptr; - const char* _description = nullptr; - bool _isMaxOneCheatActive = false; - CheatCategory* _subCategories = nullptr; - u32 _numberOfSubCategories = 0; - Cheat* _cheats = nullptr; - u32 _numberOfCheats = 0; -}; diff --git a/arm9/source/cheats/CheatEntry.h b/arm9/source/cheats/CheatEntry.h new file mode 100644 index 0000000..dfcf839 --- /dev/null +++ b/arm9/source/cheats/CheatEntry.h @@ -0,0 +1,190 @@ +#pragma once + +/// @brief Class representing a cheat or a cheat category. +class CheatEntry +{ +public: + /// @brief Dummy empty constructor. + CheatEntry() + : _isCheatCategory(false), _flagsPointer(nullptr), _cheatData(nullptr), _cheatDataLength(0) { } + + /// @brief Constructor for a cheat. + CheatEntry(const char* name, const char* description, u32* flagsPointer, const void* cheatData, u32 cheatDataLength) + : _name(name), _description(description), _isCheatCategory(false), _flagsPointer(flagsPointer) + , _cheatData(cheatData), _cheatDataLength(cheatDataLength) { } + + /// @brief Constructor for a category. + CheatEntry(const char* name, const char* description, bool isMaxOneCheatActive, CheatEntry* subEntries, u32 numberOfSubEntries) + : _name(name), _description(description), _isCheatCategory(true), _isMaxOneCheatActive(isMaxOneCheatActive) + , _subEntries(subEntries), _numberOfSubEntries(numberOfSubEntries) { } + + CheatEntry(const CheatEntry& other) = delete; + + CheatEntry(CheatEntry&& other) + : _isCheatCategory(false), _flagsPointer(nullptr), _cheatData(nullptr), _cheatDataLength(0) + { + *this = std::move(other); + } + + ~CheatEntry() + { + if (_isCheatCategory && _subEntries != nullptr) + { + delete[] _subEntries; + } + } + + CheatEntry& operator=(const CheatEntry& other) = delete; + + CheatEntry& operator=(CheatEntry&& other) + { + if (_isCheatCategory && _subEntries != nullptr) + { + delete[] _subEntries; + _subEntries = nullptr; + } + + _name = other._name; + other._name = nullptr; + _description = other._description; + other._description = nullptr; + _isCheatCategory = other.IsCheatCategory(); + if (_isCheatCategory) + { + _isMaxOneCheatActive = other._isMaxOneCheatActive; + _subEntries = other._subEntries; + other._subEntries = nullptr; + _numberOfSubEntries = other._numberOfSubEntries; + other._numberOfSubEntries = 0; + } + else + { + _flagsPointer = other._flagsPointer; + other._flagsPointer = nullptr; + _cheatData = other._cheatData; + other._cheatData = nullptr; + _cheatDataLength = other._cheatDataLength; + other._cheatDataLength = 0; + } + + return *this; + } + + /// @brief Gets the name of this cheat entry. + /// @return A pointer to the name of this cheat entry. + const char* GetName() const + { + return _name; + } + + /// @brief Gets the description of this cheat entry. + /// @return A pointer to the description of this cheat entry. + const char* GetDescription() const + { + return _description; + } + + /// @brief When this entry is a cheat, gets a pointer to the cheat data. + /// @param cheatDataLength The length of the cheat data is returned in this reference. + /// @return A pointer to the cheat data. + /// This pointer is only valid for the lifetime of the \see GameCheats instance this cheat belongs to. + /// If this entry is not a cheat, \c nullptr is returned. + const void* GetCheatData(u32& cheatDataLength) const + { + if (_isCheatCategory) + { + cheatDataLength = 0; + return nullptr; + } + else + { + cheatDataLength = _cheatDataLength; + return _cheatData; + } + } + + /// @brief Gets whether this entry is an active (enabled) cheat or not. + /// @return \c true when this entry is an active cheat, or \c false otherwise. + bool GetIsCheatActive() const + { + if (_isCheatCategory) + { + return false; + } + else + { + return ((*_flagsPointer >> 24) & 1) == 1; + } + } + + /// @brief If this entry is a cheat, sets whether this cheat is active (enabled) or not. + /// @param isCheatActive \c true to enable this cheat, or \c false to disable this cheat. + void SetIsCheatActive(bool isCheatActive) const + { + if (!_isCheatCategory) + { + u32 flags = *_flagsPointer; + flags &= ~(1 << 24); + if (isCheatActive) + { + flags |= 1 << 24; + } + *_flagsPointer = flags; + } + } + + /// @brief Indicates if this entry is a cheat category or not. + /// @return \c true when this entry is a cheat category, or \c false when this entry is a cheat. + bool IsCheatCategory() const + { + return _isCheatCategory; + } + + /// @brief Indicates if this entry is a cheat category in which only one cheat is allowed to be on at a time or not. + /// @return \c true when this entry is a cheat category in which only one cheat is allowed + /// to be active at a time, or \c false otherwise. + bool GetIsMaxOneCheatActive() const + { + return _isCheatCategory && _isMaxOneCheatActive; + } + + /// @brief Gets the sub-entries of this entry. + /// @param numberOfSubEntries The number of sub-entries is returned through this reference. + /// @return A pointer to an array of entries. This may be \c nullptr when \p numberOfSubEntries is 0. + const CheatEntry* GetSubEntries(u32& numberOfSubEntries) const + { + if (_isCheatCategory) + { + numberOfSubEntries = _numberOfSubEntries; + return _subEntries; + } + else + { + numberOfSubEntries = 0; + return nullptr; + } + } + +private: + const char* _name = nullptr; + const char* _description = nullptr; + bool _isCheatCategory; + + union + { + struct + { + // For cheat + u32* _flagsPointer; + const void* _cheatData; + u32 _cheatDataLength; + }; + struct + { + // For category + bool _isMaxOneCheatActive; + CheatEntry* _subEntries; + u32 _numberOfSubEntries; + }; + }; +}; diff --git a/arm9/source/cheats/GameCheats.h b/arm9/source/cheats/GameCheats.h index a8ad835..24f7f5d 100644 --- a/arm9/source/cheats/GameCheats.h +++ b/arm9/source/cheats/GameCheats.h @@ -1,48 +1,15 @@ #pragma once -#include "Cheat.h" -#include "CheatCategory.h" -#include "ICheatCategory.h" +#include "CheatEntry.h" /// @brief Class holding the cheats for a game. -class GameCheats : public ICheatCategory +class GameCheats : public CheatEntry { public: GameCheats(std::unique_ptr cheatData, u32 cheatDataLength, u32 fileOffset, const char* gameName, - CheatCategory* categories, u32 numberOfCategories, Cheat* cheats, u32 numberOfCheats) - : _cheatData(std::move(cheatData)), _cheatDataLength(cheatDataLength), _fileOffset(fileOffset), _gameName(gameName) - , _categories(categories), _numberOfCategories(numberOfCategories) - , _cheats(cheats), _numberOfCheats(numberOfCheats) { } - - ~GameCheats() - { - if (_categories != nullptr) - { - free(_categories); - } - if (_cheats != nullptr) - { - free(_cheats); - } - } - - /// @brief Gets the name of the game. - /// @return A pointer to the name of the game. - const char* GetGameName() const - { - return _gameName; - } - - const CheatCategory* GetCategories(u32& numberOfCategories) const override - { - numberOfCategories = _numberOfCategories; - return _categories; - } - - const Cheat* GetCheats(u32& numberOfCheats) const override - { - numberOfCheats = _numberOfCheats; - return _cheats; - } + CheatEntry* subEntries, u32 numberOfSubEntries) + : CheatEntry(gameName, "", false, subEntries, numberOfSubEntries) + , _cheatData(std::move(cheatData)), _cheatDataLength(cheatDataLength) + , _fileOffset(fileOffset) { } /// @brief Gets a pointer to the cheat data. /// @param cheatDataLength The length of the cheat data is returned in this reference. @@ -62,20 +29,4 @@ private: std::unique_ptr _cheatData; u32 _cheatDataLength; u32 _fileOffset; - const char* _gameName; - CheatCategory* _categories; - u32 _numberOfCategories; - Cheat* _cheats; - u32 _numberOfCheats; - - // From ICheatCategory - const char* GetName() const override - { - return ""; - } - - bool GetIsMaxOneCheatActive() const override - { - return false; - } }; diff --git a/arm9/source/cheats/ICheatCategory.h b/arm9/source/cheats/ICheatCategory.h deleted file mode 100644 index e555cac..0000000 --- a/arm9/source/cheats/ICheatCategory.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -class CheatCategory; -class Cheat; - -/// @brief Interface for a collection of cheats. -class ICheatCategory -{ -public: - virtual ~ICheatCategory() = default; - - /// @brief Gets the name of this category. - /// @return The name of this category. - virtual const char* GetName() const = 0; - - /// @brief Indicates if only one cheat in this category is allowed to be on or not. - /// @return \c true when only one cheat is allowed to be active in this category, or \c false otherwise. - virtual bool GetIsMaxOneCheatActive() const = 0; - - /// @brief Gets the sub-categories of this category. - /// @param numberOfCategories The number of categories is returned through this reference. - /// @return A pointer to an array of categories. This may be \c nullptr when \p numberOfCategories is 0. - virtual const CheatCategory* GetCategories(u32& numberOfCategories) const; - - /// @brief Gets the cheats in this category. - /// @param numberOfCheats The number of cheats is returned through this reference. - /// @return A pointer to an array of cheats. This may be \c nullptr when \p numberOfCheats is 0. - virtual const Cheat* GetCheats(u32& numberOfCheats) const; - -protected: - ICheatCategory() = default; -}; diff --git a/arm9/source/cheats/PicoLoaderCheatDataFactory.cpp b/arm9/source/cheats/PicoLoaderCheatDataFactory.cpp index 42fb5ae..f9d464c 100644 --- a/arm9/source/cheats/PicoLoaderCheatDataFactory.cpp +++ b/arm9/source/cheats/PicoLoaderCheatDataFactory.cpp @@ -8,7 +8,7 @@ pload_cheats_t* PicoLoaderCheatDataFactory::CreateCheatData(const std::unique_pt if (gameCheats) { u32 totalNumberOfCheats = 0; - u32 requiredSize = GetCheatCategoryRequiredSize(gameCheats.get(), totalNumberOfCheats); + u32 requiredSize = GetCheatEntryRequiredSize(gameCheats.get(), totalNumberOfCheats); if (totalNumberOfCheats != 0) { requiredSize += sizeof(u32) * 2; @@ -16,32 +16,32 @@ pload_cheats_t* PicoLoaderCheatDataFactory::CreateCheatData(const std::unique_pt cheatData->length = requiredSize; cheatData->numberOfCheats = totalNumberOfCheats; u8* buffer = (u8*)&cheatData->firstCheat; - GetCheatCategoryData(gameCheats.get(), buffer); + GetCheatEntryData(gameCheats.get(), buffer); } } return cheatData; } -u32 PicoLoaderCheatDataFactory::GetCheatCategoryRequiredSize(const ICheatCategory* cheatCategory, u32& totalNumberOfCheats) const +u32 PicoLoaderCheatDataFactory::GetCheatEntryRequiredSize(const CheatEntry* cheatEntry, u32& totalNumberOfCheats) const { u32 requiredSize = 0; - - u32 numberOfCategories = 0; - auto subCategories = cheatCategory->GetCategories(numberOfCategories); - for (u32 i = 0; i < numberOfCategories; i++) + if (cheatEntry->IsCheatCategory()) { - requiredSize += GetCheatCategoryRequiredSize(&subCategories[i], totalNumberOfCheats); - } - - u32 numberOfCheats = 0; - auto cheats = cheatCategory->GetCheats(numberOfCheats); - for (u32 i = 0; i < numberOfCheats; i++) - { - u32 cheatRequiredSize = GetCheatRequiredSize(&cheats[i]); - if (cheatRequiredSize != 0) + u32 numberOfSubEntries = 0; + auto subEntries = cheatEntry->GetSubEntries(numberOfSubEntries); + for (u32 i = 0; i < numberOfSubEntries; i++) { - requiredSize += cheatRequiredSize; + requiredSize += GetCheatEntryRequiredSize(&subEntries[i], totalNumberOfCheats); + } + } + else + { + if (cheatEntry->GetIsCheatActive()) + { + u32 cheatDataLength = 0; + cheatEntry->GetCheatData(cheatDataLength); + requiredSize += sizeof(u32) + ((cheatDataLength + 7) & ~7); totalNumberOfCheats++; } } @@ -49,51 +49,32 @@ u32 PicoLoaderCheatDataFactory::GetCheatCategoryRequiredSize(const ICheatCategor return requiredSize; } -u32 PicoLoaderCheatDataFactory::GetCheatRequiredSize(const Cheat* cheat) const +void PicoLoaderCheatDataFactory::GetCheatEntryData(const CheatEntry* cheatEntry, u8*& buffer) const { - if (cheat->GetIsCheatActive()) + if (cheatEntry->IsCheatCategory()) { - u32 cheatDataLength = 0; - cheat->GetCheatData(cheatDataLength); - return sizeof(u32) + ((cheatDataLength + 7) & ~7); + u32 numberOfSubEntries = 0; + auto subEntries = cheatEntry->GetSubEntries(numberOfSubEntries); + for (u32 i = 0; i < numberOfSubEntries; i++) + { + GetCheatEntryData(&subEntries[i], buffer); + } } else { - return 0; - } -} - -void PicoLoaderCheatDataFactory::GetCheatCategoryData(const ICheatCategory* cheatCategory, u8*& buffer) const -{ - u32 numberOfCategories = 0; - auto subCategories = cheatCategory->GetCategories(numberOfCategories); - for (u32 i = 0; i < numberOfCategories; i++) - { - GetCheatCategoryData(&subCategories[i], buffer); - } - - u32 numberOfCheats = 0; - auto cheats = cheatCategory->GetCheats(numberOfCheats); - for (u32 i = 0; i < numberOfCheats; i++) - { - GetCheatData(&cheats[i], buffer); - } -} - -void PicoLoaderCheatDataFactory::GetCheatData(const Cheat* cheat, u8*& buffer) const -{ - if (cheat->GetIsCheatActive()) - { - u32 cheatDataLength = 0; - auto cheatData = cheat->GetCheatData(cheatDataLength); - u32 paddedCheatDataLength = (cheatDataLength + 7) & ~7; - *(u32*)buffer = paddedCheatDataLength; - buffer += sizeof(u32); - memcpy(buffer, cheatData, cheatDataLength); - if (cheatDataLength != paddedCheatDataLength) + if (cheatEntry->GetIsCheatActive()) { - memset(buffer + cheatDataLength, 0, paddedCheatDataLength - cheatDataLength); + u32 cheatDataLength = 0; + auto cheatData = cheatEntry->GetCheatData(cheatDataLength); + u32 paddedCheatDataLength = (cheatDataLength + 7) & ~7; + *(u32*)buffer = paddedCheatDataLength; + buffer += sizeof(u32); + memcpy(buffer, cheatData, cheatDataLength); + if (cheatDataLength != paddedCheatDataLength) + { + memset(buffer + cheatDataLength, 0, paddedCheatDataLength - cheatDataLength); + } + buffer += paddedCheatDataLength; } - buffer += paddedCheatDataLength; } } diff --git a/arm9/source/cheats/PicoLoaderCheatDataFactory.h b/arm9/source/cheats/PicoLoaderCheatDataFactory.h index 6198dab..5278790 100644 --- a/arm9/source/cheats/PicoLoaderCheatDataFactory.h +++ b/arm9/source/cheats/PicoLoaderCheatDataFactory.h @@ -13,8 +13,6 @@ public: pload_cheats_t* CreateCheatData(const std::unique_ptr& gameCheats) const; private: - u32 GetCheatCategoryRequiredSize(const ICheatCategory* cheatCategory, u32& totalNumberOfCheats) const; - u32 GetCheatRequiredSize(const Cheat* cheat) const; - void GetCheatCategoryData(const ICheatCategory* cheatCategory, u8*& buffer) const; - void GetCheatData(const Cheat* cheat, u8*& buffer) const; + u32 GetCheatEntryRequiredSize(const CheatEntry* cheatEntry, u32& totalNumberOfCheats) const; + void GetCheatEntryData(const CheatEntry* cheatEntry, u8*& buffer) const; }; diff --git a/arm9/source/cheats/UsrCheatRepository.cpp b/arm9/source/cheats/UsrCheatRepository.cpp index 902c57b..6ae2fe3 100644 --- a/arm9/source/cheats/UsrCheatRepository.cpp +++ b/arm9/source/cheats/UsrCheatRepository.cpp @@ -107,11 +107,8 @@ std::unique_ptr UsrCheatRepository::GetCheatsForGame(u32 gameCode, u // master codes ptr += 8 * 4; - auto categories = (CheatCategory*)malloc(totalNumberOfItems * sizeof(CheatCategory)); - u32 categoryCount = 0; - - auto cheats = (Cheat*)malloc(totalNumberOfItems * sizeof(Cheat)); - u32 cheatCount = 0; + auto entries = new CheatEntry[totalNumberOfItems]; + u32 entryCount = 0; while (ptr < cheatData.get() + cheatDataLength) { @@ -119,21 +116,20 @@ std::unique_ptr UsrCheatRepository::GetCheatsForGame(u32 gameCode, u bool isCategory = ((itemFlags >> 28) & 1) == 1; if (isCategory) { - ParseCategory(categories[categoryCount], ptr); - categoryCount++; + entries[entryCount++] = ParseCategory(ptr); } else { - ParseCheat(cheats[cheatCount], ptr); - cheatCount++; + entries[entryCount++] = ParseCheat(ptr); } } - categories = (CheatCategory*)realloc(categories, categoryCount * sizeof(CheatCategory)); - cheats = (Cheat*)realloc(cheats, cheatCount * sizeof(Cheat)); + auto actualEntries = new CheatEntry[entryCount]; + std::move(entries, entries + entryCount, actualEntries); + delete[] entries; return std::make_unique( - std::move(cheatData), cheatDataLength, index->offset, gameName, categories, categoryCount, cheats, cheatCount); + std::move(cheatData), cheatDataLength, index->offset, gameName, actualEntries, entryCount); } const usr_cheat_index_entry_t* UsrCheatRepository::FindIndex(u32 gameCode, u32 headerCrc32) const @@ -162,7 +158,7 @@ const usr_cheat_index_entry_t* UsrCheatRepository::FindIndex(u32 gameCode, u32 h return nullptr; } -void UsrCheatRepository::ParseCategory(CheatCategory& category, u8*& ptr) const +CheatEntry UsrCheatRepository::ParseCategory(u8*& ptr) const { // flags u32 itemFlags = *(u32*)ptr; @@ -181,35 +177,25 @@ void UsrCheatRepository::ParseCategory(CheatCategory& category, u8*& ptr) const // padding ptr = (u8*)(((u32)ptr + 3) & ~3); // 32-bit align - auto categories = (CheatCategory*)malloc(numberOfItems * sizeof(CheatCategory)); - u32 categoryCount = 0; - - auto cheats = (Cheat*)malloc(numberOfItems * sizeof(Cheat)); - u32 cheatCount = 0; - + auto entries = new CheatEntry[numberOfItems]; for (u32 i = 0; i < numberOfItems; i++) { u32 itemFlags = *(u32*)ptr; bool isCategory = ((itemFlags >> 28) & 1) == 1; if (isCategory) { - ParseCategory(categories[categoryCount], ptr); - categoryCount++; + entries[i] = ParseCategory(ptr); } else { - ParseCheat(cheats[cheatCount], ptr); - cheatCount++; + entries[i] = ParseCheat(ptr); } } - categories = (CheatCategory*)realloc(categories, categoryCount * sizeof(CheatCategory)); - cheats = (Cheat*)realloc(cheats, cheatCount * sizeof(Cheat)); - - new (&category) CheatCategory (itemName, itemDescription, isMaxOneCheatActive, categories, categoryCount, cheats, cheatCount); + return CheatEntry(itemName, itemDescription, isMaxOneCheatActive, entries, numberOfItems); } -void UsrCheatRepository::ParseCheat(Cheat& cheat, u8*& ptr) const +CheatEntry UsrCheatRepository::ParseCheat(u8*& ptr) const { // flags u32* flagsPtr = (u32*)ptr; @@ -230,8 +216,10 @@ void UsrCheatRepository::ParseCheat(Cheat& cheat, u8*& ptr) const u32 numberOfCodeWords = *(u32*)ptr; ptr += 4; - new (&cheat) Cheat(itemName, itemDescription, flagsPtr, ptr, numberOfCodeWords * 4); + const void* cheatData = ptr; // code ptr += numberOfCodeWords * 4; + + return CheatEntry(itemName, itemDescription, flagsPtr, cheatData, numberOfCodeWords * 4); } diff --git a/arm9/source/cheats/UsrCheatRepository.h b/arm9/source/cheats/UsrCheatRepository.h index 1d20c65..595b950 100644 --- a/arm9/source/cheats/UsrCheatRepository.h +++ b/arm9/source/cheats/UsrCheatRepository.h @@ -23,6 +23,6 @@ private: std::unique_ptr GetCheatsForGame(u32 gameCode, u32 headerCrc32) const; const usr_cheat_index_entry_t* FindIndex(u32 gameCode, u32 headerCrc32) const; - void ParseCategory(CheatCategory& category, u8*& ptr) const; - void ParseCheat(Cheat& cheat, u8*& ptr) const; + CheatEntry ParseCategory(u8*& ptr) const; + CheatEntry ParseCheat(u8*& ptr) const; }; diff --git a/arm9/source/gui/AdvancedPaletteManager.cpp b/arm9/source/gui/AdvancedPaletteManager.cpp index b39d5cf..e732b68 100644 --- a/arm9/source/gui/AdvancedPaletteManager.cpp +++ b/arm9/source/gui/AdvancedPaletteManager.cpp @@ -89,14 +89,8 @@ u32 AdvancedPaletteManagerBase::TryMerge(PaletteRow* rows, const PaletteRow& new u32 AdvancedPaletteManagerBase::AllocRowInternal(PaletteRow* rows, const IPalette& palette, int yStart, int yEnd) { - if (yStart < 0) - { - yStart = 0; - } - if (yEnd > 192) - { - yEnd = 192; - } + yStart = std::clamp(yStart, 0, 192); + yEnd = std::clamp(yEnd, 0, 192); u32 newIdx = _usedRows; PaletteRow& newRow = rows[newIdx]; diff --git a/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp b/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp index e9cdde9..be7bc9b 100644 --- a/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp +++ b/arm9/source/romBrowser/viewModels/CheatsViewModel.cpp @@ -33,39 +33,40 @@ void CheatsViewModel::ActivateSelectedItem() } auto cheatCategory = GetCurrentCheatCategory(); - u32 numberOfCategories = 0; - auto categories = cheatCategory->GetCategories(numberOfCategories); - u32 numberOfCheats = 0; - auto cheats = cheatCategory->GetCheats(numberOfCheats); + u32 numberOfSubEntries = 0; + auto subEntries = cheatCategory->GetSubEntries(numberOfSubEntries); - if (numberOfCategories + numberOfCheats == 0) + if (numberOfSubEntries == 0) { // There is nothing to activate return; } - if (_selectedItem < (int)numberOfCategories) + auto& entry = subEntries[_selectedItem]; + if (entry.IsCheatCategory()) { // Category activated if (_categoryStackLevel + 1 != _categoryStack.size()) { - _categoryStack[++_categoryStackLevel] = { &categories[_selectedItem], (u32)_selectedItem }; + _categoryStack[++_categoryStackLevel] = { &entry, (u32)_selectedItem }; _selectedItem = 0; } } else { // Toggle cheat on/off - auto& cheat = cheats[_selectedItem - numberOfCategories]; - bool isEnabled = !cheat.GetIsCheatActive(); + bool isEnabled = !entry.GetIsCheatActive(); if (isEnabled && cheatCategory->GetIsMaxOneCheatActive()) { - for (u32 i = 0; i < numberOfCheats; i++) + for (u32 i = 0; i < numberOfSubEntries; i++) { - cheats[i].SetIsCheatActive(false); + if (!subEntries[i].IsCheatCategory()) + { + subEntries[i].SetIsCheatActive(false); + } } } - cheat.SetIsCheatActive(isEnabled); + entry.SetIsCheatActive(isEnabled); _changed = true; } } @@ -111,23 +112,24 @@ void CheatsViewModel::DisableAllCheats() } } -void CheatsViewModel::DisableAllCheats(const ICheatCategory* cheatCategory) +void CheatsViewModel::DisableAllCheats(const CheatEntry* cheatCategory) { - u32 numberOfCategories = 0; - auto categories = cheatCategory->GetCategories(numberOfCategories); - for (u32 i = 0; i < numberOfCategories; i++) + u32 numberOfSubEntries = 0; + auto subEntries = cheatCategory->GetSubEntries(numberOfSubEntries); + for (u32 i = 0; i < numberOfSubEntries; i++) { - DisableAllCheats(&categories[i]); - } - - u32 numberOfCheats = 0; - auto cheats = cheatCategory->GetCheats(numberOfCheats); - for (u32 i = 0; i < numberOfCheats; i++) - { - if (cheats[i].GetIsCheatActive()) + auto& entry = subEntries[i]; + if (entry.IsCheatCategory()) { - cheats[i].SetIsCheatActive(false); - _changed = true; + DisableAllCheats(&entry); + } + else + { + if (entry.GetIsCheatActive()) + { + entry.SetIsCheatActive(false); + _changed = true; + } } } } diff --git a/arm9/source/romBrowser/viewModels/CheatsViewModel.h b/arm9/source/romBrowser/viewModels/CheatsViewModel.h index 392bbd1..7b0d2c3 100644 --- a/arm9/source/romBrowser/viewModels/CheatsViewModel.h +++ b/arm9/source/romBrowser/viewModels/CheatsViewModel.h @@ -44,7 +44,7 @@ public: /// @brief Gets the current cheat category. /// @return The current cheat category. - const ICheatCategory* GetCurrentCheatCategory() const { return _categoryStack[_categoryStackLevel].cheatCategory; } + const CheatEntry* GetCurrentCheatCategory() const { return _categoryStack[_categoryStackLevel].cheatCategory; } /// @brief Gets the index of the selected item. /// @return The index of the selected item. @@ -64,7 +64,7 @@ public: private: struct CategoryStackEntry { - const ICheatCategory* cheatCategory; + const CheatEntry* cheatCategory; u32 index; }; @@ -78,5 +78,5 @@ private: u32 _categoryStackLevel = 0; std::array _categoryStack; - void DisableAllCheats(const ICheatCategory* cheatCategory); + void DisableAllCheats(const CheatEntry* cheatCategory); }; diff --git a/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp b/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp index 41eb6b5..c11f8f4 100644 --- a/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp +++ b/arm9/source/romBrowser/views/cheats/CheatListItemView.cpp @@ -25,9 +25,9 @@ CheatListItemView::CheatListItemView(const VramOffsets& vramOffsets, void CheatListItemView::Update() { _nameLabel.SetPosition(_position.x + NAME_LABEL_X, _position.y + NAME_LABEL_Y); - if (_cheat != nullptr) + if (_cheatEntry != nullptr && !_cheatEntry->IsCheatCategory()) { - _iconVramOffset = _cheat->GetIsCheatActive() + _iconVramOffset = _cheatEntry->GetIsCheatActive() ? _vramOffsets.checkboxCheckedIconVramOffset : _vramOffsets.checkboxUncheckedIconVramOffset; } diff --git a/arm9/source/romBrowser/views/cheats/CheatListItemView.h b/arm9/source/romBrowser/views/cheats/CheatListItemView.h index 16ccd8b..a9366e9 100644 --- a/arm9/source/romBrowser/views/cheats/CheatListItemView.h +++ b/arm9/source/romBrowser/views/cheats/CheatListItemView.h @@ -1,8 +1,7 @@ #pragma once #include "gui/views/ViewContainer.h" #include "gui/views/Label2DView.h" -#include "cheats/CheatCategory.h" -#include "cheats/Cheat.h" +#include "cheats/CheatEntry.h" class MaterialColorScheme; class IFontRepository; @@ -34,17 +33,14 @@ public: _nameLabel.SetText(name); } - void SetCategory(const CheatCategory* cheatCategory) + void SetEntry(const CheatEntry* cheatEntry) { - _cheat = nullptr; - _nameLabel.SetText(cheatCategory->GetName()); - _iconVramOffset = _vramOffsets.folderIconVramOffset; - } - - void SetCheat(const Cheat* cheat) - { - _cheat = cheat; - _nameLabel.SetText(_cheat->GetName()); + _cheatEntry = cheatEntry; + _nameLabel.SetText(cheatEntry->GetName()); + if (cheatEntry->IsCheatCategory()) + { + _iconVramOffset = _vramOffsets.folderIconVramOffset; + } } private: @@ -52,5 +48,5 @@ private: VramOffsets _vramOffsets; const MaterialColorScheme* _materialColorScheme; u32 _iconVramOffset = 0; - const Cheat* _cheat = nullptr; + const CheatEntry* _cheatEntry = nullptr; }; diff --git a/arm9/source/romBrowser/views/cheats/CheatsAdapter.h b/arm9/source/romBrowser/views/cheats/CheatsAdapter.h index 9ce7783..ed716aa 100644 --- a/arm9/source/romBrowser/views/cheats/CheatsAdapter.h +++ b/arm9/source/romBrowser/views/cheats/CheatsAdapter.h @@ -1,25 +1,22 @@ #pragma once #include "gui/views/RecyclerAdapter.h" -#include "cheats/CheatCategory.h" -#include "cheats/Cheat.h" +#include "cheats/CheatEntry.h" #include "CheatListItemView.h" /// @brief Recycler adapter for cheats. class CheatsAdapter : public RecyclerAdapter { public: - CheatsAdapter(const ICheatCategory* cheatCategory, const MaterialColorScheme* materialColorScheme, + CheatsAdapter(const CheatEntry* cheatCategory, const MaterialColorScheme* materialColorScheme, const IFontRepository* fontRepository, const CheatListItemView::VramOffsets& vramOffsets) : _cheatCategory(cheatCategory), _materialColorScheme(materialColorScheme) , _fontRepository(fontRepository), _vramOffsets(vramOffsets) { } u32 GetItemCount() const override { - u32 numberOfCategories = 0; - _cheatCategory->GetCategories(numberOfCategories); - u32 numberOfCheats = 0; - _cheatCategory->GetCheats(numberOfCheats); - return numberOfCategories + numberOfCheats; + u32 numberOfSubEntries = 0; + _cheatCategory->GetSubEntries(numberOfSubEntries); + return numberOfSubEntries; } void GetViewSize(int& width, int& height) const override @@ -41,19 +38,9 @@ public: void BindView(View* view, int index) const override { auto listItemView = static_cast(view); - u32 numberOfCategories = 0; - auto categories = _cheatCategory->GetCategories(numberOfCategories); - if ((u32)index < numberOfCategories) - { - listItemView->SetCategory(&categories[index]); - } - else - { - index -= numberOfCategories; - u32 numberOfCheats = 0; - auto cheats = _cheatCategory->GetCheats(numberOfCheats); - listItemView->SetCheat(&cheats[index]); - } + u32 numberOfSubEntries = 0; + auto subEntries = _cheatCategory->GetSubEntries(numberOfSubEntries); + listItemView->SetEntry(&subEntries[index]); } void ReleaseView(View* view, int index) const override @@ -62,7 +49,7 @@ public: } private: - const ICheatCategory* _cheatCategory; + const CheatEntry* _cheatCategory; const MaterialColorScheme* _materialColorScheme; const IFontRepository* _fontRepository; CheatListItemView::VramOffsets _vramOffsets; diff --git a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp index ff72932..036c576 100644 --- a/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp +++ b/arm9/source/romBrowser/views/cheats/CheatsBottomSheetView.cpp @@ -237,6 +237,9 @@ bool CheatsBottomSheetView::HandleInput(const InputProvider& inputProvider, Focu void CheatsBottomSheetView::UpdateCheatList() { + // Need to unfocus first, otherwise the focus manager still contains a pointer to a view that is going to be destroyed + _focusManager->Unfocus(); + auto oldAdapter = _cheatsAdapter; _cheatsAdapter = new CheatsAdapter( _viewModel->GetCurrentCheatCategory(), _materialColorScheme, _fontRepository, _vramOffsets); @@ -261,21 +264,8 @@ void CheatsBottomSheetView::UpdateDescriptionText() else { auto cheatCategory = _viewModel->GetCurrentCheatCategory(); - u32 numberOfCategories = 0; - auto categories = cheatCategory->GetCategories(numberOfCategories); - u32 numberOfCheats = 0; - auto cheats = cheatCategory->GetCheats(numberOfCheats); - if ((u32)selectedItem < numberOfCategories) - { - _descriptionLabel.SetText(categories[selectedItem].GetDescription()); - } - else if ((u32)selectedItem < numberOfCategories + numberOfCheats) - { - _descriptionLabel.SetText(cheats[selectedItem - numberOfCategories].GetDescription()); - } - else - { - _descriptionLabel.SetText(""); - } + u32 numberOfSubEntries = 0; + auto subEntries = cheatCategory->GetSubEntries(numberOfSubEntries); + _descriptionLabel.SetText(subEntries[selectedItem].GetDescription()); } }