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.
This commit is contained in:
Gericom
2026-03-15 13:28:59 +01:00
parent 601fd6371e
commit b7d7f9f352
16 changed files with 313 additions and 424 deletions

View File

@@ -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;
};
};
};