mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
Merge pull request #328 from hydra-emu/cheats
Make cheats struct more versatile
This commit is contained in:
commit
5984c27960
4 changed files with 96 additions and 11 deletions
|
@ -12,17 +12,21 @@ class Memory;
|
||||||
class Cheats {
|
class Cheats {
|
||||||
public:
|
public:
|
||||||
enum class CheatType {
|
enum class CheatType {
|
||||||
|
None, // Cheat has been removed by the frontend or is invalid
|
||||||
ActionReplay, // CTRPF cheats
|
ActionReplay, // CTRPF cheats
|
||||||
// TODO: Other cheat devices and standards?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Cheat {
|
struct Cheat {
|
||||||
CheatType type;
|
bool enabled = true;
|
||||||
|
CheatType type = CheatType::ActionReplay;
|
||||||
std::vector<u32> instructions;
|
std::vector<u32> instructions;
|
||||||
};
|
};
|
||||||
|
|
||||||
Cheats(Memory& mem, HIDService& hid);
|
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 reset();
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -7,9 +7,49 @@ void Cheats::reset() {
|
||||||
ar.reset(); // Reset ActionReplay
|
ar.reset(); // Reset ActionReplay
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cheats::addCheat(const Cheat& cheat) {
|
u32 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(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() {
|
void Cheats::clear() {
|
||||||
|
@ -19,12 +59,15 @@ 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);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CheatType::None: break;
|
||||||
default: Helpers::panic("Unknown cheat device!");
|
default: Helpers::panic("Unknown cheat device!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -25,11 +30,17 @@ class HC_GLOBAL HydraCore final : public hydra::IBase, public hydra::IOpenGlRend
|
||||||
|
|
||||||
// IFrontendDriven
|
// IFrontendDriven
|
||||||
void runFrame() override;
|
void runFrame() override;
|
||||||
uint16_t getFps() override;
|
u16 getFps() override;
|
||||||
|
|
||||||
// IInput
|
// IInput
|
||||||
void setPollInputCallback(void (*callback)()) override;
|
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;
|
std::unique_ptr<Emulator> emulator;
|
||||||
RendererGL* renderer;
|
RendererGL* renderer;
|
||||||
|
@ -93,7 +104,7 @@ void HydraCore::runFrame() {
|
||||||
emulator->runFrame();
|
emulator->runFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t HydraCore::getFps() { return 60; }
|
u16 HydraCore::getFps() { return 60; }
|
||||||
|
|
||||||
void HydraCore::reset() { emulator->reset(Emulator::ReloadOption::Reload); }
|
void HydraCore::reset() { emulator->reset(Emulator::ReloadOption::Reload); }
|
||||||
hydra::Size HydraCore::getNativeSize() { return {400, 480}; }
|
hydra::Size HydraCore::getNativeSize() { return {400, 480}; }
|
||||||
|
@ -120,7 +131,33 @@ void HydraCore::setFbo(unsigned handle) { renderer->setFBO(handle); }
|
||||||
void HydraCore::setGetProcAddress(void* function) { getProcAddress = function; }
|
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(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 hydra::IBase* createEmulator() { return new HydraCore(); }
|
||||||
HC_API void destroyEmulator(hydra::IBase* emulator) { delete emulator; }
|
HC_API void destroyEmulator(hydra::IBase* emulator) { delete emulator; }
|
||||||
|
|
Loading…
Add table
Reference in a new issue