Core: Allow overriding the enabling of a code

If we want to enable codes in the default game INIs,
we should have some way for users to disable them.
This commit accomplishes that by adding a *_Disabled
section corresponding to each *_Enabled section.
This commit is contained in:
JosJuice 2020-12-10 12:58:27 +01:00
parent 3328eb4523
commit 366cfd0f8c
14 changed files with 68 additions and 69 deletions

View File

@ -26,7 +26,6 @@
#include <iterator> #include <iterator>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -39,6 +38,7 @@
#include "Common/MsgHandler.h" #include "Common/MsgHandler.h"
#include "Core/ARDecrypt.h" #include "Core/ARDecrypt.h"
#include "Core/CheatCodes.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
@ -120,7 +120,7 @@ void ApplyCodes(const std::vector<ARCode>& codes)
s_disable_logging = false; s_disable_logging = false;
s_active_codes.clear(); s_active_codes.clear();
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes),
[](const ARCode& code) { return code.active; }); [](const ARCode& code) { return code.enabled; });
s_active_codes.shrink_to_fit(); s_active_codes.shrink_to_fit();
} }
@ -136,7 +136,7 @@ void UpdateSyncedCodes(const std::vector<ARCode>& codes)
s_synced_codes.clear(); s_synced_codes.clear();
s_synced_codes.reserve(codes.size()); s_synced_codes.reserve(codes.size());
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_synced_codes), std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_synced_codes),
[](const ARCode& code) { return code.active; }); [](const ARCode& code) { return code.enabled; });
s_synced_codes.shrink_to_fit(); s_synced_codes.shrink_to_fit();
} }
@ -148,7 +148,7 @@ std::vector<ARCode> ApplyAndReturnCodes(const std::vector<ARCode>& codes)
s_disable_logging = false; s_disable_logging = false;
s_active_codes.clear(); s_active_codes.clear();
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes),
[](const ARCode& code) { return code.active; }); [](const ARCode& code) { return code.enabled; });
} }
s_active_codes.shrink_to_fit(); s_active_codes.shrink_to_fit();
@ -160,7 +160,7 @@ void AddCode(ARCode code)
if (!SConfig::GetInstance().bEnableCheats) if (!SConfig::GetInstance().bEnableCheats)
return; return;
if (code.active) if (code.enabled)
{ {
std::lock_guard<std::mutex> guard(s_lock); std::lock_guard<std::mutex> guard(s_lock);
s_disable_logging = false; s_disable_logging = false;
@ -178,20 +178,6 @@ std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_in
{ {
std::vector<ARCode> codes; std::vector<ARCode> codes;
std::unordered_set<std::string> enabled_names;
{
std::vector<std::string> enabled_lines;
local_ini.GetLines("ActionReplay_Enabled", &enabled_lines);
for (const std::string& line : enabled_lines)
{
if (!line.empty() && line[0] == '$')
{
std::string name = line.substr(1, line.size() - 1);
enabled_names.insert(name);
}
}
}
const IniFile* inis[2] = {&global_ini, &local_ini}; const IniFile* inis[2] = {&global_ini, &local_ini};
for (const IniFile* ini : inis) for (const IniFile* ini : inis)
{ {
@ -225,7 +211,6 @@ std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_in
} }
current_code.name = line.substr(1, line.size() - 1); current_code.name = line.substr(1, line.size() - 1);
current_code.active = enabled_names.find(current_code.name) != enabled_names.end();
current_code.user_defined = (ini == &local_ini); current_code.user_defined = (ini == &local_ini);
} }
else else
@ -279,6 +264,8 @@ std::vector<ARCode> LoadCodes(const IniFile& global_ini, const IniFile& local_in
DecryptARCode(encrypted_lines, &current_code.ops); DecryptARCode(encrypted_lines, &current_code.ops);
codes.push_back(current_code); codes.push_back(current_code);
} }
ReadEnabledAndDisabled(*ini, "ActionReplay", &codes);
} }
return codes; return codes;
@ -290,7 +277,7 @@ void SaveCodes(IniFile* local_ini, const std::vector<ARCode>& codes)
std::vector<std::string> enabled_lines; std::vector<std::string> enabled_lines;
for (const ActionReplay::ARCode& code : codes) for (const ActionReplay::ARCode& code : codes)
{ {
if (code.active) if (code.enabled)
enabled_lines.emplace_back("$" + code.name); enabled_lines.emplace_back("$" + code.name);
if (code.user_defined) if (code.user_defined)

View File

@ -28,8 +28,8 @@ struct ARCode
{ {
std::string name; std::string name;
std::vector<AREntry> ops; std::vector<AREntry> ops;
bool active; bool enabled = false;
bool user_defined; bool user_defined = false;
}; };
void RunAllActive(); void RunAllActive();

View File

@ -7,6 +7,7 @@ add_library(core
ARDecrypt.h ARDecrypt.h
BootManager.cpp BootManager.cpp
BootManager.h BootManager.h
CheatCodes.h
CommonTitles.h CommonTitles.h
ConfigManager.cpp ConfigManager.cpp
ConfigManager.h ConfigManager.h

View File

@ -0,0 +1,38 @@
// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include "Common/IniFile.h"
template <typename T>
void ReadEnabledOrDisabled(const IniFile& ini, const std::string& section, bool enabled,
std::vector<T>* codes)
{
std::vector<std::string> lines;
ini.GetLines(section, &lines, false);
for (const std::string& line : lines)
{
if (line.empty() || line[0] != '$')
continue;
for (T& code : *codes)
{
// Exclude the initial '$' from the comparison.
if (line.compare(1, std::string::npos, code.name) == 0)
code.enabled = enabled;
}
}
}
template <typename T>
void ReadEnabledAndDisabled(const IniFile& ini, const std::string& section, std::vector<T>* codes)
{
ReadEnabledOrDisabled(ini, section + "_Enabled", true, codes);
ReadEnabledOrDisabled(ini, section + "_Disabled", false, codes);
}

View File

@ -384,6 +384,7 @@
<ClInclude Include="Boot\DolReader.h" /> <ClInclude Include="Boot\DolReader.h" />
<ClInclude Include="Boot\ElfReader.h" /> <ClInclude Include="Boot\ElfReader.h" />
<ClInclude Include="Boot\ElfTypes.h" /> <ClInclude Include="Boot\ElfTypes.h" />
<ClInclude Include="CheatCodes.h" />
<ClInclude Include="Config\GraphicsSettings.h" /> <ClInclude Include="Config\GraphicsSettings.h" />
<ClInclude Include="Config\MainSettings.h" /> <ClInclude Include="Config\MainSettings.h" />
<ClInclude Include="Config\NetplaySettings.h" /> <ClInclude Include="Config\NetplaySettings.h" />

View File

@ -1765,6 +1765,7 @@
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface\BBA</Filter> <Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface\BBA</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="SyncIdentifier.h" /> <ClInclude Include="SyncIdentifier.h" />
<ClInclude Include="CheatCodes.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="CMakeLists.txt" /> <Text Include="CMakeLists.txt" />

View File

@ -13,6 +13,7 @@
#include "Common/IniFile.h" #include "Common/IniFile.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/CheatCodes.h"
namespace Gecko namespace Gecko
{ {
@ -190,24 +191,7 @@ std::vector<GeckoCode> LoadCodes(const IniFile& globalIni, const IniFile& localI
gcodes.push_back(gcode); gcodes.push_back(gcode);
} }
ini->GetLines("Gecko_Enabled", &lines, false); ReadEnabledAndDisabled(*ini, "Gecko", &gcodes);
for (const std::string& line : lines)
{
if (line.empty() || line[0] != '$')
{
continue;
}
for (GeckoCode& ogcode : gcodes)
{
// Exclude the initial '$' from the comparison.
if (line.compare(1, std::string::npos, ogcode.name) == 0)
{
ogcode.enabled = true;
}
}
}
} }
return gcodes; return gcodes;

View File

@ -1158,7 +1158,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
arcode = ActionReplay::ARCode(); arcode = ActionReplay::ARCode();
// Initialize arcode // Initialize arcode
arcode.name = "Synced Codes"; arcode.name = "Synced Codes";
arcode.active = true; arcode.enabled = true;
// Receive code contents from packet // Receive code contents from packet
for (int i = 0; i < m_sync_ar_codes_count; i++) for (int i = 0; i < m_sync_ar_codes_count; i++)

View File

@ -12,7 +12,6 @@
#include <array> #include <array>
#include <iterator> #include <iterator>
#include <map> #include <map>
#include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -21,6 +20,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/ActionReplay.h" #include "Core/ActionReplay.h"
#include "Core/CheatCodes.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/GeckoCode.h" #include "Core/GeckoCode.h"
@ -47,20 +47,6 @@ const char* PatchTypeAsString(PatchType type)
void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni, void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, IniFile& globalIni,
IniFile& localIni) IniFile& localIni)
{ {
// Load the name of all enabled patches
std::string enabledSectionName = section + "_Enabled";
std::vector<std::string> enabledLines;
std::set<std::string> enabledNames;
localIni.GetLines(enabledSectionName, &enabledLines);
for (const std::string& line : enabledLines)
{
if (!line.empty() && line[0] == '$')
{
std::string name = line.substr(1, line.size() - 1);
enabledNames.insert(name);
}
}
const IniFile* inis[2] = {&globalIni, &localIni}; const IniFile* inis[2] = {&globalIni, &localIni};
for (const IniFile* ini : inis) for (const IniFile* ini : inis)
@ -83,9 +69,8 @@ void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, I
} }
currentPatch.entries.clear(); currentPatch.entries.clear();
// Set active and name // Set name and whether the patch is user defined
currentPatch.name = line.substr(1, line.size() - 1); currentPatch.name = line.substr(1, line.size() - 1);
currentPatch.active = enabledNames.find(currentPatch.name) != enabledNames.end();
currentPatch.user_defined = (ini == &localIni); currentPatch.user_defined = (ini == &localIni);
} }
else else
@ -123,6 +108,8 @@ void LoadPatchSection(const std::string& section, std::vector<Patch>& patches, I
{ {
patches.push_back(currentPatch); patches.push_back(currentPatch);
} }
ReadEnabledAndDisabled(*ini, section, &patches);
} }
} }
@ -185,7 +172,7 @@ static void ApplyPatches(const std::vector<Patch>& patches)
{ {
for (const Patch& patch : patches) for (const Patch& patch : patches)
{ {
if (patch.active) if (patch.enabled)
{ {
for (const PatchEntry& entry : patch.entries) for (const PatchEntry& entry : patch.entries)
{ {

View File

@ -33,7 +33,7 @@ struct Patch
{ {
std::string name; std::string name;
std::vector<PatchEntry> entries; std::vector<PatchEntry> entries;
bool active = false; bool enabled = false;
bool user_defined = false; // False if this code is shipped with Dolphin. bool user_defined = false; // False if this code is shipped with Dolphin.
}; };

View File

@ -292,7 +292,7 @@ void CheatsManager::GenerateARCode()
int index = item->data(INDEX_ROLE).toInt(); int index = item->data(INDEX_ROLE).toInt();
ActionReplay::ARCode ar_code; ActionReplay::ARCode ar_code;
ar_code.active = true; ar_code.enabled = true;
ar_code.user_defined = true; ar_code.user_defined = true;
ar_code.name = tr("Generated by search (Address %1)") ar_code.name = tr("Generated by search (Address %1)")
.arg(m_watch[index].address, 8, 16, QLatin1Char('0')) .arg(m_watch[index].address, 8, 16, QLatin1Char('0'))

View File

@ -89,7 +89,7 @@ void ARCodeWidget::ConnectWidgets()
void ARCodeWidget::OnItemChanged(QListWidgetItem* item) void ARCodeWidget::OnItemChanged(QListWidgetItem* item)
{ {
m_ar_codes[m_code_list->row(item)].active = (item->checkState() == Qt::Checked); m_ar_codes[m_code_list->row(item)].enabled = (item->checkState() == Qt::Checked);
if (!m_restart_required) if (!m_restart_required)
ActionReplay::ApplyCodes(m_ar_codes); ActionReplay::ApplyCodes(m_ar_codes);
@ -159,7 +159,7 @@ void ARCodeWidget::UpdateList()
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable |
Qt::ItemIsDragEnabled); Qt::ItemIsDragEnabled);
item->setCheckState(ar.active ? Qt::Checked : Qt::Unchecked); item->setCheckState(ar.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole, static_cast<int>(i)); item->setData(Qt::UserRole, static_cast<int>(i));
m_code_list->addItem(item); m_code_list->addItem(item);
@ -190,7 +190,7 @@ void ARCodeWidget::AddCode(ActionReplay::ARCode code)
void ARCodeWidget::OnCodeAddClicked() void ARCodeWidget::OnCodeAddClicked()
{ {
ActionReplay::ARCode ar; ActionReplay::ARCode ar;
ar.active = true; ar.enabled = true;
CheatCodeEditor ed(this); CheatCodeEditor ed(this);
ed.SetARCode(&ar); ed.SetARCode(&ar);

View File

@ -34,7 +34,7 @@ NewPatchDialog::NewPatchDialog(QWidget* parent, PatchEngine::Patch& patch)
if (m_patch.entries.empty()) if (m_patch.entries.empty())
{ {
AddEntry(); AddEntry();
m_patch.active = true; m_patch.enabled = true;
} }
} }

View File

@ -65,7 +65,7 @@ void PatchesWidget::ConnectWidgets()
void PatchesWidget::OnItemChanged(QListWidgetItem* item) void PatchesWidget::OnItemChanged(QListWidgetItem* item)
{ {
m_patches[m_list->row(item)].active = (item->checkState() == Qt::Checked); m_patches[m_list->row(item)].enabled = (item->checkState() == Qt::Checked);
SavePatches(); SavePatches();
} }
@ -132,7 +132,7 @@ void PatchesWidget::SavePatches()
for (const auto& patch : m_patches) for (const auto& patch : m_patches)
{ {
if (patch.active) if (patch.enabled)
lines_enabled.push_back("$" + patch.name); lines_enabled.push_back("$" + patch.name);
if (!patch.user_defined) if (!patch.user_defined)
@ -164,7 +164,7 @@ void PatchesWidget::Update()
{ {
auto* item = new QListWidgetItem(QString::fromStdString(patch.name)); auto* item = new QListWidgetItem(QString::fromStdString(patch.name));
item->setFlags(item->flags() | Qt::ItemIsUserCheckable); item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(patch.active ? Qt::Checked : Qt::Unchecked); item->setCheckState(patch.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole, patch.user_defined); item->setData(Qt::UserRole, patch.user_defined);
m_list->addItem(item); m_list->addItem(item);