libretro: Cheat support

This commit is contained in:
Connor McLaughlin 2020-09-25 21:16:33 +10:00
parent 1e6815634a
commit 40037d6e90
6 changed files with 90 additions and 39 deletions

View file

@ -13,6 +13,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c
## Latest News ## Latest News
- 2020/09/25: Cheat support added for libretro core.
- 2020/09/23: Game covers added to Qt frontend (see [Adding Game Covers](https://github.com/stenzek/duckstation/wiki/Adding-Game-Covers)). - 2020/09/23: Game covers added to Qt frontend (see [Adding Game Covers](https://github.com/stenzek/duckstation/wiki/Adding-Game-Covers)).
- 2020/09/19: Memory card importer/editor added to Qt frontend. - 2020/09/19: Memory card importer/editor added to Qt frontend.
- 2020/09/13: Support for chaining post processing shaders added. - 2020/09/13: Support for chaining post processing shaders added.

View file

@ -196,49 +196,55 @@ bool CheatList::LoadFromLibretroFile(const char* filename)
CheatCode cc; CheatCode cc;
cc.description = *desc; cc.description = *desc;
cc.enabled = StringUtil::FromChars<bool>(*enable).value_or(false); cc.enabled = StringUtil::FromChars<bool>(*enable).value_or(false);
if (ParseLibretroCheat(&cc, code->c_str()))
const char* current_ptr = code->c_str(); m_codes.push_back(std::move(cc));
while (current_ptr)
{
char* end_ptr;
CheatCode::Instruction inst;
inst.first = static_cast<u32>(std::strtoul(current_ptr, &end_ptr, 16));
current_ptr = end_ptr;
if (end_ptr)
{
if (*end_ptr != ' ')
{
Log_WarningPrintf("Malformed code '%s'", code->c_str());
break;
}
end_ptr++;
inst.second = static_cast<u32>(std::strtoul(current_ptr, &end_ptr, 16));
current_ptr = end_ptr;
if (end_ptr)
{
if (*end_ptr != '+')
{
Log_WarningPrintf("Malformed code '%s'", code->c_str());
break;
}
end_ptr++;
current_ptr = end_ptr;
}
cc.instructions.push_back(inst);
}
}
m_codes.push_back(std::move(cc));
} }
Log_InfoPrintf("Loaded %zu cheats from '%s' (libretro format)", m_codes.size(), filename); Log_InfoPrintf("Loaded %zu cheats from '%s' (libretro format)", m_codes.size(), filename);
return !m_codes.empty(); return !m_codes.empty();
} }
bool CheatList::ParseLibretroCheat(CheatCode* cc, const char* line)
{
const char* current_ptr = line;
while (current_ptr)
{
char* end_ptr;
CheatCode::Instruction inst;
inst.first = static_cast<u32>(std::strtoul(current_ptr, &end_ptr, 16));
current_ptr = end_ptr;
if (end_ptr)
{
if (*end_ptr != ' ')
{
Log_WarningPrintf("Malformed code '%s'", line);
break;
}
end_ptr++;
inst.second = static_cast<u32>(std::strtoul(current_ptr, &end_ptr, 16));
if (end_ptr && *end_ptr == '\0')
end_ptr = nullptr;
if (end_ptr)
{
if (*end_ptr != '+')
{
Log_WarningPrintf("Malformed code '%s'", line);
break;
}
end_ptr++;
}
current_ptr = end_ptr;
cc->instructions.push_back(inst);
}
}
return !cc->instructions.empty();
}
void CheatList::Apply() void CheatList::Apply()
{ {
for (const CheatCode& code : m_codes) for (const CheatCode& code : m_codes)
@ -253,6 +259,20 @@ void CheatList::AddCode(CheatCode cc)
m_codes.push_back(std::move(cc)); m_codes.push_back(std::move(cc));
} }
void CheatList::SetCode(u32 index, CheatCode cc)
{
if (index > m_codes.size())
return;
if (index == m_codes.size())
{
m_codes.push_back(std::move(cc));
return;
}
m_codes[index] = std::move(cc);
}
void CheatList::RemoveCode(u32 i) void CheatList::RemoveCode(u32 i)
{ {
m_codes.erase(m_codes.begin() + i); m_codes.erase(m_codes.begin() + i);

View file

@ -71,6 +71,7 @@ public:
ALWAYS_INLINE bool IsCodeEnabled(u32 index) const { return m_codes[index].enabled; } ALWAYS_INLINE bool IsCodeEnabled(u32 index) const { return m_codes[index].enabled; }
void AddCode(CheatCode cc); void AddCode(CheatCode cc);
void SetCode(u32 index, CheatCode cc);
void RemoveCode(u32 i); void RemoveCode(u32 i);
u32 GetEnabledCodeCount() const; u32 GetEnabledCodeCount() const;
@ -79,6 +80,7 @@ public:
void SetCodeEnabled(u32 index, bool state); void SetCodeEnabled(u32 index, bool state);
static std::optional<Format> DetectFileFormat(const char* filename); static std::optional<Format> DetectFileFormat(const char* filename);
static bool ParseLibretroCheat(CheatCode* cc, const char* line);
bool LoadFromFile(const char* filename, Format format); bool LoadFromFile(const char* filename, Format format);
bool LoadFromPCSXRFile(const char* filename); bool LoadFromPCSXRFile(const char* filename);

View file

@ -6,6 +6,7 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/analog_controller.h" #include "core/analog_controller.h"
#include "core/bus.h" #include "core/bus.h"
#include "core/cheats.h"
#include "core/digital_controller.h" #include "core/digital_controller.h"
#include "core/gpu.h" #include "core/gpu.h"
#include "core/system.h" #include "core/system.h"
@ -369,6 +370,29 @@ size_t LibretroHostInterface::retro_get_memory_size(unsigned id)
} }
} }
void LibretroHostInterface::retro_cheat_reset()
{
System::SetCheatList(nullptr);
}
void LibretroHostInterface::retro_cheat_set(unsigned index, bool enabled, const char* code)
{
CheatList* cl = System::GetCheatList();
if (!cl)
{
System::SetCheatList(std::make_unique<CheatList>());
cl = System::GetCheatList();
}
CheatCode cc;
cc.description = StringUtil::StdStringFromFormat("Cheat%u", index);
cc.enabled = true;
if (!CheatList::ParseLibretroCheat(&cc, code))
Log_ErrorPrintf("Failed to parse cheat %u '%s'", index, code);
cl->SetCode(index, std::move(cc));
}
bool LibretroHostInterface::AcquireHostDisplay() bool LibretroHostInterface::AcquireHostDisplay()
{ {
// start in software mode, switch to hardware later // start in software mode, switch to hardware later

View file

@ -40,6 +40,8 @@ public:
bool retro_unserialize(const void* data, size_t size); bool retro_unserialize(const void* data, size_t size);
void* retro_get_memory_data(unsigned id); void* retro_get_memory_data(unsigned id);
size_t retro_get_memory_size(unsigned id); size_t retro_get_memory_size(unsigned id);
void retro_cheat_reset();
void retro_cheat_set(unsigned index, bool enabled, const char* code);
protected: protected:
bool AcquireHostDisplay() override; bool AcquireHostDisplay() override;

View file

@ -79,12 +79,14 @@ RETRO_API bool retro_unserialize(const void* data, size_t size)
RETRO_API void retro_cheat_reset(void) RETRO_API void retro_cheat_reset(void)
{ {
Log_ErrorPrintf("retro_cheat_reset()"); Log_InfoPrint("retro_cheat_reset()");
g_libretro_host_interface.retro_cheat_reset();
} }
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char* code) RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char* code)
{ {
Log_ErrorPrintf("retro_cheat_set(%u, %u, %s)", index, enabled, code); Log_InfoPrintf("retro_cheat_set(%u, %u, %s)", index, enabled, code);
g_libretro_host_interface.retro_cheat_set(index, enabled, code);
} }
RETRO_API bool retro_load_game(const struct retro_game_info* game) RETRO_API bool retro_load_game(const struct retro_game_info* game)