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
This commit is contained in:
Jesse Talavera 2024-08-01 16:01:00 -04:00 committed by GitHub
parent f3f6a6a194
commit c6bf5d5181
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 45 additions and 37 deletions

View File

@ -33,17 +33,26 @@ ARCodeFile::ARCodeFile(const std::string& filename)
{ {
Filename = filename; Filename = filename;
Error = false;
Categories.clear();
if (!Load()) if (!Load())
Error = true; Error = true;
} }
ARCodeFile::~ARCodeFile() std::vector<ARCode> ARCodeFile::GetCodes() const noexcept
{ {
Categories.clear(); if (Error)
return {};
std::vector<ARCode> codes;
for (const ARCodeCat& cat : Categories)
{
for (const ARCode& code : cat.Codes)
{
codes.push_back(code);
}
}
return codes;
} }
bool ARCodeFile::Load() bool ARCodeFile::Load()

View File

@ -48,14 +48,16 @@ class ARCodeFile
{ {
public: public:
ARCodeFile(const std::string& filename); ARCodeFile(const std::string& filename);
~ARCodeFile(); ~ARCodeFile() noexcept = default;
bool Error; [[nodiscard]] std::vector<ARCode> GetCodes() const noexcept;
bool Error = false;
bool Load(); bool Load();
bool Save(); bool Save();
ARCodeCatList Categories; ARCodeCatList Categories {};
private: private:
std::string Filename; std::string Filename;

View File

@ -31,7 +31,6 @@ using Platform::LogLevel;
AREngine::AREngine(melonDS::NDS& nds) : NDS(nds) AREngine::AREngine(melonDS::NDS& nds) : NDS(nds)
{ {
CodeFile = nullptr;
} }
#define case16(x) \ #define case16(x) \
@ -388,19 +387,12 @@ void AREngine::RunCheat(const ARCode& arcode)
void AREngine::RunCheats() 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) if (code.Enabled)
RunCheat(code); RunCheat(code);
} }
}
} }
} }

View File

@ -19,6 +19,7 @@
#ifndef ARENGINE_H #ifndef ARENGINE_H
#define ARENGINE_H #define ARENGINE_H
#include <vector>
#include "ARCodeFile.h" #include "ARCodeFile.h"
namespace melonDS namespace melonDS
@ -29,14 +30,13 @@ class AREngine
public: public:
AREngine(melonDS::NDS& nds); AREngine(melonDS::NDS& nds);
ARCodeFile* GetCodeFile() { return CodeFile; } std::vector<ARCode> Cheats {};
void SetCodeFile(ARCodeFile* file) { CodeFile = file; } private:
friend class ARM;
void RunCheats(); void RunCheats();
void RunCheat(const ARCode& arcode); void RunCheat(const ARCode& arcode);
private:
melonDS::NDS& NDS; melonDS::NDS& NDS;
ARCodeFile* CodeFile; // AR code file - frontend is responsible for managing this
}; };
} }

View File

@ -686,12 +686,8 @@ void EmuInstance::undoStateLoad()
void EmuInstance::unloadCheats() void EmuInstance::unloadCheats()
{ {
if (cheatFile) cheatFile = nullptr; // cleaned up by unique_ptr
{ nds->AREngine.Cheats.clear();
delete cheatFile;
cheatFile = nullptr;
nds->AREngine.SetCodeFile(nullptr);
}
} }
void EmuInstance::loadCheats() void EmuInstance::loadCheats()
@ -701,9 +697,16 @@ void EmuInstance::loadCheats()
std::string filename = getAssetPath(false, globalCfg.GetString("CheatFilePath"), ".mch"); std::string filename = getAssetPath(false, globalCfg.GetString("CheatFilePath"), ".mch");
// TODO: check for error (malformed cheat file, ...) // TODO: check for error (malformed cheat file, ...)
cheatFile = new ARCodeFile(filename); cheatFile = std::make_unique<ARCodeFile>(filename);
nds->AREngine.SetCodeFile(cheatsOn ? cheatFile : nullptr); if (cheatsOn)
{
nds->AREngine.Cheats = cheatFile->GetCodes();
}
else
{
nds->AREngine.Cheats.clear();
}
} }
std::unique_ptr<ARM9BIOSImage> EmuInstance::loadARM9BIOS() noexcept std::unique_ptr<ARM9BIOSImage> EmuInstance::loadARM9BIOS() noexcept
@ -1013,12 +1016,14 @@ void EmuInstance::enableCheats(bool enable)
{ {
cheatsOn = enable; cheatsOn = enable;
if (cheatFile) if (cheatFile)
nds->AREngine.SetCodeFile(cheatsOn ? cheatFile : nullptr); nds->AREngine.Cheats = cheatFile->GetCodes();
else
nds->AREngine.Cheats.clear();
} }
ARCodeFile* EmuInstance::getCheatFile() ARCodeFile* EmuInstance::getCheatFile()
{ {
return cheatFile; return cheatFile.get();
} }
void EmuInstance::setBatteryLevels() void EmuInstance::setBatteryLevels()

View File

@ -256,7 +256,7 @@ private:
bool savestateLoaded; bool savestateLoaded;
std::string previousSaveFile; std::string previousSaveFile;
melonDS::ARCodeFile* cheatFile; std::unique_ptr<melonDS::ARCodeFile> cheatFile;
bool cheatsOn; bool cheatsOn;
SDL_AudioDeviceID audioDevice; SDL_AudioDeviceID audioDevice;