From c6bf5d51812f1d646546f4e89499c4e963ba351d Mon Sep 17 00:00:00 2001 From: Jesse Talavera Date: Thu, 1 Aug 2024 16:01:00 -0400 Subject: [PATCH] Allow `AREngine` to be used independently of `ARCodeFile` (#2108) * Make `EmuInstance::cheatFile` use a `unique_ptr` - Fixes a memory leak, as the cheat file wasn't cleaned up in the destructor * Split `AREngine` and `ARCodeFile` apart - Suitable for frontends that have their own way of storing cheats - Store the cheats in `AREngine` in a `std::vector` - Apparently cheats are _supposed_ to be executed each frame; I didn't understand this until recently --- src/ARCodeFile.cpp | 21 +++++++++++++++------ src/ARCodeFile.h | 8 +++++--- src/AREngine.cpp | 16 ++++------------ src/AREngine.h | 10 +++++----- src/frontend/qt_sdl/EmuInstance.cpp | 25 +++++++++++++++---------- src/frontend/qt_sdl/EmuInstance.h | 2 +- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/ARCodeFile.cpp b/src/ARCodeFile.cpp index 2b37e859..a98f5e50 100644 --- a/src/ARCodeFile.cpp +++ b/src/ARCodeFile.cpp @@ -33,17 +33,26 @@ ARCodeFile::ARCodeFile(const std::string& filename) { Filename = filename; - Error = false; - - Categories.clear(); - if (!Load()) Error = true; } -ARCodeFile::~ARCodeFile() +std::vector ARCodeFile::GetCodes() const noexcept { - Categories.clear(); + if (Error) + return {}; + + std::vector codes; + + for (const ARCodeCat& cat : Categories) + { + for (const ARCode& code : cat.Codes) + { + codes.push_back(code); + } + } + + return codes; } bool ARCodeFile::Load() diff --git a/src/ARCodeFile.h b/src/ARCodeFile.h index 2cdf1f05..04f9e4f4 100644 --- a/src/ARCodeFile.h +++ b/src/ARCodeFile.h @@ -48,14 +48,16 @@ class ARCodeFile { public: ARCodeFile(const std::string& filename); - ~ARCodeFile(); + ~ARCodeFile() noexcept = default; - bool Error; + [[nodiscard]] std::vector GetCodes() const noexcept; + + bool Error = false; bool Load(); bool Save(); - ARCodeCatList Categories; + ARCodeCatList Categories {}; private: std::string Filename; diff --git a/src/AREngine.cpp b/src/AREngine.cpp index 879c620c..bdda5863 100644 --- a/src/AREngine.cpp +++ b/src/AREngine.cpp @@ -31,7 +31,6 @@ using Platform::LogLevel; AREngine::AREngine(melonDS::NDS& nds) : NDS(nds) { - CodeFile = nullptr; } #define case16(x) \ @@ -388,19 +387,12 @@ void AREngine::RunCheat(const ARCode& arcode) void AREngine::RunCheats() { - if (!CodeFile) return; + if (Cheats.empty()) return; - for (ARCodeCatList::iterator i = CodeFile->Categories.begin(); i != CodeFile->Categories.end(); i++) + for (const ARCode& code : Cheats) { - ARCodeCat& cat = *i; - - for (ARCodeList::iterator j = cat.Codes.begin(); j != cat.Codes.end(); j++) - { - ARCode& code = *j; - - if (code.Enabled) - RunCheat(code); - } + if (code.Enabled) + RunCheat(code); } } } diff --git a/src/AREngine.h b/src/AREngine.h index cdffac07..e73fc98e 100644 --- a/src/AREngine.h +++ b/src/AREngine.h @@ -19,6 +19,7 @@ #ifndef ARENGINE_H #define ARENGINE_H +#include #include "ARCodeFile.h" namespace melonDS @@ -29,14 +30,13 @@ class AREngine public: AREngine(melonDS::NDS& nds); - ARCodeFile* GetCodeFile() { return CodeFile; } - void SetCodeFile(ARCodeFile* file) { CodeFile = file; } - + std::vector Cheats {}; +private: + friend class ARM; void RunCheats(); void RunCheat(const ARCode& arcode); -private: + melonDS::NDS& NDS; - ARCodeFile* CodeFile; // AR code file - frontend is responsible for managing this }; } diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 5fa1612b..2c8e52a0 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -686,12 +686,8 @@ void EmuInstance::undoStateLoad() void EmuInstance::unloadCheats() { - if (cheatFile) - { - delete cheatFile; - cheatFile = nullptr; - nds->AREngine.SetCodeFile(nullptr); - } + cheatFile = nullptr; // cleaned up by unique_ptr + nds->AREngine.Cheats.clear(); } void EmuInstance::loadCheats() @@ -701,9 +697,16 @@ void EmuInstance::loadCheats() std::string filename = getAssetPath(false, globalCfg.GetString("CheatFilePath"), ".mch"); // TODO: check for error (malformed cheat file, ...) - cheatFile = new ARCodeFile(filename); + cheatFile = std::make_unique(filename); - nds->AREngine.SetCodeFile(cheatsOn ? cheatFile : nullptr); + if (cheatsOn) + { + nds->AREngine.Cheats = cheatFile->GetCodes(); + } + else + { + nds->AREngine.Cheats.clear(); + } } std::unique_ptr EmuInstance::loadARM9BIOS() noexcept @@ -1013,12 +1016,14 @@ void EmuInstance::enableCheats(bool enable) { cheatsOn = enable; if (cheatFile) - nds->AREngine.SetCodeFile(cheatsOn ? cheatFile : nullptr); + nds->AREngine.Cheats = cheatFile->GetCodes(); + else + nds->AREngine.Cheats.clear(); } ARCodeFile* EmuInstance::getCheatFile() { - return cheatFile; + return cheatFile.get(); } void EmuInstance::setBatteryLevels() diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 43b9d9ff..34290795 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -256,7 +256,7 @@ private: bool savestateLoaded; std::string previousSaveFile; - melonDS::ARCodeFile* cheatFile; + std::unique_ptr cheatFile; bool cheatsOn; SDL_AudioDeviceID audioDevice;