Skip to content

Commit

Permalink
Merge pull request #328 from hydra-emu/cheats
Browse files Browse the repository at this point in the history
Make cheats struct more versatile
  • Loading branch information
wheremyfoodat authored Oct 29, 2023
2 parents d4a84c3 + 8b6008e commit 5984c27
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 11 deletions.
12 changes: 8 additions & 4 deletions include/cheats.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ class Memory;
class Cheats {
public:
enum class CheatType {
None, // Cheat has been removed by the frontend or is invalid
ActionReplay, // CTRPF cheats
// TODO: Other cheat devices and standards?
};

struct Cheat {
CheatType type;
bool enabled = true;
CheatType type = CheatType::ActionReplay;
std::vector<u32> instructions;
};

Cheats(Memory& mem, HIDService& hid);
void addCheat(const Cheat& cheat);
u32 addCheat(const Cheat& cheat);
void removeCheat(u32 id);
void enableCheat(u32 id);
void disableCheat(u32 id);
void reset();
void run();

Expand All @@ -33,4 +37,4 @@ class Cheats {
ActionReplay ar; // An ActionReplay cheat machine for executing CTRPF codes
std::vector<Cheat> cheats;
bool cheatsLoaded = false;
};
};
1 change: 1 addition & 0 deletions include/emulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class Emulator {
void deinitGraphicsContext() { gpu.deinitGraphicsContext(); }

EmulatorConfig& getConfig() { return config; }
Cheats& getCheats() { return cheats; }
ServiceManager& getServiceManager() { return kernel.getServiceManager(); }
RendererType getRendererType() const { return config.rendererType; }
Renderer* getRenderer() { return gpu.getRenderer(); }
Expand Down
47 changes: 45 additions & 2 deletions src/core/cheats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,49 @@ void Cheats::reset() {
ar.reset(); // Reset ActionReplay
}

void Cheats::addCheat(const Cheat& cheat) {
cheats.push_back(cheat);
u32 Cheats::addCheat(const Cheat& cheat) {
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(u32 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(u32 id) {
if (id < cheats.size()) {
cheats[id].enabled = true;
}
}

void Cheats::disableCheat(u32 id) {
if (id < cheats.size()) {
cheats[id].enabled = false;
}
}

void Cheats::clear() {
Expand All @@ -19,12 +59,15 @@ void Cheats::clear() {

void Cheats::run() {
for (const Cheat& cheat : cheats) {
if (!cheat.enabled) continue;

switch (cheat.type) {
case CheatType::ActionReplay: {
ar.runCheat(cheat.instructions);
break;
}

case CheatType::None: break;
default: Helpers::panic("Unknown cheat device!");
}
}
Expand Down
47 changes: 42 additions & 5 deletions src/hydra_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
#include <stdexcept>

#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
public:
HydraCore();
Expand All @@ -25,11 +30,17 @@ class HC_GLOBAL HydraCore final : public hydra::IBase, public hydra::IOpenGlRend

// IFrontendDriven
void runFrame() override;
uint16_t getFps() override;
u16 getFps() override;

// IInput
void setPollInputCallback(void (*callback)()) override;
void setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) override;
void setCheckButtonCallback(s32 (*callback)(u32 player, hydra::ButtonType button)) override;

// ICheat
u32 addCheat(const u8* data, u32 size) override;
void removeCheat(u32 id) override;
void enableCheat(u32 id) override;
void disableCheat(u32 id) override;

std::unique_ptr<Emulator> emulator;
RendererGL* renderer;
Expand Down Expand Up @@ -93,7 +104,7 @@ void HydraCore::runFrame() {
emulator->runFrame();
}

uint16_t HydraCore::getFps() { return 60; }
u16 HydraCore::getFps() { return 60; }

void HydraCore::reset() { emulator->reset(Emulator::ReloadOption::Reload); }
hydra::Size HydraCore::getNativeSize() { return {400, 480}; }
Expand All @@ -120,7 +131,33 @@ void HydraCore::setFbo(unsigned handle) { renderer->setFBO(handle); }
void HydraCore::setGetProcAddress(void* function) { getProcAddress = function; }

void HydraCore::setPollInputCallback(void (*callback)()) { pollInputCallback = callback; }
void HydraCore::setCheckButtonCallback(int32_t (*callback)(uint32_t player, hydra::ButtonType button)) { checkButtonCallback = callback; }
void HydraCore::setCheckButtonCallback(s32 (*callback)(u32 player, hydra::ButtonType button)) { checkButtonCallback = callback; }

u32 HydraCore::addCheat(const u8* data, u32 size) {
// Every 3DS cheat is a multiple of 64 bits == 8 bytes
if ((size % 8) != 0) {
return hydra::BAD_CHEAT;
}

Cheats::Cheat cheat;
cheat.enabled = true;
cheat.type = Cheats::CheatType::ActionReplay;

for (u32 i = 0; i < size; i += 8) {
auto read32 = [](const u8* ptr) { return (u32(ptr[3]) << 24) | (u32(ptr[2]) << 16) | (u32(ptr[1]) << 8) | u32(ptr[0]); };

// Data is passed to us in big endian so we bswap
u32 firstWord = Common::swap32(read32(data + i));
u32 secondWord = Common::swap32(read32(data + i + 4));
cheat.instructions.insert(cheat.instructions.end(), {firstWord, secondWord});
}

return emulator->getCheats().addCheat(cheat);
};

void HydraCore::removeCheat(u32 id) { emulator->getCheats().removeCheat(id); }
void HydraCore::enableCheat(u32 id) { emulator->getCheats().enableCheat(id); }
void HydraCore::disableCheat(u32 id) { emulator->getCheats().disableCheat(id); }

HC_API hydra::IBase* createEmulator() { return new HydraCore(); }
HC_API void destroyEmulator(hydra::IBase* emulator) { delete emulator; }
Expand Down

0 comments on commit 5984c27

Please sign in to comment.