Merge pull request #7448 from RolandMunsil/improve-cheat-search
Improve performance of cheat searching & add input validation
This commit is contained in:
commit
f819ea687a
|
@ -454,33 +454,81 @@ size_t CheatsManager::GetTypeSize() const
|
|||
}
|
||||
}
|
||||
|
||||
bool CheatsManager::MatchesSearch(u32 addr) const
|
||||
std::function<bool(u32)> CheatsManager::CreateMatchFunction()
|
||||
{
|
||||
const auto text = m_match_value->text();
|
||||
const auto op = static_cast<CompareType>(m_match_operation->currentIndex());
|
||||
const QString text = m_match_value->text();
|
||||
|
||||
if (text.isEmpty())
|
||||
{
|
||||
m_result_label->setText(tr("No search value entered."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CompareType op = static_cast<CompareType>(m_match_operation->currentIndex());
|
||||
|
||||
const int base =
|
||||
(m_match_decimal->isChecked() ? 10 : (m_match_hexadecimal->isChecked() ? 16 : 8));
|
||||
|
||||
bool conversion_succeeded = false;
|
||||
std::function<bool(u32)> matches_func;
|
||||
switch (static_cast<DataType>(m_match_length->currentIndex()))
|
||||
{
|
||||
case DataType::Byte:
|
||||
return Compare<u8>(PowerPC::HostRead_U8(addr), text.toUShort(nullptr, base) & 0xFF, op);
|
||||
{
|
||||
u8 comparison_value = text.toUShort(&conversion_succeeded, base) & 0xFF;
|
||||
matches_func = [=](u32 addr) {
|
||||
return Compare<u8>(PowerPC::HostRead_U8(addr), comparison_value, op);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case DataType::Short:
|
||||
return Compare(PowerPC::HostRead_U16(addr), text.toUShort(nullptr, base), op);
|
||||
{
|
||||
u16 comparison_value = text.toUShort(&conversion_succeeded, base);
|
||||
matches_func = [=](u32 addr) {
|
||||
return Compare(PowerPC::HostRead_U16(addr), comparison_value, op);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case DataType::Int:
|
||||
return Compare(PowerPC::HostRead_U32(addr), text.toUInt(nullptr, base), op);
|
||||
{
|
||||
u32 comparison_value = text.toUInt(&conversion_succeeded, base);
|
||||
matches_func = [=](u32 addr) {
|
||||
return Compare(PowerPC::HostRead_U32(addr), comparison_value, op);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case DataType::Float:
|
||||
return Compare(PowerPC::HostRead_F32(addr), text.toFloat(), op);
|
||||
{
|
||||
float comparison_value = text.toFloat(&conversion_succeeded);
|
||||
matches_func = [=](u32 addr) {
|
||||
return Compare(PowerPC::HostRead_F32(addr), comparison_value, op);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case DataType::Double:
|
||||
return Compare(PowerPC::HostRead_F64(addr), text.toDouble(), op);
|
||||
{
|
||||
double comparison_value = text.toDouble(&conversion_succeeded);
|
||||
matches_func = [=](u32 addr) {
|
||||
return Compare(PowerPC::HostRead_F64(addr), comparison_value, op);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case DataType::String:
|
||||
{
|
||||
bool is_equal = std::equal(text.toUtf8().cbegin(), text.toUtf8().cend(),
|
||||
reinterpret_cast<char*>(Memory::m_pRAM + addr - 0x80000000));
|
||||
if (op != CompareType::Equal && op != CompareType::NotEqual)
|
||||
{
|
||||
m_result_label->setText(tr("String values can only be compared using equality."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// String only supports equals and not equals comparisons because the other ones frankly don't
|
||||
// make any sense here
|
||||
conversion_succeeded = true;
|
||||
|
||||
const QString lambda_text = m_match_value->text();
|
||||
const QByteArray utf8_bytes = lambda_text.toUtf8();
|
||||
|
||||
matches_func = [op, utf8_bytes](u32 addr) {
|
||||
bool is_equal = std::equal(utf8_bytes.cbegin(), utf8_bytes.cend(),
|
||||
reinterpret_cast<char*>(Memory::m_pRAM + addr - 0x80000000));
|
||||
switch (op)
|
||||
{
|
||||
case CompareType::Equal:
|
||||
|
@ -488,12 +536,19 @@ bool CheatsManager::MatchesSearch(u32 addr) const
|
|||
case CompareType::NotEqual:
|
||||
return !is_equal;
|
||||
default:
|
||||
// This should never occur since we've already checked the type of op
|
||||
return false;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
if (conversion_succeeded)
|
||||
return matches_func;
|
||||
|
||||
m_result_label->setText(tr("Cannot interpret the given value.\nHave you chosen the right type?"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CheatsManager::NewSearch()
|
||||
|
@ -507,10 +562,14 @@ void CheatsManager::NewSearch()
|
|||
return;
|
||||
}
|
||||
|
||||
std::function<bool(u32)> matches_func = CreateMatchFunction();
|
||||
if (matches_func == nullptr)
|
||||
return;
|
||||
|
||||
Core::RunAsCPUThread([&] {
|
||||
for (u32 i = 0; i < Memory::REALRAM_SIZE - GetTypeSize(); i++)
|
||||
{
|
||||
if (PowerPC::HostIsRAMAddress(base_address + i) && MatchesSearch(base_address + i))
|
||||
if (PowerPC::HostIsRAMAddress(base_address + i) && matches_func(base_address + i))
|
||||
m_results.push_back(
|
||||
{base_address + i, static_cast<DataType>(m_match_length->currentIndex())});
|
||||
}
|
||||
|
@ -529,11 +588,15 @@ void CheatsManager::NextSearch()
|
|||
return;
|
||||
}
|
||||
|
||||
Core::RunAsCPUThread([this] {
|
||||
std::function<bool(u32)> matches_func = CreateMatchFunction();
|
||||
if (matches_func == nullptr)
|
||||
return;
|
||||
|
||||
Core::RunAsCPUThread([this, matches_func] {
|
||||
m_results.erase(std::remove_if(m_results.begin(), m_results.end(),
|
||||
[this](Result r) {
|
||||
[matches_func](Result r) {
|
||||
return !PowerPC::HostIsRAMAddress(r.address) ||
|
||||
!MatchesSearch(r.address);
|
||||
!matches_func(r.address);
|
||||
}),
|
||||
m_results.end());
|
||||
});
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
@ -48,7 +49,7 @@ private:
|
|||
void OnStateChanged(Core::State state);
|
||||
|
||||
size_t GetTypeSize() const;
|
||||
bool MatchesSearch(u32 addr) const;
|
||||
std::function<bool(u32)> CreateMatchFunction();
|
||||
|
||||
void Reset();
|
||||
void NewSearch();
|
||||
|
|
Loading…
Reference in New Issue