CheatsManager: Improve performance of searching & add input validation
The previous implementation of cheat search would reconvert the input string for every single memory value. Now we do it once and construct a comparison lambda which we pass to the search code. In addition, I also added input validation. So, for example, if you've selected Decimal input and you try to compare against "FF", it won't search and will instead let the user know they've entered an invalid value. Similar logic for if you enter "1.2" in a search for bytes. Before, it would just use 0 if it failed to convert the value.
This commit is contained in:
parent
526698d2fc
commit
4ce7079098
|
@ -454,46 +454,101 @@ 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));
|
||||
|
||||
// String only supports equals and not equals comparisons because the other ones frankly don't
|
||||
// make any sense here
|
||||
switch (op)
|
||||
if (op != CompareType::Equal && op != CompareType::NotEqual)
|
||||
{
|
||||
case CompareType::Equal:
|
||||
return is_equal;
|
||||
case CompareType::NotEqual:
|
||||
return !is_equal;
|
||||
default:
|
||||
return false;
|
||||
m_result_label->setText(tr("String values can only be compared using equality."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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:
|
||||
return is_equal;
|
||||
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