Make cheats struct more versatile

This commit is contained in:
offtkp 2023-10-24 16:52:08 +03:00
parent d4a84c337e
commit 7e7d4f7f16
4 changed files with 82 additions and 5 deletions

View file

@ -12,17 +12,22 @@ class Memory;
class Cheats { class Cheats {
public: public:
enum class CheatType { enum class CheatType {
None,
ActionReplay, // CTRPF cheats ActionReplay, // CTRPF cheats
// TODO: Other cheat devices and standards? // TODO: Other cheat devices and standards?
}; };
struct Cheat { struct Cheat {
bool enabled;
CheatType type; CheatType type;
std::vector<u32> instructions; std::vector<u32> instructions;
}; };
Cheats(Memory& mem, HIDService& hid); Cheats(Memory& mem, HIDService& hid);
void addCheat(const Cheat& cheat); uint32_t addCheat(const Cheat& cheat);
void removeCheat(uint32_t id);
void enableCheat(uint32_t id);
void disableCheat(uint32_t id);
void reset(); void reset();
void run(); void run();

View file

@ -115,6 +115,7 @@ class Emulator {
void deinitGraphicsContext() { gpu.deinitGraphicsContext(); } void deinitGraphicsContext() { gpu.deinitGraphicsContext(); }
EmulatorConfig& getConfig() { return config; } EmulatorConfig& getConfig() { return config; }
Cheats& getCheats() { return cheats; }
ServiceManager& getServiceManager() { return kernel.getServiceManager(); } ServiceManager& getServiceManager() { return kernel.getServiceManager(); }
RendererType getRendererType() const { return config.rendererType; } RendererType getRendererType() const { return config.rendererType; }
Renderer* getRenderer() { return gpu.getRenderer(); } Renderer* getRenderer() { return gpu.getRenderer(); }

View file

@ -7,9 +7,45 @@ void Cheats::reset() {
ar.reset(); // Reset ActionReplay ar.reset(); // Reset ActionReplay
} }
void Cheats::addCheat(const Cheat& cheat) { uint32_t Cheats::addCheat(const Cheat& cheat) {
cheats.push_back(cheat);
cheatsLoaded = true; cheatsLoaded = true;
// Find an empty slot if a cheat was previously removed
for (size_t i = 0; i < cheats.size(); i++) {
if (cheats[i].type == CheatType::None) {
cheats[i] = cheat;
return i;
}
}
// Otherwise, just add a new slot
cheats.push_back(cheat);
return cheats.size() - 1;
}
void Cheats::removeCheat(uint32_t id) {
if (id >= cheats.size()) return;
// Not using std::erase because we don't want to invalidate cheat IDs
cheats[id].type = CheatType::None;
cheats[id].instructions.clear();
// Check if no cheats are loaded
for (const auto& cheat : cheats) {
if (cheat.type != CheatType::None) return;
}
cheatsLoaded = false;
}
void Cheats::enableCheat(uint32_t id) {
if (id >= cheats.size()) return;
cheats[id].enabled = true;
}
void Cheats::disableCheat(uint32_t id) {
if (id >= cheats.size()) return;
cheats[id].enabled = false;
} }
void Cheats::clear() { void Cheats::clear() {
@ -19,6 +55,8 @@ void Cheats::clear() {
void Cheats::run() { void Cheats::run() {
for (const Cheat& cheat : cheats) { for (const Cheat& cheat : cheats) {
if (!cheat.enabled) continue;
switch (cheat.type) { switch (cheat.type) {
case CheatType::ActionReplay: { case CheatType::ActionReplay: {
ar.runCheat(cheat.instructions); ar.runCheat(cheat.instructions);

View file

@ -4,8 +4,13 @@
#include <stdexcept> #include <stdexcept>
#include "hydra_icon.hpp" #include "hydra_icon.hpp"
#include "swap.hpp"
class HC_GLOBAL HydraCore final : public hydra::IBase, public hydra::IOpenGlRendered, public hydra::IFrontendDriven, public hydra::IInput { class HC_GLOBAL HydraCore final : public hydra::IBase,
public hydra::IOpenGlRendered,
public hydra::IFrontendDriven,
public hydra::IInput,
public hydra::ICheat {
HYDRA_CLASS HYDRA_CLASS
public: public:
HydraCore(); HydraCore();
@ -31,6 +36,12 @@ class HC_GLOBAL HydraCore final : public hydra::IBase, public hydra::IOpenGlRend
void setPollInputCallback(void (*callback)()) override; void setPollInputCallback(void (*callback)()) override;
void setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) override; void setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) override;
// ICheat
uint32_t addCheat(const uint8_t* data, uint32_t size) override;
void removeCheat(uint32_t id) override;
void enableCheat(uint32_t id) override;
void disableCheat(uint32_t id) override;
std::unique_ptr<Emulator> emulator; std::unique_ptr<Emulator> emulator;
RendererGL* renderer; RendererGL* renderer;
void (*pollInputCallback)() = nullptr; void (*pollInputCallback)() = nullptr;
@ -122,7 +133,29 @@ void HydraCore::setGetProcAddress(void* function) { getProcAddress = function; }
void HydraCore::setPollInputCallback(void (*callback)()) { pollInputCallback = callback; } void HydraCore::setPollInputCallback(void (*callback)()) { pollInputCallback = callback; }
void HydraCore::setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) { checkButtonCallback = callback; } void HydraCore::setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) { checkButtonCallback = callback; }
HC_API hydra::IBase* createEmulator() { return new HydraCore(); } uint32_t HydraCore::addCheat(const uint8_t* data, uint32_t size) {
if ((size % 8) != 0) return hydra::BAD_CHEAT;
Cheats::Cheat cheat;
cheat.enabled = true;
cheat.type = Cheats::CheatType::ActionReplay;
for (uint32_t i = 0; i < size; i += 8) {
uint32_t first_word = Common::swap32(*reinterpret_cast<const uint32_t*>(data + i));
uint32_t second_word = Common::swap32(*reinterpret_cast<const uint32_t*>(data + i + 4));
cheat.instructions.insert(cheat.instructions.end(), {first_word, second_word});
}
return emulator->getCheats().addCheat(cheat);
};
void HydraCore::removeCheat(uint32_t id) { emulator->getCheats().removeCheat(id); }
void HydraCore::enableCheat(uint32_t id) { emulator->getCheats().enableCheat(id); }
void HydraCore::disableCheat(uint32_t id) { emulator->getCheats().disableCheat(id); }
HC_API hydra::IBase* createEmulator() { return new HydraCore; }
HC_API void destroyEmulator(hydra::IBase* emulator) { delete emulator; } HC_API void destroyEmulator(hydra::IBase* emulator) { delete emulator; }
HC_API const char* getInfo(hydra::InfoType type) { HC_API const char* getInfo(hydra::InfoType type) {