diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index f2fdd5a058..40868e5efc 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -505,6 +505,23 @@ bool Cheats::CheatSearchSession::WasFirstSearchDone() const return m_first_search_done; } +template +bool Cheats::CheatSearchSession::WriteValue(const Core::CPUThreadGuard& guard, + std::span addresses) const +{ + if (!m_value) + return false; + + T value = m_value.value(); + bool result = true; + for (auto address : addresses) + { + if (!PowerPC::MMU::HostTryWrite(guard, value, address, m_address_space).has_value()) + result = false; + } + return result; +} + template std::unique_ptr Cheats::CheatSearchSession::Clone() const { diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index bd3c6f3598..6c6d509047 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -165,6 +166,8 @@ public: virtual SearchResultValueState GetResultValueState(size_t index) const = 0; virtual bool WasFirstSearchDone() const = 0; + virtual bool WriteValue(const Core::CPUThreadGuard& guard, std::span addresses) const = 0; + // Create a complete copy of this search session. virtual std::unique_ptr Clone() const = 0; @@ -212,6 +215,8 @@ public: SearchResultValueState GetResultValueState(size_t index) const override; bool WasFirstSearchDone() const override; + bool WriteValue(const Core::CPUThreadGuard& guard, std::span addresses) const override; + std::unique_ptr Clone() const override; std::unique_ptr ClonePartial(size_t begin_index, size_t end_index) const override; diff --git a/Source/Core/DolphinQt/CheatSearchWidget.cpp b/Source/Core/DolphinQt/CheatSearchWidget.cpp index 609f03b808..2b25256c33 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.cpp +++ b/Source/Core/DolphinQt/CheatSearchWidget.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -491,13 +492,14 @@ void CheatSearchWidget::OnAddressTableContextMenu() if (m_address_table->selectedItems().isEmpty()) return; - auto* item = m_address_table->selectedItems()[0]; - const u32 address = item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); - QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose, true); - menu->addAction(tr("Show in memory"), [this, address] { emit ShowMemory(address); }); + menu->addAction(tr("Show in memory"), this, [this] { + auto* item = m_address_table->selectedItems()[0]; + const u32 address = item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); + emit ShowMemory(address); + }); menu->addAction(tr("Add to watch"), this, [this] { for (auto* const item : m_address_table->selectedItems()) { @@ -507,6 +509,7 @@ void CheatSearchWidget::OnAddressTableContextMenu() } }); menu->addAction(tr("Generate Action Replay Code(s)"), this, &CheatSearchWidget::GenerateARCodes); + menu->addAction(tr("Write value"), this, &CheatSearchWidget::WriteValue); menu->exec(QCursor::pos()); } @@ -589,10 +592,40 @@ void CheatSearchWidget::GenerateARCodes() } } +void CheatSearchWidget::WriteValue() +{ + if (m_address_table->selectedItems().isEmpty()) + return; + + bool ok{}; + QString text = QInputDialog::getText(this, tr("Write value"), tr("Value:"), QLineEdit::Normal, + QString{}, &ok); + + if (ok && m_session->SetValueFromString(text.toStdString(), + m_parse_values_as_hex_checkbox->isChecked())) + { + auto items = m_address_table->selectedItems(); + std::vector addresses(items.size()); + std::transform(items.begin(), items.end(), addresses.begin(), [](QTableWidgetItem* item) { + return item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); + }); + + Core::CPUThreadGuard guard{m_system}; + if (!m_session->WriteValue(guard, std::span(addresses))) + { + m_info_label_1->setText(tr("There was an error writing (some) values.")); + } + } + else + { + m_info_label_1->setText(tr("Invalid value.")); + } +} + void CheatSearchWidget::RefreshCurrentValueTableItem( QTableWidgetItem* const current_value_table_item) { - const auto address = current_value_table_item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); + const u32 address = current_value_table_item->data(ADDRESS_TABLE_ADDRESS_ROLE).toUInt(); const auto curr_val_iter = m_address_table_current_values.find(address); if (curr_val_iter != m_address_table_current_values.end()) current_value_table_item->setText(QString::fromStdString(curr_val_iter->second)); diff --git a/Source/Core/DolphinQt/CheatSearchWidget.h b/Source/Core/DolphinQt/CheatSearchWidget.h index f7427ca6a6..cb953c5aca 100644 --- a/Source/Core/DolphinQt/CheatSearchWidget.h +++ b/Source/Core/DolphinQt/CheatSearchWidget.h @@ -71,6 +71,7 @@ private: UpdateSource source); void RecreateGUITable(); void GenerateARCodes(); + void WriteValue(); int GetVisibleRowsBeginIndex() const; int GetVisibleRowsEndIndex() const;