mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 15:45:42 +00:00
libretro: Cheat support
This commit is contained in:
parent
1e6815634a
commit
40037d6e90
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue