mirror of https://github.com/PCSX2/pcsx2.git
Patch: Add new toggleable cheat and patch interface
This commit is contained in:
parent
ec35330593
commit
81da9fb5a4
|
@ -371,7 +371,6 @@ SysMtgsThread& GetMTGS()
|
||||||
// Interface Stuff
|
// Interface Stuff
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const IConsoleWriter* PatchesCon = &Console;
|
|
||||||
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
||||||
END_HOTKEY_LIST()
|
END_HOTKEY_LIST()
|
||||||
|
|
||||||
|
|
|
@ -76,12 +76,19 @@ target_sources(pcsx2-qt PRIVATE
|
||||||
Settings/FolderSettingsWidget.cpp
|
Settings/FolderSettingsWidget.cpp
|
||||||
Settings/FolderSettingsWidget.h
|
Settings/FolderSettingsWidget.h
|
||||||
Settings/FolderSettingsWidget.ui
|
Settings/FolderSettingsWidget.ui
|
||||||
|
Settings/GameCheatSettingsWidget.cpp
|
||||||
|
Settings/GameCheatSettingsWidget.h
|
||||||
|
Settings/GameCheatSettingsWidget.ui
|
||||||
Settings/GameFixSettingsWidget.cpp
|
Settings/GameFixSettingsWidget.cpp
|
||||||
Settings/GameFixSettingsWidget.h
|
Settings/GameFixSettingsWidget.h
|
||||||
Settings/GameFixSettingsWidget.ui
|
Settings/GameFixSettingsWidget.ui
|
||||||
Settings/GameListSettingsWidget.cpp
|
Settings/GameListSettingsWidget.cpp
|
||||||
Settings/GameListSettingsWidget.h
|
Settings/GameListSettingsWidget.h
|
||||||
Settings/GameListSettingsWidget.ui
|
Settings/GameListSettingsWidget.ui
|
||||||
|
Settings/GamePatchDetailsWidget.ui
|
||||||
|
Settings/GamePatchSettingsWidget.cpp
|
||||||
|
Settings/GamePatchSettingsWidget.h
|
||||||
|
Settings/GamePatchSettingsWidget.ui
|
||||||
Settings/GameSummaryWidget.cpp
|
Settings/GameSummaryWidget.cpp
|
||||||
Settings/GameSummaryWidget.h
|
Settings/GameSummaryWidget.h
|
||||||
Settings/GameSummaryWidget.ui
|
Settings/GameSummaryWidget.ui
|
||||||
|
@ -116,6 +123,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||||
Settings/DEV9UiCommon.h
|
Settings/DEV9UiCommon.h
|
||||||
Settings/HddCreateQt.cpp
|
Settings/HddCreateQt.cpp
|
||||||
Settings/HddCreateQt.h
|
Settings/HddCreateQt.h
|
||||||
|
Settings/PatchDetailsWidget.ui
|
||||||
Settings/SettingsDialog.cpp
|
Settings/SettingsDialog.cpp
|
||||||
Settings/SettingsDialog.h
|
Settings/SettingsDialog.h
|
||||||
Settings/SettingsDialog.ui
|
Settings/SettingsDialog.ui
|
||||||
|
|
|
@ -84,7 +84,6 @@ namespace QtHost
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Local variable declarations
|
// Local variable declarations
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
const IConsoleWriter* PatchesCon = &Console;
|
|
||||||
static std::unique_ptr<QTimer> s_settings_save_timer;
|
static std::unique_ptr<QTimer> s_settings_save_timer;
|
||||||
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
static std::unique_ptr<INISettingsInterface> s_base_settings_interface;
|
||||||
static bool s_batch_mode = false;
|
static bool s_batch_mode = false;
|
||||||
|
@ -671,7 +670,11 @@ void EmuThread::reloadPatches()
|
||||||
if (!VMManager::HasValidVM())
|
if (!VMManager::HasValidVM())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VMManager::ReloadPatches(true, true);
|
Patch::ReloadPatches(true, false, true);
|
||||||
|
|
||||||
|
// Might change widescreen mode.
|
||||||
|
if (Patch::ReloadPatchAffectingOptions())
|
||||||
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::reloadInputSources()
|
void EmuThread::reloadInputSources()
|
||||||
|
|
|
@ -64,9 +64,29 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||||
.arg(m_ui.eeCycleRate->itemText(
|
.arg(m_ui.eeCycleRate->itemText(
|
||||||
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
|
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
|
||||||
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
|
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
|
||||||
|
|
||||||
|
// Disable cheats, use the cheats panel instead (move fastcvd up in its spot).
|
||||||
|
const int count = m_ui.systemSettingsLayout->count();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
QLayoutItem* item = m_ui.systemSettingsLayout->itemAt(i);
|
||||||
|
if (item && item->widget() == m_ui.cheats)
|
||||||
|
{
|
||||||
|
int row, col, rowSpan, colSpan;
|
||||||
|
m_ui.systemSettingsLayout->getItemPosition(i, &row, &col, &rowSpan, &colSpan);
|
||||||
|
delete m_ui.systemSettingsLayout->takeAt(i);
|
||||||
|
m_ui.systemSettingsLayout->removeWidget(m_ui.fastCDVD);
|
||||||
|
m_ui.systemSettingsLayout->addWidget(m_ui.fastCDVD, row, col);
|
||||||
|
delete m_ui.cheats;
|
||||||
|
m_ui.cheats = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cheats, "EmuCore", "EnableCheats", false);
|
||||||
|
|
||||||
// Allow for FastCDVD for per-game settings only
|
// Allow for FastCDVD for per-game settings only
|
||||||
m_ui.systemSettingsLayout->removeWidget(m_ui.fastCDVD);
|
m_ui.systemSettingsLayout->removeWidget(m_ui.fastCDVD);
|
||||||
m_ui.fastCDVD->deleteLater();
|
m_ui.fastCDVD->deleteLater();
|
||||||
|
@ -84,7 +104,6 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||||
m_dialog->setIntSettingValue("EmuCore/Speedhacks", "EECycleRate", value);
|
m_dialog->setIntSettingValue("EmuCore/Speedhacks", "EECycleRate", value);
|
||||||
});
|
});
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cheats, "EmuCore", "EnableCheats", false);
|
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hostFilesystem, "EmuCore", "HostFs", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hostFilesystem, "EmuCore", "HostFs", false);
|
||||||
|
|
||||||
dialog->registerWidgetHelp(m_ui.normalSpeed, tr("Normal Speed"), "100%",
|
dialog->registerWidgetHelp(m_ui.normalSpeed, tr("Normal Speed"), "100%",
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2023 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "QtHost.h"
|
||||||
|
#include "QtUtils.h"
|
||||||
|
#include "SettingWidgetBinder.h"
|
||||||
|
#include "Settings/GameCheatSettingsWidget.h"
|
||||||
|
#include "Settings/SettingsDialog.h"
|
||||||
|
|
||||||
|
#include "pcsx2/GameList.h"
|
||||||
|
#include "pcsx2/Patch.h"
|
||||||
|
|
||||||
|
#include "common/HeterogeneousContainers.h"
|
||||||
|
|
||||||
|
GameCheatSettingsWidget::GameCheatSettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent)
|
||||||
|
: m_dialog(dialog)
|
||||||
|
, m_serial(entry->serial)
|
||||||
|
, m_crc(entry->crc)
|
||||||
|
{
|
||||||
|
m_ui.setupUi(this);
|
||||||
|
QtUtils::ResizeColumnsForTreeView(m_ui.cheatList, {300, 100, -1});
|
||||||
|
|
||||||
|
reloadList();
|
||||||
|
|
||||||
|
SettingsInterface* sif = m_dialog->getSettingsInterface();
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableCheats, "EmuCore", "EnableCheats", false);
|
||||||
|
updateListEnabled();
|
||||||
|
|
||||||
|
connect(m_ui.enableCheats, &QCheckBox::stateChanged, this, &GameCheatSettingsWidget::updateListEnabled);
|
||||||
|
connect(m_ui.cheatList, &QTreeWidget::itemDoubleClicked, this, &GameCheatSettingsWidget::onCheatListItemDoubleClicked);
|
||||||
|
connect(m_ui.cheatList, &QTreeWidget::itemChanged, this, &GameCheatSettingsWidget::onCheatListItemChanged);
|
||||||
|
connect(m_ui.reloadCheats, &QPushButton::clicked, this, &GameCheatSettingsWidget::reloadList);
|
||||||
|
connect(m_ui.enableAll, &QPushButton::clicked, this, [this]() { setStateForAll(true); });
|
||||||
|
connect(m_ui.disableAll, &QPushButton::clicked, this, [this]() { setStateForAll(false); });
|
||||||
|
}
|
||||||
|
|
||||||
|
GameCheatSettingsWidget::~GameCheatSettingsWidget() = default;
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::onCheatListItemDoubleClicked(QTreeWidgetItem* item, int column)
|
||||||
|
{
|
||||||
|
QVariant data = item->data(0, Qt::UserRole);
|
||||||
|
if (!data.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string cheat_name = data.toString().toStdString();
|
||||||
|
const bool new_state = !(item->checkState(0) == Qt::Checked);
|
||||||
|
item->setCheckState(0, new_state ? Qt::Checked : Qt::Unchecked);
|
||||||
|
setCheatEnabled(std::move(cheat_name), new_state, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::onCheatListItemChanged(QTreeWidgetItem* item, int column)
|
||||||
|
{
|
||||||
|
QVariant data = item->data(0, Qt::UserRole);
|
||||||
|
if (!data.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string cheat_name = data.toString().toStdString();
|
||||||
|
const bool current_enabled =
|
||||||
|
(std::find(m_enabled_patches.begin(), m_enabled_patches.end(), cheat_name) != m_enabled_patches.end());
|
||||||
|
const bool current_checked = (item->checkState(0) == Qt::Checked);
|
||||||
|
if (current_enabled == current_checked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
setCheatEnabled(std::move(cheat_name), current_checked, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::onReloadClicked()
|
||||||
|
{
|
||||||
|
reloadList();
|
||||||
|
|
||||||
|
// reload it on the emu thread too, so it picks up any changes
|
||||||
|
g_emu_thread->reloadPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::updateListEnabled()
|
||||||
|
{
|
||||||
|
const bool cheats_enabled = m_dialog->getEffectiveBoolValue("EmuCore", "EnableCheats", false);
|
||||||
|
m_ui.cheatList->setEnabled(cheats_enabled);
|
||||||
|
m_ui.enableAll->setEnabled(cheats_enabled);
|
||||||
|
m_ui.disableAll->setEnabled(cheats_enabled);
|
||||||
|
m_ui.reloadCheats->setEnabled(cheats_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::setCheatEnabled(std::string name, bool enabled, bool save_and_reload_settings)
|
||||||
|
{
|
||||||
|
SettingsInterface* si = m_dialog->getSettingsInterface();
|
||||||
|
auto it = std::find(m_enabled_patches.begin(), m_enabled_patches.end(), name);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
si->AddToStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY, name.c_str());
|
||||||
|
if (it == m_enabled_patches.end())
|
||||||
|
m_enabled_patches.push_back(std::move(name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
si->RemoveFromStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY, name.c_str());
|
||||||
|
if (it != m_enabled_patches.end())
|
||||||
|
m_enabled_patches.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_and_reload_settings)
|
||||||
|
{
|
||||||
|
si->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::setStateForAll(bool enabled)
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.cheatList);
|
||||||
|
setStateRecursively(nullptr, enabled);
|
||||||
|
m_dialog->getSettingsInterface()->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::setStateRecursively(QTreeWidgetItem* parent, bool enabled)
|
||||||
|
{
|
||||||
|
const int count = parent ? parent->childCount() : m_ui.cheatList->topLevelItemCount();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* item = parent ? parent->child(i) : m_ui.cheatList->topLevelItem(i);
|
||||||
|
QVariant data = item->data(0, Qt::UserRole);
|
||||||
|
if (data.isValid())
|
||||||
|
{
|
||||||
|
if ((item->checkState(0) == Qt::Checked) != enabled)
|
||||||
|
{
|
||||||
|
item->setCheckState(0, enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
|
setCheatEnabled(data.toString().toStdString(), enabled, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setStateRecursively(item, enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::reloadList()
|
||||||
|
{
|
||||||
|
u32 num_unlabelled_codes = 0;
|
||||||
|
m_patches = Patch::GetPatchInfo(m_serial, m_crc, true, &num_unlabelled_codes);
|
||||||
|
m_enabled_patches =
|
||||||
|
m_dialog->getSettingsInterface()->GetStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY);
|
||||||
|
|
||||||
|
m_parent_map.clear();
|
||||||
|
while (m_ui.cheatList->topLevelItemCount() > 0)
|
||||||
|
delete m_ui.cheatList->takeTopLevelItem(0);
|
||||||
|
|
||||||
|
for (const Patch::PatchInfo& pi : m_patches)
|
||||||
|
{
|
||||||
|
const bool enabled =
|
||||||
|
(std::find(m_enabled_patches.begin(), m_enabled_patches.end(), pi.name) != m_enabled_patches.end());
|
||||||
|
|
||||||
|
const std::string_view name_part = pi.GetNamePart();
|
||||||
|
const std::string_view parent_part = pi.GetNameParentPart();
|
||||||
|
|
||||||
|
QTreeWidgetItem* parent = getTreeWidgetParent(parent_part);
|
||||||
|
QTreeWidgetItem* item = new QTreeWidgetItem();
|
||||||
|
populateTreeWidgetItem(item, pi, enabled);
|
||||||
|
if (parent)
|
||||||
|
parent->addChild(item);
|
||||||
|
else
|
||||||
|
m_ui.cheatList->addTopLevelItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide root indicator when there's no groups, frees up some whitespace.
|
||||||
|
m_ui.cheatList->setRootIsDecorated(!m_parent_map.empty());
|
||||||
|
|
||||||
|
if (num_unlabelled_codes > 0)
|
||||||
|
{
|
||||||
|
QTreeWidgetItem* item = new QTreeWidgetItem();
|
||||||
|
item->setText(0, tr("%1 unlabelled patch codes will automatically activate.").arg(num_unlabelled_codes));
|
||||||
|
m_ui.cheatList->addTopLevelItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem* GameCheatSettingsWidget::getTreeWidgetParent(const std::string_view& parent)
|
||||||
|
{
|
||||||
|
if (parent.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto it = UnorderedStringMapFind(m_parent_map, parent);
|
||||||
|
if (it != m_parent_map.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
std::string_view this_part = parent;
|
||||||
|
QTreeWidgetItem* parent_to_this = nullptr;
|
||||||
|
const std::string_view::size_type pos = parent.rfind('\\');
|
||||||
|
if (pos != std::string::npos && pos != (parent.size() - 1))
|
||||||
|
{
|
||||||
|
// go up the chain until we find the real parent, then back down
|
||||||
|
parent_to_this = getTreeWidgetParent(parent.substr(0, pos));
|
||||||
|
this_part = parent.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTreeWidgetItem* item = new QTreeWidgetItem();
|
||||||
|
item->setText(0, QString::fromUtf8(this_part.data(), this_part.length()));
|
||||||
|
|
||||||
|
if (parent_to_this)
|
||||||
|
parent_to_this->addChild(item);
|
||||||
|
else
|
||||||
|
m_ui.cheatList->addTopLevelItem(item);
|
||||||
|
|
||||||
|
// Must be called after adding.
|
||||||
|
item->setExpanded(true);
|
||||||
|
m_parent_map.emplace(parent, item);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameCheatSettingsWidget::populateTreeWidgetItem(QTreeWidgetItem* item, const Patch::PatchInfo& pi, bool enabled)
|
||||||
|
{
|
||||||
|
const std::string_view name_part = pi.GetNamePart();
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemNeverHasChildren);
|
||||||
|
item->setCheckState(0, enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
|
item->setData(0, Qt::UserRole, QString::fromStdString(pi.name));
|
||||||
|
if (!name_part.empty())
|
||||||
|
item->setText(0, QString::fromUtf8(name_part.data(), name_part.length()));
|
||||||
|
item->setText(1, QString::fromStdString(pi.author));
|
||||||
|
item->setText(2, QString::fromStdString(pi.description));
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2023 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
|
||||||
|
#include "ui_GameCheatSettingsWidget.h"
|
||||||
|
|
||||||
|
#include "pcsx2/Patch.h"
|
||||||
|
|
||||||
|
#include "common/HeterogeneousContainers.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace GameList
|
||||||
|
{
|
||||||
|
struct Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsDialog;
|
||||||
|
|
||||||
|
class GameCheatSettingsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GameCheatSettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent);
|
||||||
|
~GameCheatSettingsWidget();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onCheatListItemDoubleClicked(QTreeWidgetItem* item, int column);
|
||||||
|
void onCheatListItemChanged(QTreeWidgetItem* item, int column);
|
||||||
|
void onReloadClicked();
|
||||||
|
void updateListEnabled();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTreeWidgetItem* getTreeWidgetParent(const std::string_view& parent);
|
||||||
|
void populateTreeWidgetItem(QTreeWidgetItem* item, const Patch::PatchInfo& pi, bool enabled);
|
||||||
|
void setCheatEnabled(std::string name, bool enabled, bool save_and_reload_settings);
|
||||||
|
void setStateForAll(bool enabled);
|
||||||
|
void setStateRecursively(QTreeWidgetItem* parent, bool enabled);
|
||||||
|
void reloadList();
|
||||||
|
|
||||||
|
Ui::GameCheatSettingsWidget m_ui;
|
||||||
|
SettingsDialog* m_dialog;
|
||||||
|
|
||||||
|
std::string m_serial;
|
||||||
|
u32 m_crc;
|
||||||
|
|
||||||
|
UnorderedStringMap<QTreeWidgetItem*> m_parent_map;
|
||||||
|
std::vector<Patch::PatchInfo> m_patches;
|
||||||
|
std::vector<std::string> m_enabled_patches;
|
||||||
|
};
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GameCheatSettingsWidget</class>
|
||||||
|
<widget class="QWidget" name="GameCheatSettingsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>697</width>
|
||||||
|
<height>361</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Activating cheats can cause unpredictable behavior, crashing, soft-locks, or broken saved games. Use cheats at your own risk, the PCSX2 team will provide no support for users who have enabled cheats.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enableCheats">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Cheats</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="cheatList">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectItems</enum>
|
||||||
|
</property>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Author</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="enableAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="disableAll">
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="reloadCheats">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Cheats</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GamePatchDetailsWidget</class>
|
||||||
|
<widget class="QWidget" name="GamePatchDetailsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>541</width>
|
||||||
|
<height>112</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Patch Title</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enabled">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enabled</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:700;">Author: </span>Patch Author</p><p>Description would go here</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,132 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2023 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "QtHost.h"
|
||||||
|
#include "QtUtils.h"
|
||||||
|
#include "Settings/GamePatchSettingsWidget.h"
|
||||||
|
#include "Settings/SettingsDialog.h"
|
||||||
|
|
||||||
|
#include "pcsx2/GameList.h"
|
||||||
|
#include "pcsx2/Patch.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::string& author,
|
||||||
|
const std::string& description, bool enabled, SettingsDialog* dialog, QWidget* parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_dialog(dialog)
|
||||||
|
, m_name(name)
|
||||||
|
{
|
||||||
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
|
m_ui.name->setText(QString::fromStdString(name));
|
||||||
|
m_ui.description->setText(
|
||||||
|
tr("<strong>Author: </strong>%1<br>%2")
|
||||||
|
.arg(author.empty() ? tr("Unknown") : QString::fromStdString(author))
|
||||||
|
.arg(description.empty() ? tr("No description provided.") : QString::fromStdString(description)));
|
||||||
|
|
||||||
|
pxAssert(dialog->getSettingsInterface());
|
||||||
|
m_ui.enabled->setChecked(enabled);
|
||||||
|
connect(m_ui.enabled, &QCheckBox::stateChanged, this, &GamePatchDetailsWidget::onEnabledStateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePatchDetailsWidget::~GamePatchDetailsWidget() = default;
|
||||||
|
|
||||||
|
void GamePatchDetailsWidget::onEnabledStateChanged(int state)
|
||||||
|
{
|
||||||
|
SettingsInterface* si = m_dialog->getSettingsInterface();
|
||||||
|
if (state == Qt::Checked)
|
||||||
|
si->AddToStringList("Patches", "Enable", m_name.c_str());
|
||||||
|
else
|
||||||
|
si->RemoveFromStringList("Patches", "Enable", m_name.c_str());
|
||||||
|
|
||||||
|
si->Save();
|
||||||
|
g_emu_thread->reloadGameSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePatchSettingsWidget::GamePatchSettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent)
|
||||||
|
: m_dialog(dialog)
|
||||||
|
, m_serial(entry->serial)
|
||||||
|
, m_crc(entry->crc)
|
||||||
|
{
|
||||||
|
m_ui.setupUi(this);
|
||||||
|
m_ui.scrollArea->setFrameShape(QFrame::WinPanel);
|
||||||
|
m_ui.scrollArea->setFrameShadow(QFrame::Sunken);
|
||||||
|
|
||||||
|
connect(m_ui.reload, &QPushButton::clicked, this, &GamePatchSettingsWidget::onReloadClicked);
|
||||||
|
|
||||||
|
reloadList();
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePatchSettingsWidget::~GamePatchSettingsWidget() = default;
|
||||||
|
|
||||||
|
void GamePatchSettingsWidget::onReloadClicked()
|
||||||
|
{
|
||||||
|
reloadList();
|
||||||
|
|
||||||
|
// reload it on the emu thread too, so it picks up any changes
|
||||||
|
g_emu_thread->reloadPatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamePatchSettingsWidget::reloadList()
|
||||||
|
{
|
||||||
|
// Patches shouldn't have any unlabelled patch groups, because they're new.
|
||||||
|
std::vector<Patch::PatchInfo> patches = Patch::GetPatchInfo(m_serial, m_crc, false, nullptr);
|
||||||
|
std::vector<std::string> enabled_list =
|
||||||
|
m_dialog->getSettingsInterface()->GetStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY);
|
||||||
|
|
||||||
|
delete m_ui.scrollArea->takeWidget();
|
||||||
|
|
||||||
|
QWidget* container = new QWidget(m_ui.scrollArea);
|
||||||
|
QVBoxLayout* layout = new QVBoxLayout(container);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
if (!patches.empty())
|
||||||
|
{
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
for (Patch::PatchInfo& pi : patches)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
QFrame* frame = new QFrame(container);
|
||||||
|
frame->setFrameShape(QFrame::HLine);
|
||||||
|
frame->setFrameShadow(QFrame::Sunken);
|
||||||
|
layout->addWidget(frame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool enabled = (std::find(enabled_list.begin(), enabled_list.end(), pi.name) != enabled_list.end());
|
||||||
|
GamePatchDetailsWidget* it =
|
||||||
|
new GamePatchDetailsWidget(std::move(pi.name), pi.author, pi.description, enabled, m_dialog, container);
|
||||||
|
layout->addWidget(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QLabel* label = new QLabel(tr("There are no patches available for this game."), container);
|
||||||
|
layout->addWidget(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout->addStretch(1);
|
||||||
|
|
||||||
|
m_ui.scrollArea->setWidget(container);
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
|
* Copyright (C) 2023 PCSX2 Dev Team
|
||||||
|
*
|
||||||
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
* ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
|
||||||
|
#include "ui_GamePatchDetailsWidget.h"
|
||||||
|
#include "ui_GamePatchSettingsWidget.h"
|
||||||
|
|
||||||
|
#include "pcsx2/Patch.h"
|
||||||
|
|
||||||
|
namespace GameList
|
||||||
|
{
|
||||||
|
struct Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsDialog;
|
||||||
|
|
||||||
|
class GamePatchDetailsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GamePatchDetailsWidget(std::string name, const std::string& author, const std::string& description, bool enabled,
|
||||||
|
SettingsDialog* dialog, QWidget* parent);
|
||||||
|
~GamePatchDetailsWidget();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onEnabledStateChanged(int state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::GamePatchDetailsWidget m_ui;
|
||||||
|
SettingsDialog* m_dialog;
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GamePatchSettingsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
GamePatchSettingsWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent);
|
||||||
|
~GamePatchSettingsWidget();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void onReloadClicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reloadList();
|
||||||
|
|
||||||
|
Ui::GamePatchSettingsWidget m_ui;
|
||||||
|
SettingsDialog* m_dialog;
|
||||||
|
|
||||||
|
std::string m_serial;
|
||||||
|
u32 m_crc;
|
||||||
|
};
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GamePatchSettingsWidget</class>
|
||||||
|
<widget class="QWidget" name="GamePatchSettingsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>766</width>
|
||||||
|
<height>392</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Activating game patches can cause unpredictable behavior, crashing, soft-locks, or broken saved games. Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scrollArea">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="reload">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Patches</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,72 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>GamePatchDetailsWidget</class>
|
||||||
|
<widget class="QWidget" name="GamePatchDetailsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>541</width>
|
||||||
|
<height>112</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="name">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>16</pointsize>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Patch Title</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enabled">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enabled</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="description">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:700;">Author: </span>Patch Author</p><p>Description would go here</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -12,7 +12,7 @@
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
* If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
@ -26,8 +26,10 @@
|
||||||
#include "Settings/DebugSettingsWidget.h"
|
#include "Settings/DebugSettingsWidget.h"
|
||||||
#include "Settings/EmulationSettingsWidget.h"
|
#include "Settings/EmulationSettingsWidget.h"
|
||||||
#include "Settings/FolderSettingsWidget.h"
|
#include "Settings/FolderSettingsWidget.h"
|
||||||
|
#include "Settings/GameCheatSettingsWidget.h"
|
||||||
#include "Settings/GameFixSettingsWidget.h"
|
#include "Settings/GameFixSettingsWidget.h"
|
||||||
#include "Settings/GameListSettingsWidget.h"
|
#include "Settings/GameListSettingsWidget.h"
|
||||||
|
#include "Settings/GamePatchSettingsWidget.h"
|
||||||
#include "Settings/GameSummaryWidget.h"
|
#include "Settings/GameSummaryWidget.h"
|
||||||
#include "Settings/GraphicsSettingsWidget.h"
|
#include "Settings/GraphicsSettingsWidget.h"
|
||||||
#include "Settings/HotkeySettingsWidget.h"
|
#include "Settings/HotkeySettingsWidget.h"
|
||||||
|
@ -106,11 +108,24 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||||
tr("<strong>Emulation Settings</strong><hr>These options determine the configuration of frame pacing and game "
|
tr("<strong>Emulation Settings</strong><hr>These options determine the configuration of frame pacing and game "
|
||||||
"settings.<br><br>Mouse over an option for additional information."));
|
"settings.<br><br>Mouse over an option for additional information."));
|
||||||
|
|
||||||
|
if (isPerGameSettings() && game && game->crc != 0)
|
||||||
|
{
|
||||||
|
addWidget(m_game_patch_settings_widget = new GamePatchSettingsWidget(game, this, m_ui.settingsContainer),
|
||||||
|
tr("Patches"), QStringLiteral("tools-line"),
|
||||||
|
tr("<strong>Patches</strong><hr>This section allows you to select optional patches to apply to the game, "
|
||||||
|
"which may provide performance, visual, or gameplay improvements."));
|
||||||
|
addWidget(m_game_cheat_settings_widget = new GameCheatSettingsWidget(game, this, m_ui.settingsContainer),
|
||||||
|
tr("Cheats"), QStringLiteral("flask-line"),
|
||||||
|
tr("<strong>Cheats</strong><hr>This section allows you to select which cheats you wish to enable. You "
|
||||||
|
"cannot enable/disable cheats without labels for old-format pnach files, those will automatically "
|
||||||
|
"activate if the main cheat enable option is checked."));
|
||||||
|
}
|
||||||
|
|
||||||
// Only show the game fixes for per-game settings, there's really no reason to be setting them globally.
|
// Only show the game fixes for per-game settings, there's really no reason to be setting them globally.
|
||||||
if (show_advanced_settings && isPerGameSettings())
|
if (show_advanced_settings && isPerGameSettings())
|
||||||
{
|
{
|
||||||
addWidget(m_game_fix_settings_widget = new GameFixSettingsWidget(this, m_ui.settingsContainer), tr("Game Fixes"),
|
addWidget(m_game_fix_settings_widget = new GameFixSettingsWidget(this, m_ui.settingsContainer), tr("Game Fixes"),
|
||||||
QStringLiteral("close-line"),
|
QStringLiteral("hammer-line"),
|
||||||
tr("<strong>Game Fixes Settings</strong><hr>Game Fixes can work around incorrect emulation in some titles.<br>However, they can "
|
tr("<strong>Game Fixes Settings</strong><hr>Game Fixes can work around incorrect emulation in some titles.<br>However, they can "
|
||||||
"also cause problems in games if used incorrectly.<br>It is best to leave them all disabled unless advised otherwise."));
|
"also cause problems in games if used incorrectly.<br>It is best to leave them all disabled unless advised otherwise."));
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,9 @@ class InterfaceSettingsWidget;
|
||||||
class GameListSettingsWidget;
|
class GameListSettingsWidget;
|
||||||
class EmulationSettingsWidget;
|
class EmulationSettingsWidget;
|
||||||
class BIOSSettingsWidget;
|
class BIOSSettingsWidget;
|
||||||
|
class GameCheatSettingsWidget;
|
||||||
class GameFixSettingsWidget;
|
class GameFixSettingsWidget;
|
||||||
|
class GamePatchSettingsWidget;
|
||||||
class GraphicsSettingsWidget;
|
class GraphicsSettingsWidget;
|
||||||
class AudioSettingsWidget;
|
class AudioSettingsWidget;
|
||||||
class MemoryCardSettingsWidget;
|
class MemoryCardSettingsWidget;
|
||||||
|
@ -61,7 +63,9 @@ public:
|
||||||
__fi GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; }
|
__fi GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; }
|
||||||
__fi BIOSSettingsWidget* getBIOSSettingsWidget() const { return m_bios_settings; }
|
__fi BIOSSettingsWidget* getBIOSSettingsWidget() const { return m_bios_settings; }
|
||||||
__fi EmulationSettingsWidget* getEmulationSettingsWidget() const { return m_emulation_settings; }
|
__fi EmulationSettingsWidget* getEmulationSettingsWidget() const { return m_emulation_settings; }
|
||||||
|
__fi GameCheatSettingsWidget* getGameCheatSettingsWidget() const { return m_game_cheat_settings_widget; }
|
||||||
__fi GameFixSettingsWidget* getGameFixSettingsWidget() const { return m_game_fix_settings_widget; }
|
__fi GameFixSettingsWidget* getGameFixSettingsWidget() const { return m_game_fix_settings_widget; }
|
||||||
|
__fi GamePatchSettingsWidget* getGamePatchSettingsWidget() const { return m_game_patch_settings_widget; }
|
||||||
__fi GraphicsSettingsWidget* getGraphicsSettingsWidget() const { return m_graphics_settings; }
|
__fi GraphicsSettingsWidget* getGraphicsSettingsWidget() const { return m_graphics_settings; }
|
||||||
__fi AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; }
|
__fi AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; }
|
||||||
__fi MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; }
|
__fi MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; }
|
||||||
|
@ -107,7 +111,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
MAX_SETTINGS_WIDGETS = 12
|
MAX_SETTINGS_WIDGETS = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
void setupUi(const GameList::Entry* game);
|
void setupUi(const GameList::Entry* game);
|
||||||
|
@ -122,7 +126,9 @@ private:
|
||||||
GameListSettingsWidget* m_game_list_settings = nullptr;
|
GameListSettingsWidget* m_game_list_settings = nullptr;
|
||||||
BIOSSettingsWidget* m_bios_settings = nullptr;
|
BIOSSettingsWidget* m_bios_settings = nullptr;
|
||||||
EmulationSettingsWidget* m_emulation_settings = nullptr;
|
EmulationSettingsWidget* m_emulation_settings = nullptr;
|
||||||
|
GameCheatSettingsWidget* m_game_cheat_settings_widget = nullptr;
|
||||||
GameFixSettingsWidget* m_game_fix_settings_widget = nullptr;
|
GameFixSettingsWidget* m_game_fix_settings_widget = nullptr;
|
||||||
|
GamePatchSettingsWidget* m_game_patch_settings_widget = nullptr;
|
||||||
GraphicsSettingsWidget* m_graphics_settings = nullptr;
|
GraphicsSettingsWidget* m_graphics_settings = nullptr;
|
||||||
AudioSettingsWidget* m_audio_settings = nullptr;
|
AudioSettingsWidget* m_audio_settings = nullptr;
|
||||||
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
|
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||||
<PreprocessorDefinitions>LZMA_API_STATIC;BUILD_DX=1;ENABLE_RAINTEGRATION;ENABLE_ACHIEVEMENTS;ENABLE_DISCORD_PRESENCE;ENABLE_OPENGL;ENABLE_VULKAN;SDL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>LZMA_API_STATIC;BUILD_DX=1;ENABLE_RAINTEGRATION;ENABLE_ACHIEVEMENTS;ENABLE_DISCORD_PRESENCE;ENABLE_OPENGL;ENABLE_VULKAN;SDL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
|
||||||
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
|
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
|
||||||
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
|
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -85,6 +84,8 @@
|
||||||
<ClCompile Include="QtProgressCallback.cpp" />
|
<ClCompile Include="QtProgressCallback.cpp" />
|
||||||
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
|
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
|
||||||
<ClCompile Include="Settings\FolderSettingsWidget.cpp" />
|
<ClCompile Include="Settings\FolderSettingsWidget.cpp" />
|
||||||
|
<ClCompile Include="Settings\GameCheatSettingsWidget.cpp" />
|
||||||
|
<ClCompile Include="Settings\GamePatchSettingsWidget.cpp" />
|
||||||
<ClCompile Include="Settings\MemoryCardConvertWorker.cpp" />
|
<ClCompile Include="Settings\MemoryCardConvertWorker.cpp" />
|
||||||
<ClCompile Include="Themes.cpp" />
|
<ClCompile Include="Themes.cpp" />
|
||||||
<ClCompile Include="Tools\InputRecording\InputRecordingViewer.cpp" />
|
<ClCompile Include="Tools\InputRecording\InputRecordingViewer.cpp" />
|
||||||
|
@ -162,6 +163,8 @@
|
||||||
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h" />
|
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h" />
|
||||||
<QtMoc Include="Settings\FolderSettingsWidget.h" />
|
<QtMoc Include="Settings\FolderSettingsWidget.h" />
|
||||||
<QtMoc Include="Settings\DebugSettingsWidget.h" />
|
<QtMoc Include="Settings\DebugSettingsWidget.h" />
|
||||||
|
<QtMoc Include="Settings\GameCheatSettingsWidget.h" />
|
||||||
|
<QtMoc Include="Settings\GamePatchSettingsWidget.h" />
|
||||||
<ClInclude Include="Settings\HddCreateQt.h" />
|
<ClInclude Include="Settings\HddCreateQt.h" />
|
||||||
<QtMoc Include="Settings\GameSummaryWidget.h" />
|
<QtMoc Include="Settings\GameSummaryWidget.h" />
|
||||||
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
|
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
|
||||||
|
@ -211,7 +214,9 @@
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_InterfaceSettingsWidget.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_InterfaceSettingsWidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_SettingsDialog.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_SettingsDialog.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_AdvancedSettingsWidget.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_AdvancedSettingsWidget.cpp" />
|
||||||
|
<ClCompile Include="$(IntDir)Settings\moc_GameCheatSettingsWidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_GameFixSettingsWidget.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_GameFixSettingsWidget.cpp" />
|
||||||
|
<ClCompile Include="$(IntDir)Settings\moc_GamePatchSettingsWidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_HotkeySettingsWidget.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_HotkeySettingsWidget.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_InputBindingDialog.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_InputBindingDialog.cpp" />
|
||||||
<ClCompile Include="$(IntDir)Settings\moc_InputBindingWidget.cpp" />
|
<ClCompile Include="$(IntDir)Settings\moc_InputBindingWidget.cpp" />
|
||||||
|
@ -369,6 +374,12 @@
|
||||||
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
||||||
<FileType>Document</FileType>
|
<FileType>Document</FileType>
|
||||||
</QtUi>
|
</QtUi>
|
||||||
|
<QtUi Include="Settings\GameCheatSettingsWidget.ui">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
</QtUi>
|
||||||
|
<QtUi Include="Settings\GamePatchSettingsWidget.ui">
|
||||||
|
<FileType>Document</FileType>
|
||||||
|
</QtUi>
|
||||||
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
|
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
|
||||||
<None Include="Settings\USBBindingWidget_GTForce.ui" />
|
<None Include="Settings\USBBindingWidget_GTForce.ui" />
|
||||||
<QtUi Include="Settings\USBDeviceWidget.ui">
|
<QtUi Include="Settings\USBDeviceWidget.ui">
|
||||||
|
@ -385,4 +396,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
|
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets" />
|
<ImportGroup Label="ExtensionTargets" />
|
||||||
</Project>
|
</Project>
|
|
@ -316,6 +316,18 @@
|
||||||
<Filter>moc</Filter>
|
<Filter>moc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Themes.cpp" />
|
<ClCompile Include="Themes.cpp" />
|
||||||
|
<ClCompile Include="Settings\GamePatchSettingsWidget.cpp">
|
||||||
|
<Filter>Settings</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Settings\GameCheatSettingsWidget.cpp">
|
||||||
|
<Filter>Settings</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="$(IntDir)Settings\moc_GamePatchSettingsWidget.cpp">
|
||||||
|
<Filter>moc</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="$(IntDir)Settings\moc_GameCheatSettingsWidget.cpp">
|
||||||
|
<Filter>moc</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||||
|
@ -463,6 +475,8 @@
|
||||||
<Filter>Debugger\Models</Filter>
|
<Filter>Debugger\Models</Filter>
|
||||||
</QtMoc>
|
</QtMoc>
|
||||||
<QtMoc Include="ColorPickerButton.h" />
|
<QtMoc Include="ColorPickerButton.h" />
|
||||||
|
<QtMoc Include="Settings\GameCheatSettingsWidget.h" />
|
||||||
|
<QtMoc Include="Settings\GamePatchSettingsWidget.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtResource Include="resources\resources.qrc">
|
<QtResource Include="resources\resources.qrc">
|
||||||
|
@ -587,6 +601,12 @@
|
||||||
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
||||||
<Filter>Settings</Filter>
|
<Filter>Settings</Filter>
|
||||||
</QtUi>
|
</QtUi>
|
||||||
|
<QtUi Include="Settings\GameCheatSettingsWidget.ui">
|
||||||
|
<Filter>Settings</Filter>
|
||||||
|
</QtUi>
|
||||||
|
<QtUi Include="Settings\GamePatchSettingsWidget.ui">
|
||||||
|
<Filter>Settings</Filter>
|
||||||
|
</QtUi>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Settings\FolderSettingsWidget.ui">
|
<None Include="Settings\FolderSettingsWidget.ui">
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 2C20.5523 2 21 2.44772 21 3V8C21 8.55228 20.5523 9 20 9H15V22C15 22.5523 14.5523 23 14 23H10C9.44772 23 9 22.5523 9 22V9H3.5C2.94772 9 2.5 8.55228 2.5 8V5.61803C2.5 5.23926 2.714 4.893 3.05279 4.72361L8.5 2H20ZM15 4H8.97214L4.5 6.23607V7H11V21H13V7H15V4ZM19 4H17V7H19V4Z" fill="#000000"></path></svg>
|
After Width: | Height: | Size: 373 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5.32894 3.27158C6.56203 2.8332 7.99181 3.10749 8.97878 4.09446C10.0997 5.21537 10.3014 6.90741 9.58382 8.23385L20.2925 18.9437L18.8783 20.3579L8.16933 9.64875C6.84277 10.3669 5.1502 10.1654 4.02903 9.04421C3.04178 8.05696 2.76761 6.62665 3.20652 5.39332L5.44325 7.63C6.02903 8.21578 6.97878 8.21578 7.56457 7.63C8.15035 7.04421 8.15035 6.09446 7.56457 5.50868L5.32894 3.27158ZM15.6963 5.15512L18.8783 3.38736L20.2925 4.80157L18.5247 7.98355L16.757 8.3371L14.6356 10.4584L13.2214 9.04421L15.3427 6.92289L15.6963 5.15512ZM8.97878 13.2868L10.393 14.7011L5.08969 20.0044C4.69917 20.3949 4.066 20.3949 3.67548 20.0044C3.31285 19.6417 3.28695 19.0699 3.59777 18.6774L3.67548 18.5902L8.97878 13.2868Z" fill="#000000"></path></svg>
|
After Width: | Height: | Size: 793 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 2C20.5523 2 21 2.44772 21 3V8C21 8.55228 20.5523 9 20 9H15V22C15 22.5523 14.5523 23 14 23H10C9.44772 23 9 22.5523 9 22V9H3.5C2.94772 9 2.5 8.55228 2.5 8V5.61803C2.5 5.23926 2.714 4.893 3.05279 4.72361L8.5 2H20ZM15 4H8.97214L4.5 6.23607V7H11V21H13V7H15V4ZM19 4H17V7H19V4Z" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 373 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5.32894 3.27158C6.56203 2.8332 7.99181 3.10749 8.97878 4.09446C10.0997 5.21537 10.3014 6.90741 9.58382 8.23385L20.2925 18.9437L18.8783 20.3579L8.16933 9.64875C6.84277 10.3669 5.1502 10.1654 4.02903 9.04421C3.04178 8.05696 2.76761 6.62665 3.20652 5.39332L5.44325 7.63C6.02903 8.21578 6.97878 8.21578 7.56457 7.63C8.15035 7.04421 8.15035 6.09446 7.56457 5.50868L5.32894 3.27158ZM15.6963 5.15512L18.8783 3.38736L20.2925 4.80157L18.5247 7.98355L16.757 8.3371L14.6356 10.4584L13.2214 9.04421L15.3427 6.92289L15.6963 5.15512ZM8.97878 13.2868L10.393 14.7011L5.08969 20.0044C4.69917 20.3949 4.066 20.3949 3.67548 20.0044C3.31285 19.6417 3.28695 19.0699 3.59777 18.6774L3.67548 18.5902L8.97878 13.2868Z" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 793 B |
|
@ -37,6 +37,7 @@
|
||||||
<file>icons/black/svg/function-line.svg</file>
|
<file>icons/black/svg/function-line.svg</file>
|
||||||
<file>icons/black/svg/gamepad-line.svg</file>
|
<file>icons/black/svg/gamepad-line.svg</file>
|
||||||
<file>icons/black/svg/global-line.svg</file>
|
<file>icons/black/svg/global-line.svg</file>
|
||||||
|
<file>icons/black/svg/hammer-line.svg</file>
|
||||||
<file>icons/black/svg/hard-drive-2-line.svg</file>
|
<file>icons/black/svg/hard-drive-2-line.svg</file>
|
||||||
<file>icons/black/svg/image-fill.svg</file>
|
<file>icons/black/svg/image-fill.svg</file>
|
||||||
<file>icons/black/svg/keyboard-line.svg</file>
|
<file>icons/black/svg/keyboard-line.svg</file>
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
<file>icons/black/svg/sd-card-line.svg</file>
|
<file>icons/black/svg/sd-card-line.svg</file>
|
||||||
<file>icons/black/svg/settings-3-line.svg</file>
|
<file>icons/black/svg/settings-3-line.svg</file>
|
||||||
<file>icons/black/svg/shut-down-line.svg</file>
|
<file>icons/black/svg/shut-down-line.svg</file>
|
||||||
|
<file>icons/black/svg/tools-line.svg</file>
|
||||||
<file>icons/black/svg/trophy-line.svg</file>
|
<file>icons/black/svg/trophy-line.svg</file>
|
||||||
<file>icons/black/svg/tv-2-line.svg</file>
|
<file>icons/black/svg/tv-2-line.svg</file>
|
||||||
<file>icons/black/svg/usb-fill.svg</file>
|
<file>icons/black/svg/usb-fill.svg</file>
|
||||||
|
@ -101,6 +103,7 @@
|
||||||
<file>icons/white/svg/function-line.svg</file>
|
<file>icons/white/svg/function-line.svg</file>
|
||||||
<file>icons/white/svg/gamepad-line.svg</file>
|
<file>icons/white/svg/gamepad-line.svg</file>
|
||||||
<file>icons/white/svg/global-line.svg</file>
|
<file>icons/white/svg/global-line.svg</file>
|
||||||
|
<file>icons/white/svg/hammer-line.svg</file>
|
||||||
<file>icons/white/svg/hard-drive-2-line.svg</file>
|
<file>icons/white/svg/hard-drive-2-line.svg</file>
|
||||||
<file>icons/white/svg/image-fill.svg</file>
|
<file>icons/white/svg/image-fill.svg</file>
|
||||||
<file>icons/white/svg/keyboard-line.svg</file>
|
<file>icons/white/svg/keyboard-line.svg</file>
|
||||||
|
@ -119,6 +122,7 @@
|
||||||
<file>icons/white/svg/sd-card-line.svg</file>
|
<file>icons/white/svg/sd-card-line.svg</file>
|
||||||
<file>icons/white/svg/settings-3-line.svg</file>
|
<file>icons/white/svg/settings-3-line.svg</file>
|
||||||
<file>icons/white/svg/shut-down-line.svg</file>
|
<file>icons/white/svg/shut-down-line.svg</file>
|
||||||
|
<file>icons/white/svg/tools-line.svg</file>
|
||||||
<file>icons/white/svg/trophy-line.svg</file>
|
<file>icons/white/svg/trophy-line.svg</file>
|
||||||
<file>icons/white/svg/tv-2-line.svg</file>
|
<file>icons/white/svg/tv-2-line.svg</file>
|
||||||
<file>icons/white/svg/usb-fill.svg</file>
|
<file>icons/white/svg/usb-fill.svg</file>
|
||||||
|
|
|
@ -124,7 +124,6 @@ set(pcsx2Sources
|
||||||
MultipartFileReader.cpp
|
MultipartFileReader.cpp
|
||||||
MultitapProtocol.cpp
|
MultitapProtocol.cpp
|
||||||
Patch.cpp
|
Patch.cpp
|
||||||
Patch_Memory.cpp
|
|
||||||
Pcsx2Config.cpp
|
Pcsx2Config.cpp
|
||||||
PerformanceMetrics.cpp
|
PerformanceMetrics.cpp
|
||||||
PrecompiledHeader.cpp
|
PrecompiledHeader.cpp
|
||||||
|
|
|
@ -623,6 +623,9 @@ struct Pcsx2Config
|
||||||
static constexpr float DEFAULT_FRAME_RATE_NTSC = 59.94f;
|
static constexpr float DEFAULT_FRAME_RATE_NTSC = 59.94f;
|
||||||
static constexpr float DEFAULT_FRAME_RATE_PAL = 50.00f;
|
static constexpr float DEFAULT_FRAME_RATE_PAL = 50.00f;
|
||||||
|
|
||||||
|
static constexpr AspectRatioType DEFAULT_ASPECT_RATIO = AspectRatioType::RAuto4_3_3_2;
|
||||||
|
static constexpr GSInterlaceMode DEFAULT_INTERLACE_MODE = GSInterlaceMode::Automatic;
|
||||||
|
|
||||||
static constexpr int DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
|
static constexpr int DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
|
||||||
static constexpr int DEFAULT_VIDEO_CAPTURE_WIDTH = 640;
|
static constexpr int DEFAULT_VIDEO_CAPTURE_WIDTH = 640;
|
||||||
static constexpr int DEFAULT_VIDEO_CAPTURE_HEIGHT = 480;
|
static constexpr int DEFAULT_VIDEO_CAPTURE_HEIGHT = 480;
|
||||||
|
@ -719,9 +722,9 @@ struct Pcsx2Config
|
||||||
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
||||||
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
||||||
|
|
||||||
AspectRatioType AspectRatio = AspectRatioType::RAuto4_3_3_2;
|
AspectRatioType AspectRatio = DEFAULT_ASPECT_RATIO;
|
||||||
FMVAspectRatioSwitchType FMVAspectRatioSwitch = FMVAspectRatioSwitchType::Off;
|
FMVAspectRatioSwitchType FMVAspectRatioSwitch = FMVAspectRatioSwitchType::Off;
|
||||||
GSInterlaceMode InterlaceMode = GSInterlaceMode::Automatic;
|
GSInterlaceMode InterlaceMode = DEFAULT_INTERLACE_MODE;
|
||||||
GSPostBilinearMode LinearPresent = GSPostBilinearMode::BilinearSmooth;
|
GSPostBilinearMode LinearPresent = GSPostBilinearMode::BilinearSmooth;
|
||||||
|
|
||||||
float StretchY = 100.0f;
|
float StretchY = 100.0f;
|
||||||
|
@ -1306,6 +1309,9 @@ struct Pcsx2Config
|
||||||
void LoadSave(SettingsWrapper& wrap);
|
void LoadSave(SettingsWrapper& wrap);
|
||||||
void LoadSaveMemcards(SettingsWrapper& wrap);
|
void LoadSaveMemcards(SettingsWrapper& wrap);
|
||||||
|
|
||||||
|
/// Reloads options affected by patches.
|
||||||
|
void ReloadPatchAffectingOptions();
|
||||||
|
|
||||||
std::string FullpathToBios() const;
|
std::string FullpathToBios() const;
|
||||||
std::string FullpathToMcd(uint slot) const;
|
std::string FullpathToMcd(uint slot) const;
|
||||||
|
|
||||||
|
@ -1335,8 +1341,7 @@ namespace EmuFolders
|
||||||
extern std::string Langs;
|
extern std::string Langs;
|
||||||
extern std::string Logs;
|
extern std::string Logs;
|
||||||
extern std::string Cheats;
|
extern std::string Cheats;
|
||||||
extern std::string CheatsWS;
|
extern std::string Patches;
|
||||||
extern std::string CheatsNI;
|
|
||||||
extern std::string Resources;
|
extern std::string Resources;
|
||||||
extern std::string Cache;
|
extern std::string Cache;
|
||||||
extern std::string Covers;
|
extern std::string Covers;
|
||||||
|
|
|
@ -312,13 +312,13 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
|
||||||
{
|
{
|
||||||
for (const auto& n : node["dynaPatches"].children())
|
for (const auto& n : node["dynaPatches"].children())
|
||||||
{
|
{
|
||||||
DynamicPatch patch;
|
Patch::DynamicPatch patch;
|
||||||
|
|
||||||
if (n.has_child("pattern") && n["pattern"].has_children())
|
if (n.has_child("pattern") && n["pattern"].has_children())
|
||||||
{
|
{
|
||||||
for (const auto& db_pattern : n["pattern"].children())
|
for (const auto& db_pattern : n["pattern"].children())
|
||||||
{
|
{
|
||||||
DynamicPatchEntry entry;
|
Patch::DynamicPatchEntry entry;
|
||||||
db_pattern["offset"] >> entry.offset;
|
db_pattern["offset"] >> entry.offset;
|
||||||
db_pattern["value"] >> entry.value;
|
db_pattern["value"] >> entry.value;
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
|
||||||
}
|
}
|
||||||
for (const auto& db_replacement : n["replacement"].children())
|
for (const auto& db_replacement : n["replacement"].children())
|
||||||
{
|
{
|
||||||
DynamicPatchEntry entry;
|
Patch::DynamicPatchEntry entry;
|
||||||
db_replacement["offset"] >> entry.offset;
|
db_replacement["offset"] >> entry.offset;
|
||||||
db_replacement["value"] >> entry.value;
|
db_replacement["value"] >> entry.value;
|
||||||
|
|
||||||
|
@ -431,12 +431,12 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
{
|
{
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
Console.WriteLn("(GameDB) Changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
||||||
config.Cpu.sseMXCSR.SetRoundMode(eeRM);
|
config.Cpu.sseMXCSR.SetRoundMode(eeRM);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
Console.Warning("[GameDB] Skipping changing EE/FPU roundmode to %d [%s]", eeRM, EnumToString(eeRM));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,12 +447,12 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
{
|
{
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU0 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
Console.WriteLn("(GameDB) Changing VU0 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||||
config.Cpu.sseVU0MXCSR.SetRoundMode(vuRM);
|
config.Cpu.sseVU0MXCSR.SetRoundMode(vuRM);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing VU0 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
Console.Warning("[GameDB] Skipping changing VU0 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,12 +463,12 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
{
|
{
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
Console.WriteLn("(GameDB) Changing VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||||
config.Cpu.sseVU1MXCSR.SetRoundMode(vuRM);
|
config.Cpu.sseVU1MXCSR.SetRoundMode(vuRM);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
Console.Warning("[GameDB] Skipping changing VU1 roundmode to %d [%s]", vuRM, EnumToString(vuRM));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,14 +477,14 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
const int clampMode = enum_cast(eeClampMode);
|
const int clampMode = enum_cast(eeClampMode);
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
Console.WriteLn("(GameDB) Changing EE/FPU clamp mode [mode=%d]", clampMode);
|
||||||
config.Cpu.Recompiler.fpuOverflow = (clampMode >= 1);
|
config.Cpu.Recompiler.fpuOverflow = (clampMode >= 1);
|
||||||
config.Cpu.Recompiler.fpuExtraOverflow = (clampMode >= 2);
|
config.Cpu.Recompiler.fpuExtraOverflow = (clampMode >= 2);
|
||||||
config.Cpu.Recompiler.fpuFullMode = (clampMode >= 3);
|
config.Cpu.Recompiler.fpuFullMode = (clampMode >= 3);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing EE/FPU clamp mode [mode=%d]", clampMode);
|
Console.Warning("[GameDB] Skipping changing EE/FPU clamp mode [mode=%d]", clampMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vu0ClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
if (vu0ClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
||||||
|
@ -492,14 +492,14 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
const int clampMode = enum_cast(vu0ClampMode);
|
const int clampMode = enum_cast(vu0ClampMode);
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU0 clamp mode [mode=%d]", clampMode);
|
Console.WriteLn("(GameDB) Changing VU0 clamp mode [mode=%d]", clampMode);
|
||||||
config.Cpu.Recompiler.vu0Overflow = (clampMode >= 1);
|
config.Cpu.Recompiler.vu0Overflow = (clampMode >= 1);
|
||||||
config.Cpu.Recompiler.vu0ExtraOverflow = (clampMode >= 2);
|
config.Cpu.Recompiler.vu0ExtraOverflow = (clampMode >= 2);
|
||||||
config.Cpu.Recompiler.vu0SignOverflow = (clampMode >= 3);
|
config.Cpu.Recompiler.vu0SignOverflow = (clampMode >= 3);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing VU0 clamp mode [mode=%d]", clampMode);
|
Console.Warning("[GameDB] Skipping changing VU0 clamp mode [mode=%d]", clampMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vu1ClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
if (vu1ClampMode != GameDatabaseSchema::ClampMode::Undefined)
|
||||||
|
@ -507,14 +507,14 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
const int clampMode = enum_cast(vu1ClampMode);
|
const int clampMode = enum_cast(vu1ClampMode);
|
||||||
if (applyAuto)
|
if (applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->WriteLn("(GameDB) Changing VU1 clamp mode [mode=%d]", clampMode);
|
Console.WriteLn("(GameDB) Changing VU1 clamp mode [mode=%d]", clampMode);
|
||||||
config.Cpu.Recompiler.vu1Overflow = (clampMode >= 1);
|
config.Cpu.Recompiler.vu1Overflow = (clampMode >= 1);
|
||||||
config.Cpu.Recompiler.vu1ExtraOverflow = (clampMode >= 2);
|
config.Cpu.Recompiler.vu1ExtraOverflow = (clampMode >= 2);
|
||||||
config.Cpu.Recompiler.vu1SignOverflow = (clampMode >= 3);
|
config.Cpu.Recompiler.vu1SignOverflow = (clampMode >= 3);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PatchesCon->Warning("[GameDB] Skipping changing VU1 clamp mode [mode=%d]", clampMode);
|
Console.Warning("[GameDB] Skipping changing VU1 clamp mode [mode=%d]", clampMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - config - this could be simplified with maps instead of bitfields and enums
|
// TODO - config - this could be simplified with maps instead of bitfields and enums
|
||||||
|
@ -523,13 +523,13 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
const bool mode = it.second != 0;
|
const bool mode = it.second != 0;
|
||||||
if (!applyAuto)
|
if (!applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->Warning("[GameDB] Skipping setting Speedhack '%s' to [mode=%d]", EnumToString(it.first), mode);
|
Console.Warning("[GameDB] Skipping setting Speedhack '%s' to [mode=%d]", EnumToString(it.first), mode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Legacy note - speedhacks are setup in the GameDB as integer values, but
|
// Legacy note - speedhacks are setup in the GameDB as integer values, but
|
||||||
// are effectively booleans like the gamefixes
|
// are effectively booleans like the gamefixes
|
||||||
config.Speedhacks.Set(it.first, mode);
|
config.Speedhacks.Set(it.first, mode);
|
||||||
PatchesCon->WriteLn("(GameDB) Setting Speedhack '%s' to [mode=%d]", EnumToString(it.first), mode);
|
Console.WriteLn("(GameDB) Setting Speedhack '%s' to [mode=%d]", EnumToString(it.first), mode);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,12 +538,12 @@ u32 GameDatabaseSchema::GameEntry::applyGameFixes(Pcsx2Config& config, bool appl
|
||||||
{
|
{
|
||||||
if (!applyAuto)
|
if (!applyAuto)
|
||||||
{
|
{
|
||||||
PatchesCon->Warning("[GameDB] Skipping Gamefix: %s", EnumToString(id));
|
Console.Warning("[GameDB] Skipping Gamefix: %s", EnumToString(id));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if the fix is present, it is said to be enabled
|
// if the fix is present, it is said to be enabled
|
||||||
config.Gamefixes.Set(id, true);
|
config.Gamefixes.Set(id, true);
|
||||||
PatchesCon->WriteLn("(GameDB) Enabled Gamefix: %s", EnumToString(id));
|
Console.WriteLn("(GameDB) Enabled Gamefix: %s", EnumToString(id));
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
|
|
||||||
// The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB)
|
// The LUT is only used for 1 game so we allocate it only when the gamefix is enabled (save 4MB)
|
||||||
|
@ -685,7 +685,7 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||||
if (configMatchesHWFix(config, id, value))
|
if (configMatchesHWFix(config, id, value))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
PatchesCon->Warning("[GameDB] Skipping GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
Console.Warning("[GameDB] Skipping GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
||||||
fmt::format_to(std::back_inserter(disabled_fixes), "{} {} = {}", disabled_fixes.empty() ? " " : "\n ", getHWFixName(id), value);
|
fmt::format_to(std::back_inserter(disabled_fixes), "{} {} = {}", disabled_fixes.empty() ? " " : "\n ", getHWFixName(id), value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -900,7 +900,7 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PatchesCon->WriteLn("[GameDB] Enabled GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
Console.WriteLn("[GameDB] Enabled GS Hardware Fix: %s to [mode=%d]", getHWFixName(id), value);
|
||||||
num_applied_fixes++;
|
num_applied_fixes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ namespace GameDatabaseSchema
|
||||||
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
|
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
|
||||||
std::vector<std::string> memcardFilters;
|
std::vector<std::string> memcardFilters;
|
||||||
std::unordered_map<u32, std::string> patches;
|
std::unordered_map<u32, std::string> patches;
|
||||||
std::vector<DynamicPatch> dynaPatches;
|
std::vector<Patch::DynamicPatch> dynaPatches;
|
||||||
|
|
||||||
// Returns the list of memory card serials as a `/` delimited string
|
// Returns the list of memory card serials as a `/` delimited string
|
||||||
std::string memcardFiltersAsString() const;
|
std::string memcardFiltersAsString() const;
|
||||||
|
|
|
@ -4098,8 +4098,7 @@ void FullscreenUI::DrawFoldersSettingsPage()
|
||||||
DrawFolderSetting(bsi, ICON_FA_WRENCH " Game Settings Directory", "Folders", "GameSettings", EmuFolders::GameSettings);
|
DrawFolderSetting(bsi, ICON_FA_WRENCH " Game Settings Directory", "Folders", "GameSettings", EmuFolders::GameSettings);
|
||||||
DrawFolderSetting(bsi, ICON_FA_GAMEPAD " Input Profile Directory", "Folders", "InputProfiles", EmuFolders::InputProfiles);
|
DrawFolderSetting(bsi, ICON_FA_GAMEPAD " Input Profile Directory", "Folders", "InputProfiles", EmuFolders::InputProfiles);
|
||||||
DrawFolderSetting(bsi, ICON_FA_FROWN " Cheats Directory", "Folders", "Cheats", EmuFolders::Cheats);
|
DrawFolderSetting(bsi, ICON_FA_FROWN " Cheats Directory", "Folders", "Cheats", EmuFolders::Cheats);
|
||||||
DrawFolderSetting(bsi, ICON_FA_TV " Widescreen Cheats Directory", "Folders", "CheatsWS", EmuFolders::CheatsWS);
|
DrawFolderSetting(bsi, ICON_FA_MAGIC " Patches Directory", "Folders", "Patches", EmuFolders::Patches);
|
||||||
DrawFolderSetting(bsi, ICON_FA_MAGIC " No-Interlace Cheats Directory", "Folders", "CheatsNI", EmuFolders::CheatsNI);
|
|
||||||
DrawFolderSetting(bsi, ICON_FA_SLIDERS_H "Texture Replacements Directory", "Folders", "Textures", EmuFolders::Textures);
|
DrawFolderSetting(bsi, ICON_FA_SLIDERS_H "Texture Replacements Directory", "Folders", "Textures", EmuFolders::Textures);
|
||||||
DrawFolderSetting(bsi, ICON_FA_SLIDERS_H "Video Dumping Directory", "Folders", "Videos", EmuFolders::Videos);
|
DrawFolderSetting(bsi, ICON_FA_SLIDERS_H "Video Dumping Directory", "Folders", "Videos", EmuFolders::Videos);
|
||||||
|
|
||||||
|
|
1417
pcsx2/Patch.cpp
1417
pcsx2/Patch.cpp
File diff suppressed because it is too large
Load Diff
178
pcsx2/Patch.h
178
pcsx2/Patch.h
|
@ -28,121 +28,91 @@
|
||||||
// - UI name: "Patches", controlled via system -> enable automatic game fixes
|
// - UI name: "Patches", controlled via system -> enable automatic game fixes
|
||||||
// - note that automatic game fixes also controls automatic config changes from GameIndex.dbf (UI name: "fixes")
|
// - note that automatic game fixes also controls automatic config changes from GameIndex.dbf (UI name: "fixes")
|
||||||
//
|
//
|
||||||
// So, if the console title contains the following suffix: "... [2 Fixes] [1 Patches] [0 Cheats] [6 widescreen hacks]" then:
|
|
||||||
// - The 2 fixes are configuration (not patches) fixes applied from the Games DB (automatic game fixes).
|
|
||||||
// - The 1 Patch is one uncommented pnach-style patch line from the GamesDB (automatic game fixes).
|
|
||||||
// - The 0 cheats - cheats are enabled but nothing found/loaded from the "cheats" folder.
|
|
||||||
// - The 6 widescreen patches are 6 pnach-style patch lines loaded either from cheats_ws folder or from cheats_ws.zip
|
|
||||||
|
|
||||||
#include "common/Pcsx2Defs.h"
|
#include "Config.h"
|
||||||
#include "SysForwardDefs.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct IConsoleWriter;
|
namespace Patch
|
||||||
|
|
||||||
enum patch_cpu_type {
|
|
||||||
NO_CPU,
|
|
||||||
CPU_EE,
|
|
||||||
CPU_IOP
|
|
||||||
};
|
|
||||||
|
|
||||||
enum patch_data_type {
|
|
||||||
NO_TYPE,
|
|
||||||
BYTE_T,
|
|
||||||
SHORT_T,
|
|
||||||
WORD_T,
|
|
||||||
DOUBLE_T,
|
|
||||||
EXTENDED_T,
|
|
||||||
SHORT_BE_T,
|
|
||||||
WORD_BE_T,
|
|
||||||
DOUBLE_BE_T
|
|
||||||
};
|
|
||||||
|
|
||||||
// "place" is the first number at a pnach line (patch=<place>,...), e.g.:
|
|
||||||
// - patch=1,EE,001110e0,word,00000000 <-- place is 1
|
|
||||||
// - patch=0,EE,0010BC88,word,48468800 <-- place is 0
|
|
||||||
// In PCSX2 it indicates how/when/where the patch line should be applied. If
|
|
||||||
// place is not one of the supported values then the patch line is never applied.
|
|
||||||
// PCSX2 currently supports the following values:
|
|
||||||
// 0 - apply the patch line once on game boot/startup
|
|
||||||
// 1 - apply the patch line continuously (technically - on every vsync)
|
|
||||||
// 2 - effect of 0 and 1 combined, see below
|
|
||||||
// Note:
|
|
||||||
// - while it may seem that a value of 1 does the same as 0, but also later
|
|
||||||
// continues to apply the patch on every vsync - it's not.
|
|
||||||
// The current (and past) behavior is that these patches are applied at different
|
|
||||||
// places at the code, and it's possible, depending on circumstances, that 0 patches
|
|
||||||
// will get applied before the first vsync and therefore earlier than 1 patches.
|
|
||||||
// - There's no "place" value which indicates to apply both once on startup
|
|
||||||
// and then also continuously, however such behavior can be achieved by
|
|
||||||
// duplicating the line where one has a 0 place and the other has a 1 place.
|
|
||||||
enum patch_place_type {
|
|
||||||
PPT_ONCE_ON_LOAD = 0,
|
|
||||||
PPT_CONTINUOUSLY = 1,
|
|
||||||
PPT_COMBINED_0_1 = 2,
|
|
||||||
|
|
||||||
_PPT_END_MARKER
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void PATCHTABLEFUNC(const std::string_view& text1, const std::string_view& text2);
|
|
||||||
|
|
||||||
struct IniPatch
|
|
||||||
{
|
{
|
||||||
int enabled;
|
// "place" is the first number at a pnach line (patch=<place>,...), e.g.:
|
||||||
patch_data_type type;
|
// - patch=1,EE,001110e0,word,00000000 <-- place is 1
|
||||||
patch_cpu_type cpu;
|
// - patch=0,EE,0010BC88,word,48468800 <-- place is 0
|
||||||
int placetopatch;
|
// In PCSX2 it indicates how/when/where the patch line should be applied. If
|
||||||
u32 addr;
|
// place is not one of the supported values then the patch line is never applied.
|
||||||
u64 data;
|
// PCSX2 currently supports the following values:
|
||||||
};
|
// 0 - apply the patch line once on game boot/startup
|
||||||
|
// 1 - apply the patch line continuously (technically - on every vsync)
|
||||||
|
// 2 - effect of 0 and 1 combined, see below
|
||||||
|
// Note:
|
||||||
|
// - while it may seem that a value of 1 does the same as 0, but also later
|
||||||
|
// continues to apply the patch on every vsync - it's not.
|
||||||
|
// The current (and past) behavior is that these patches are applied at different
|
||||||
|
// places at the code, and it's possible, depending on circumstances, that 0 patches
|
||||||
|
// will get applied before the first vsync and therefore earlier than 1 patches.
|
||||||
|
// - There's no "place" value which indicates to apply both once on startup
|
||||||
|
// and then also continuously, however such behavior can be achieved by
|
||||||
|
// duplicating the line where one has a 0 place and the other has a 1 place.
|
||||||
|
enum patch_place_type
|
||||||
|
{
|
||||||
|
PPT_ONCE_ON_LOAD = 0,
|
||||||
|
PPT_CONTINUOUSLY = 1,
|
||||||
|
PPT_COMBINED_0_1 = 2,
|
||||||
|
|
||||||
struct DynamicPatchEntry
|
PPT_END_MARKER
|
||||||
{
|
};
|
||||||
u32 offset;
|
|
||||||
u32 value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DynamicPatch
|
struct PatchInfo
|
||||||
{
|
{
|
||||||
std::vector<DynamicPatchEntry> pattern;
|
std::string name;
|
||||||
std::vector<DynamicPatchEntry> replacement;
|
std::string description;
|
||||||
};
|
std::string author;
|
||||||
|
|
||||||
namespace PatchFunc
|
std::string_view GetNamePart() const;
|
||||||
{
|
std::string_view GetNameParentPart() const;
|
||||||
PATCHTABLEFUNC author;
|
};
|
||||||
PATCHTABLEFUNC comment;
|
|
||||||
PATCHTABLEFUNC gametitle;
|
|
||||||
PATCHTABLEFUNC patch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following LoadPatchesFrom* functions:
|
using PatchInfoList = std::vector<PatchInfo>;
|
||||||
// - do not reset/unload previously loaded patches (use ForgetLoadedPatches() for that)
|
|
||||||
// - do not actually patch the emulation memory (that happens at ApplyLoadedPatches(...) )
|
|
||||||
extern int LoadPatchesFromString(const std::string& patches);
|
|
||||||
extern int LoadPatchesFromDir(const std::string& crc, const std::string& folder, const char* friendly_name, bool show_error_when_missing);
|
|
||||||
extern int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_data_size);
|
|
||||||
|
|
||||||
// Functions for Dynamic EE patching.
|
struct DynamicPatchEntry
|
||||||
extern void LoadDynamicPatches(const std::vector<DynamicPatch>& patches);
|
{
|
||||||
extern void ApplyDynamicPatches(u32 pc);
|
u32 offset;
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
// Patches the emulation memory by applying all the loaded patches with a specific place value.
|
struct DynamicPatch
|
||||||
// Note: unless you know better, there's no need to check whether or not different patch sources
|
{
|
||||||
// are enabled (e.g. ws patches, auto game fixes, etc) before calling ApplyLoadedPatches,
|
std::vector<DynamicPatchEntry> pattern;
|
||||||
// because on boot or on any configuration change --> all the loaded patches are invalidated,
|
std::vector<DynamicPatchEntry> replacement;
|
||||||
// and then it loads only the ones which are enabled according to the current config
|
};
|
||||||
// (this happens at AppCoreThread::ApplySettings(...) )
|
|
||||||
extern void ApplyLoadedPatches(patch_place_type place);
|
|
||||||
|
|
||||||
// Empties the patches store ("unload" the patches) but doesn't touch the emulation memory.
|
// Config sections/keys to use to enable patches.
|
||||||
// Following ApplyLoadedPatches calls will do nothing until some LoadPatchesFrom* are invoked.
|
extern const char* PATCHES_CONFIG_SECTION;
|
||||||
extern void ForgetLoadedPatches();
|
extern const char* CHEATS_CONFIG_SECTION;
|
||||||
|
extern const char* PATCH_ENABLE_CONFIG_KEY;
|
||||||
|
|
||||||
extern const IConsoleWriter *PatchesCon;
|
extern PatchInfoList GetPatchInfo(const std::string& serial, u32 crc, bool cheats, u32* num_unlabelled_patches);
|
||||||
|
|
||||||
// The following prototypes seem unused in PCSX2, but maybe part of the cheats browser?
|
/// Reloads cheats/patches. If verbose is set, the number of patches loaded will be shown in the OSD.
|
||||||
// regardless, they don't seem to have an implementation anywhere.
|
extern void ReloadPatches(std::string serial, u32 crc, bool force_reload_files, bool reload_enabled_list, bool verbose);
|
||||||
// extern int AddPatch(int Mode, int Place, int Address, int Size, u64 data);
|
extern void ReloadPatches(bool force_reload_files, bool reload_enabled_list, bool verbose);
|
||||||
// extern void ResetPatch(void);
|
|
||||||
|
extern void UpdateActivePatches(bool reload_enabled_list, bool verbose, bool verbose_if_changed);
|
||||||
|
extern void ApplyPatchSettingOverrides();
|
||||||
|
extern bool ReloadPatchAffectingOptions();
|
||||||
|
extern void UnloadPatches();
|
||||||
|
|
||||||
|
// Functions for Dynamic EE patching.
|
||||||
|
extern void LoadDynamicPatches(const std::vector<DynamicPatch>& patches);
|
||||||
|
extern void ApplyDynamicPatches(u32 pc);
|
||||||
|
|
||||||
|
// Patches the emulation memory by applying all the loaded patches with a specific place value.
|
||||||
|
// Note: unless you know better, there's no need to check whether or not different patch sources
|
||||||
|
// are enabled (e.g. ws patches, auto game fixes, etc) before calling ApplyLoadedPatches,
|
||||||
|
// because on boot or on any configuration change --> all the loaded patches are invalidated,
|
||||||
|
// and then it loads only the ones which are enabled according to the current config
|
||||||
|
// (this happens at AppCoreThread::ApplySettings(...) )
|
||||||
|
extern void ApplyLoadedPatches(patch_place_type place);
|
||||||
|
} // namespace Patch
|
|
@ -1,609 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
|
|
||||||
#include "common/ByteSwap.h"
|
|
||||||
|
|
||||||
#define _PC_ // disables MIPS opcode macros.
|
|
||||||
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Patch.h"
|
|
||||||
#include "IopMem.h"
|
|
||||||
|
|
||||||
u32 SkipCount = 0, IterationCount = 0;
|
|
||||||
u32 IterationIncrement = 0, ValueIncrement = 0;
|
|
||||||
u32 PrevCheatType = 0, PrevCheatAddr = 0, LastType = 0;
|
|
||||||
|
|
||||||
void writeCheat()
|
|
||||||
{
|
|
||||||
switch (LastType)
|
|
||||||
{
|
|
||||||
case 0x0:
|
|
||||||
memWrite8(PrevCheatAddr, IterationIncrement & 0xFF);
|
|
||||||
break;
|
|
||||||
case 0x1:
|
|
||||||
memWrite16(PrevCheatAddr, IterationIncrement & 0xFFFF);
|
|
||||||
break;
|
|
||||||
case 0x2:
|
|
||||||
memWrite32(PrevCheatAddr, IterationIncrement);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_extended_t(IniPatch *p)
|
|
||||||
{
|
|
||||||
if (SkipCount > 0)
|
|
||||||
{
|
|
||||||
SkipCount--;
|
|
||||||
}
|
|
||||||
else switch (PrevCheatType)
|
|
||||||
{
|
|
||||||
case 0x3040: // vvvvvvvv 00000000 Inc
|
|
||||||
{
|
|
||||||
u32 mem = memRead32(PrevCheatAddr);
|
|
||||||
memWrite32(PrevCheatAddr, mem + (p->addr));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x3050: // vvvvvvvv 00000000 Dec
|
|
||||||
{
|
|
||||||
u32 mem = memRead32(PrevCheatAddr);
|
|
||||||
memWrite32(PrevCheatAddr, mem - (p->addr));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 0x4000: // vvvvvvvv iiiiiiii
|
|
||||||
for (u32 i = 0; i < IterationCount; i++)
|
|
||||||
{
|
|
||||||
memWrite32((u32)(PrevCheatAddr + (i * IterationIncrement)), (u32)(p->addr + ((u32)p->data * i)));
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x5000: // bbbbbbbb 00000000
|
|
||||||
for (u32 i = 0; i < IterationCount; i++)
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(PrevCheatAddr + i);
|
|
||||||
memWrite8((p->addr + i) & 0x0FFFFFFF, mem);
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x6000: // 000Xnnnn iiiiiiii
|
|
||||||
{
|
|
||||||
// Get Number of pointers
|
|
||||||
if (((u32)p->addr & 0x0000FFFF) == 0)
|
|
||||||
IterationCount = 1;
|
|
||||||
else
|
|
||||||
IterationCount = (u32)p->addr & 0x0000FFFF;
|
|
||||||
|
|
||||||
// Read first pointer
|
|
||||||
LastType = ((u32)p->addr & 0x000F0000) >> 16;
|
|
||||||
u32 mem = memRead32(PrevCheatAddr);
|
|
||||||
|
|
||||||
PrevCheatAddr = mem + (u32)p->data;
|
|
||||||
IterationCount--;
|
|
||||||
|
|
||||||
// Check if needed to read another pointer
|
|
||||||
if (IterationCount == 0)
|
|
||||||
{
|
|
||||||
PrevCheatType = 0;
|
|
||||||
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) == 0)
|
|
||||||
PrevCheatType = 0;
|
|
||||||
else
|
|
||||||
PrevCheatType = 0x6001;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x6001: // 000Xnnnn iiiiiiii
|
|
||||||
{
|
|
||||||
// Read first pointer
|
|
||||||
u32 mem = memRead32(PrevCheatAddr & 0x0FFFFFFF);
|
|
||||||
|
|
||||||
PrevCheatAddr = mem + (u32)p->addr;
|
|
||||||
IterationCount--;
|
|
||||||
|
|
||||||
// Check if needed to read another pointer
|
|
||||||
if (IterationCount == 0)
|
|
||||||
{
|
|
||||||
PrevCheatType = 0;
|
|
||||||
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mem = memRead32(PrevCheatAddr);
|
|
||||||
|
|
||||||
PrevCheatAddr = mem + (u32)p->data;
|
|
||||||
IterationCount--;
|
|
||||||
if (IterationCount == 0)
|
|
||||||
{
|
|
||||||
PrevCheatType = 0;
|
|
||||||
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if ((p->addr & 0xF0000000) == 0x00000000) // 0aaaaaaa 0000000vv
|
|
||||||
{
|
|
||||||
memWrite8(p->addr & 0x0FFFFFFF, (u8)p->data & 0x000000FF);
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x10000000) // 1aaaaaaa 0000vvvv
|
|
||||||
{
|
|
||||||
memWrite16(p->addr & 0x0FFFFFFF, (u16)p->data & 0x0000FFFF);
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x20000000) // 2aaaaaaa vvvvvvvv
|
|
||||||
{
|
|
||||||
memWrite32(p->addr & 0x0FFFFFFF, (u32)p->data);
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30000000) // 300000vv 0aaaaaaa Inc
|
|
||||||
{
|
|
||||||
u8 mem = memRead8((u32)p->data);
|
|
||||||
memWrite8((u32)p->data, mem + (p->addr & 0x000000FF));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30100000) // 301000vv 0aaaaaaa Dec
|
|
||||||
{
|
|
||||||
u8 mem = memRead8((u32)p->data);
|
|
||||||
memWrite8((u32)p->data, mem - (p->addr & 0x000000FF));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30200000) // 3020vvvv 0aaaaaaa Inc
|
|
||||||
{
|
|
||||||
u16 mem = memRead16((u32)p->data);
|
|
||||||
memWrite16((u32)p->data, mem + (p->addr & 0x0000FFFF));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30300000) // 3030vvvv 0aaaaaaa Dec
|
|
||||||
{
|
|
||||||
u16 mem = memRead16((u32)p->data);
|
|
||||||
memWrite16((u32)p->data, mem - (p->addr & 0x0000FFFF));
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30400000) // 30400000 0aaaaaaa Inc + Another line
|
|
||||||
{
|
|
||||||
PrevCheatType = 0x3040;
|
|
||||||
PrevCheatAddr = (u32)p->data;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xFFFF0000) == 0x30500000) // 30500000 0aaaaaaa Inc + Another line
|
|
||||||
{
|
|
||||||
PrevCheatType = 0x3050;
|
|
||||||
PrevCheatAddr = (u32)p->data;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x40000000) // 4aaaaaaa nnnnssss + Another line
|
|
||||||
{
|
|
||||||
IterationCount = ((u32)p->data & 0xFFFF0000) >> 16;
|
|
||||||
IterationIncrement = ((u32)p->data & 0x0000FFFF) * 4;
|
|
||||||
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
||||||
PrevCheatType = 0x4000;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x50000000) // 5sssssss nnnnnnnn + Another line
|
|
||||||
{
|
|
||||||
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
||||||
IterationCount = ((u32)p->data);
|
|
||||||
PrevCheatType = 0x5000;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x60000000) // 6aaaaaaa 000000vv + Another line/s
|
|
||||||
{
|
|
||||||
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
||||||
IterationIncrement = ((u32)p->data);
|
|
||||||
IterationCount = 0;
|
|
||||||
PrevCheatType = 0x6000;
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0x70000000)
|
|
||||||
{
|
|
||||||
if ((p->data & 0x00F00000) == 0x00000000) // 7aaaaaaa 000000vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem | (p->data & 0x000000FF)));
|
|
||||||
}
|
|
||||||
else if ((p->data & 0x00F00000) == 0x00100000) // 7aaaaaaa 0010vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem | (p->data & 0x0000FFFF)));
|
|
||||||
}
|
|
||||||
else if ((p->data & 0x00F00000) == 0x00200000) // 7aaaaaaa 002000vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem & (p->data & 0x000000FF)));
|
|
||||||
}
|
|
||||||
else if ((p->data & 0x00F00000) == 0x00300000) // 7aaaaaaa 0030vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem & (p->data & 0x0000FFFF)));
|
|
||||||
}
|
|
||||||
else if ((p->data & 0x00F00000) == 0x00400000) // 7aaaaaaa 004000vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem ^ (p->data & 0x000000FF)));
|
|
||||||
}
|
|
||||||
else if ((p->data & 0x00F00000) == 0x00500000) // 7aaaaaaa 0050vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
||||||
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem ^ (p->data & 0x0000FFFF)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((p->addr & 0xF0000000) == 0xD0000000 || (p->addr & 0xF0000000) == 0xE0000000)
|
|
||||||
{
|
|
||||||
u32 addr = (u32)p->addr;
|
|
||||||
u32 data = (u32)p->data;
|
|
||||||
|
|
||||||
// Since D-codes now have the additional functionality present in PS2rd which
|
|
||||||
// incorporates E-code-like functionality by making use of the unused bits in
|
|
||||||
// D-codes, the E-codes are now just converted to D-codes to reduce bloat.
|
|
||||||
|
|
||||||
if ((addr & 0xF0000000) == 0xE0000000)
|
|
||||||
{
|
|
||||||
// Ezyyvvvv taaaaaaa -> Daaaaaaa yytzvvvv
|
|
||||||
addr = 0xD0000000 | ((u32)p->data & 0x0FFFFFFF);
|
|
||||||
data = 0x00000000 | ((u32)p->addr & 0x0000FFFF);
|
|
||||||
data = data | ((u32)p->addr & 0x00FF0000) << 8;
|
|
||||||
data = data | ((u32)p->addr & 0x0F000000) >> 8;
|
|
||||||
data = data | ((u32)p->data & 0xF0000000) >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u8 type = (data & 0x000F0000) >> 16;
|
|
||||||
const u8 cond = (data & 0x00F00000) >> 20;
|
|
||||||
|
|
||||||
if (cond == 0) // Daaaaaaa yy0zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy00vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem != (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy0100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem != (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 1) // Daaaaaaa yy1zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy10vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem == (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy1100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem == (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 2) // Daaaaaaa yy2zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy20vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem >= (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy2100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem >= (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 3) // Daaaaaaa yy3zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy30vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem <= (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy3100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem <= (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 4) // Daaaaaaa yy4zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy40vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem & (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy4100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem & (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 5) // Daaaaaaa yy5zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy50vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (!(mem & (data & 0x0000FFFF)))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy5100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (!(mem & (data & 0x000000FF)))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 6) // Daaaaaaa yy6zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy60vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (mem | (data & 0x0000FFFF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy6100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (mem | (data & 0x000000FF))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cond == 7) // Daaaaaaa yy7zvvvv
|
|
||||||
{
|
|
||||||
if (type == 0) // Daaaaaaa yy70vvvv
|
|
||||||
{
|
|
||||||
u16 mem = memRead16(addr & 0x0FFFFFFF);
|
|
||||||
if (!(mem | (data & 0x0000FFFF)))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
else if (type == 1) // Daaaaaaa yy7100vv
|
|
||||||
{
|
|
||||||
u8 mem = memRead8(addr & 0x0FFFFFFF);
|
|
||||||
if (!(mem | (data & 0x000000FF)))
|
|
||||||
{
|
|
||||||
SkipCount = (data & 0xFF000000) >> 24;
|
|
||||||
if (!SkipCount)
|
|
||||||
{
|
|
||||||
SkipCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PrevCheatType = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only used from Patch.cpp and we don't export this in any h file.
|
|
||||||
// Patch.cpp itself declares this prototype, so make sure to keep in sync.
|
|
||||||
void _ApplyPatch(IniPatch *p)
|
|
||||||
{
|
|
||||||
u64 ledata = 0;
|
|
||||||
|
|
||||||
if (p->enabled == 0) return;
|
|
||||||
|
|
||||||
switch (p->cpu)
|
|
||||||
{
|
|
||||||
case CPU_EE:
|
|
||||||
switch (p->type)
|
|
||||||
{
|
|
||||||
case BYTE_T:
|
|
||||||
if (memRead8(p->addr) != (u8)p->data)
|
|
||||||
memWrite8(p->addr, (u8)p->data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SHORT_T:
|
|
||||||
if (memRead16(p->addr) != (u16)p->data)
|
|
||||||
memWrite16(p->addr, (u16)p->data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WORD_T:
|
|
||||||
if (memRead32(p->addr) != (u32)p->data)
|
|
||||||
memWrite32(p->addr, (u32)p->data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOUBLE_T:
|
|
||||||
if (memRead64(p->addr) != (u64)p->data)
|
|
||||||
memWrite64(p->addr, (u64)p->data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EXTENDED_T:
|
|
||||||
handle_extended_t(p);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SHORT_BE_T:
|
|
||||||
ledata = ByteSwap(static_cast<u16>(p->data));
|
|
||||||
if (memRead16(p->addr) != (u16)ledata)
|
|
||||||
memWrite16(p->addr, (u16)ledata);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WORD_BE_T:
|
|
||||||
ledata = ByteSwap(static_cast<u32>(p->data));
|
|
||||||
if (memRead32(p->addr) != (u32)ledata)
|
|
||||||
memWrite32(p->addr, (u32)ledata);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DOUBLE_BE_T:
|
|
||||||
ledata = ByteSwap(p->data);
|
|
||||||
if (memRead64(p->addr) != (u64)ledata)
|
|
||||||
memWrite64(p->addr, (u64)ledata);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CPU_IOP:
|
|
||||||
switch (p->type)
|
|
||||||
{
|
|
||||||
case BYTE_T:
|
|
||||||
if (iopMemRead8(p->addr) != (u8)p->data)
|
|
||||||
iopMemWrite8(p->addr, (u8)p->data);
|
|
||||||
break;
|
|
||||||
case SHORT_T:
|
|
||||||
if (iopMemRead16(p->addr) != (u16)p->data)
|
|
||||||
iopMemWrite16(p->addr, (u16)p->data);
|
|
||||||
break;
|
|
||||||
case WORD_T:
|
|
||||||
if (iopMemRead32(p->addr) != (u32)p->data)
|
|
||||||
iopMemWrite32(p->addr, (u32)p->data);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _ApplyDynaPatch(const DynamicPatch& patch, u32 address)
|
|
||||||
{
|
|
||||||
for (const auto& pattern : patch.pattern)
|
|
||||||
{
|
|
||||||
if (*static_cast<u32*>(PSM(address + pattern.offset)) != pattern.value)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchesCon->WriteLn("Applying Dynamic Patch to address 0x%08X", address);
|
|
||||||
// If everything passes, apply the patch.
|
|
||||||
for (const auto& replacement : patch.replacement)
|
|
||||||
{
|
|
||||||
memWrite32(address + replacement.offset, replacement.value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -100,8 +100,7 @@ namespace EmuFolders
|
||||||
std::string Langs;
|
std::string Langs;
|
||||||
std::string Logs;
|
std::string Logs;
|
||||||
std::string Cheats;
|
std::string Cheats;
|
||||||
std::string CheatsWS;
|
std::string Patches;
|
||||||
std::string CheatsNI;
|
|
||||||
std::string Resources;
|
std::string Resources;
|
||||||
std::string Cache;
|
std::string Cache;
|
||||||
std::string Covers;
|
std::string Covers;
|
||||||
|
@ -1613,8 +1612,7 @@ void EmuFolders::SetDefaults(SettingsInterface& si)
|
||||||
si.SetStringValue("Folders", "MemoryCards", "memcards");
|
si.SetStringValue("Folders", "MemoryCards", "memcards");
|
||||||
si.SetStringValue("Folders", "Logs", "logs");
|
si.SetStringValue("Folders", "Logs", "logs");
|
||||||
si.SetStringValue("Folders", "Cheats", "cheats");
|
si.SetStringValue("Folders", "Cheats", "cheats");
|
||||||
si.SetStringValue("Folders", "CheatsWS", "cheats_ws");
|
si.SetStringValue("Folders", "Patches", "patches");
|
||||||
si.SetStringValue("Folders", "CheatsNI", "cheats_ni");
|
|
||||||
si.SetStringValue("Folders", "Cache", "cache");
|
si.SetStringValue("Folders", "Cache", "cache");
|
||||||
si.SetStringValue("Folders", "Textures", "textures");
|
si.SetStringValue("Folders", "Textures", "textures");
|
||||||
si.SetStringValue("Folders", "InputProfiles", "inputprofiles");
|
si.SetStringValue("Folders", "InputProfiles", "inputprofiles");
|
||||||
|
@ -1637,8 +1635,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si)
|
||||||
MemoryCards = LoadPathFromSettings(si, DataRoot, "MemoryCards", "memcards");
|
MemoryCards = LoadPathFromSettings(si, DataRoot, "MemoryCards", "memcards");
|
||||||
Logs = LoadPathFromSettings(si, DataRoot, "Logs", "logs");
|
Logs = LoadPathFromSettings(si, DataRoot, "Logs", "logs");
|
||||||
Cheats = LoadPathFromSettings(si, DataRoot, "Cheats", "cheats");
|
Cheats = LoadPathFromSettings(si, DataRoot, "Cheats", "cheats");
|
||||||
CheatsWS = LoadPathFromSettings(si, DataRoot, "CheatsWS", "cheats_ws");
|
Patches = LoadPathFromSettings(si, DataRoot, "Patches", "patches");
|
||||||
CheatsNI = LoadPathFromSettings(si, DataRoot, "CheatsNI", "cheats_ni");
|
|
||||||
Covers = LoadPathFromSettings(si, DataRoot, "Covers", "covers");
|
Covers = LoadPathFromSettings(si, DataRoot, "Covers", "covers");
|
||||||
GameSettings = LoadPathFromSettings(si, DataRoot, "GameSettings", "gamesettings");
|
GameSettings = LoadPathFromSettings(si, DataRoot, "GameSettings", "gamesettings");
|
||||||
Cache = LoadPathFromSettings(si, DataRoot, "Cache", "cache");
|
Cache = LoadPathFromSettings(si, DataRoot, "Cache", "cache");
|
||||||
|
@ -1652,8 +1649,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si)
|
||||||
Console.WriteLn("MemoryCards Directory: %s", MemoryCards.c_str());
|
Console.WriteLn("MemoryCards Directory: %s", MemoryCards.c_str());
|
||||||
Console.WriteLn("Logs Directory: %s", Logs.c_str());
|
Console.WriteLn("Logs Directory: %s", Logs.c_str());
|
||||||
Console.WriteLn("Cheats Directory: %s", Cheats.c_str());
|
Console.WriteLn("Cheats Directory: %s", Cheats.c_str());
|
||||||
Console.WriteLn("CheatsWS Directory: %s", CheatsWS.c_str());
|
Console.WriteLn("Patches Directory: %s", Patches.c_str());
|
||||||
Console.WriteLn("CheatsNI Directory: %s", CheatsNI.c_str());
|
|
||||||
Console.WriteLn("Covers Directory: %s", Covers.c_str());
|
Console.WriteLn("Covers Directory: %s", Covers.c_str());
|
||||||
Console.WriteLn("Game Settings Directory: %s", GameSettings.c_str());
|
Console.WriteLn("Game Settings Directory: %s", GameSettings.c_str());
|
||||||
Console.WriteLn("Cache Directory: %s", Cache.c_str());
|
Console.WriteLn("Cache Directory: %s", Cache.c_str());
|
||||||
|
@ -1671,8 +1667,7 @@ bool EmuFolders::EnsureFoldersExist()
|
||||||
result = FileSystem::CreateDirectoryPath(MemoryCards.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(MemoryCards.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(Logs.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(Logs.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(Cheats.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(Cheats.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(CheatsWS.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(Patches.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(CheatsNI.c_str(), false) && result;
|
|
||||||
result = FileSystem::CreateDirectoryPath(Covers.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(Covers.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(GameSettings.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(GameSettings.c_str(), false) && result;
|
||||||
result = FileSystem::CreateDirectoryPath(Cache.c_str(), false) && result;
|
result = FileSystem::CreateDirectoryPath(Cache.c_str(), false) && result;
|
||||||
|
|
|
@ -15,57 +15,56 @@
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "VMManager.h"
|
|
||||||
#include "Achievements.h"
|
#include "Achievements.h"
|
||||||
#include "Counters.h"
|
|
||||||
#include "CDVD/CDVD.h"
|
#include "CDVD/CDVD.h"
|
||||||
|
#include "Counters.h"
|
||||||
#include "DEV9/DEV9.h"
|
#include "DEV9/DEV9.h"
|
||||||
|
#include "DebugTools/MIPSAnalyst.h"
|
||||||
|
#include "DebugTools/SymbolMap.h"
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "FW.h"
|
#include "FW.h"
|
||||||
#include "GameDatabase.h"
|
|
||||||
#include "GameList.h"
|
|
||||||
#include "GS.h"
|
#include "GS.h"
|
||||||
#include "GS/Renderers/HW/GSTextureReplacements.h"
|
#include "GS/Renderers/HW/GSTextureReplacements.h"
|
||||||
#include "GSDumpReplayer.h"
|
#include "GSDumpReplayer.h"
|
||||||
|
#include "GameDatabase.h"
|
||||||
|
#include "GameList.h"
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "ImGui/FullscreenUI.h"
|
|
||||||
#include "INISettingsInterface.h"
|
#include "INISettingsInterface.h"
|
||||||
|
#include "ImGui/FullscreenUI.h"
|
||||||
#include "Input/InputManager.h"
|
#include "Input/InputManager.h"
|
||||||
#include "IopBios.h"
|
#include "IopBios.h"
|
||||||
#include "LogSink.h"
|
#include "LogSink.h"
|
||||||
#include "MTVU.h"
|
#include "MTVU.h"
|
||||||
#include "MemoryCardFile.h"
|
#include "MemoryCardFile.h"
|
||||||
#include "Patch.h"
|
|
||||||
#include "PerformanceMetrics.h"
|
|
||||||
#include "PINE.h"
|
|
||||||
#include "R5900.h"
|
|
||||||
#include "SPU2/spu2.h"
|
|
||||||
#include "DEV9/DEV9.h"
|
|
||||||
#include "USB/USB.h"
|
|
||||||
#include "PAD/Host/PAD.h"
|
#include "PAD/Host/PAD.h"
|
||||||
#include "PCSX2Base.h"
|
#include "PCSX2Base.h"
|
||||||
#include "Sio.h"
|
#include "PINE.h"
|
||||||
#include "ps2/BiosTools.h"
|
#include "Patch.h"
|
||||||
#include "Recording/InputRecordingControls.h"
|
#include "PerformanceMetrics.h"
|
||||||
#include "DebugTools/MIPSAnalyst.h"
|
#include "R5900.h"
|
||||||
#include "DebugTools/SymbolMap.h"
|
|
||||||
#include "Recording/InputRecording.h"
|
#include "Recording/InputRecording.h"
|
||||||
|
#include "Recording/InputRecordingControls.h"
|
||||||
|
#include "SPU2/spu2.h"
|
||||||
|
#include "Sio.h"
|
||||||
|
#include "USB/USB.h"
|
||||||
|
#include "VMManager.h"
|
||||||
|
#include "ps2/BiosTools.h"
|
||||||
|
|
||||||
#include "common/Console.h"
|
#include "common/Console.h"
|
||||||
#include "common/FileSystem.h"
|
#include "common/FileSystem.h"
|
||||||
#include "common/ScopedGuard.h"
|
#include "common/ScopedGuard.h"
|
||||||
#include "common/StringUtil.h"
|
|
||||||
#include "common/SettingsWrapper.h"
|
#include "common/SettingsWrapper.h"
|
||||||
#include "common/Timer.h"
|
#include "common/StringUtil.h"
|
||||||
#include "common/Threading.h"
|
#include "common/Threading.h"
|
||||||
|
#include "common/Timer.h"
|
||||||
#include "common/emitter/tools.h"
|
#include "common/emitter/tools.h"
|
||||||
|
|
||||||
#include "IconsFontAwesome5.h"
|
#include "IconsFontAwesome5.h"
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <sstream>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef _M_X86
|
#ifdef _M_X86
|
||||||
#include "common/emitter/x86_intrin.h"
|
#include "common/emitter/x86_intrin.h"
|
||||||
|
@ -104,19 +103,17 @@ namespace VMManager
|
||||||
static bool AutoDetectSource(const std::string& filename);
|
static bool AutoDetectSource(const std::string& filename);
|
||||||
static bool ApplyBootParameters(VMBootParameters params, std::string* state_to_load);
|
static bool ApplyBootParameters(VMBootParameters params, std::string* state_to_load);
|
||||||
static bool CheckBIOSAvailability();
|
static bool CheckBIOSAvailability();
|
||||||
static void LoadPatches(const std::string& serial, u32 crc,
|
|
||||||
bool show_messages, bool show_messages_when_disabled);
|
|
||||||
static void UpdateRunningGame(bool resetting, bool game_starting, bool swapping);
|
static void UpdateRunningGame(bool resetting, bool game_starting, bool swapping);
|
||||||
|
|
||||||
static std::string GetCurrentSaveStateFileName(s32 slot);
|
static std::string GetCurrentSaveStateFileName(s32 slot);
|
||||||
static bool DoLoadState(const char* filename);
|
static bool DoLoadState(const char* filename);
|
||||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
static bool DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread, bool backup_old_state);
|
||||||
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
static void ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
||||||
const char* filename, s32 slot_for_message);
|
s32 slot_for_message);
|
||||||
static void ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
static void ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
||||||
std::string filename, s32 slot_for_message);
|
s32 slot_for_message);
|
||||||
|
|
||||||
static void UpdateInhibitScreensaver(bool allow);
|
static void UpdateInhibitScreensaver(bool allow);
|
||||||
static void SaveSessionTime();
|
static void SaveSessionTime();
|
||||||
|
@ -155,12 +152,6 @@ static std::string s_game_name;
|
||||||
static std::string s_elf_override;
|
static std::string s_elf_override;
|
||||||
static std::string s_input_profile_name;
|
static std::string s_input_profile_name;
|
||||||
static u32 s_active_game_fixes = 0;
|
static u32 s_active_game_fixes = 0;
|
||||||
static std::vector<u8> s_widescreen_cheats_data;
|
|
||||||
static bool s_widescreen_cheats_loaded = false;
|
|
||||||
static std::vector<u8> s_no_interlacing_cheats_data;
|
|
||||||
static bool s_no_interlacing_cheats_loaded = false;
|
|
||||||
static s32 s_active_widescreen_patches = 0;
|
|
||||||
static u32 s_active_no_interlacing_patches = 0;
|
|
||||||
static u32 s_frame_advance_count = 0;
|
static u32 s_frame_advance_count = 0;
|
||||||
static u32 s_mxcsr_saved;
|
static u32 s_mxcsr_saved;
|
||||||
static bool s_gs_open_on_initialize = false;
|
static bool s_gs_open_on_initialize = false;
|
||||||
|
@ -178,8 +169,7 @@ static bool s_discord_presence_active = false;
|
||||||
|
|
||||||
bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
||||||
{
|
{
|
||||||
#define COMMON_DOWNLOAD_MESSAGE \
|
#define COMMON_DOWNLOAD_MESSAGE "PCSX2 builds can be downloaded from https://pcsx2.net/downloads/"
|
||||||
"PCSX2 builds can be downloaded from https://pcsx2.net/downloads/"
|
|
||||||
|
|
||||||
#if defined(_M_X86)
|
#if defined(_M_X86)
|
||||||
// On Windows, this gets called as a global object constructor, before any of our objects are constructed.
|
// On Windows, this gets called as a global object constructor, before any of our objects are constructed.
|
||||||
|
@ -189,16 +179,20 @@ bool VMManager::PerformEarlyHardwareChecks(const char** error)
|
||||||
|
|
||||||
if (!temp_x86_caps.hasStreamingSIMD4Extensions)
|
if (!temp_x86_caps.hasStreamingSIMD4Extensions)
|
||||||
{
|
{
|
||||||
*error = "PCSX2 requires the Streaming SIMD 4.1 Extensions instruction set, which your CPU does not support.\n\n"
|
*error =
|
||||||
"SSE4.1 is now a minimum requirement for PCSX2. You should either upgrade your CPU, or use an older build such as 1.6.0.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
"PCSX2 requires the Streaming SIMD 4.1 Extensions instruction set, which your CPU does not support.\n\n"
|
||||||
|
"SSE4.1 is now a minimum requirement for PCSX2. You should either upgrade your CPU, or use an older build "
|
||||||
|
"such as 1.6.0.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if _M_SSE >= 0x0501
|
#if _M_SSE >= 0x0501
|
||||||
if (!temp_x86_caps.hasAVX || !temp_x86_caps.hasAVX2)
|
if (!temp_x86_caps.hasAVX || !temp_x86_caps.hasAVX2)
|
||||||
{
|
{
|
||||||
*error = "This build of PCSX2 requires the Advanced Vector Extensions 2 instruction set, which your CPU does not support.\n\n"
|
*error = "This build of PCSX2 requires the Advanced Vector Extensions 2 instruction set, which your CPU does "
|
||||||
"You should download and run the SSE4.1 build of PCSX2 instead, or upgrade to a CPU that supports AVX2 to use this build.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
"not support.\n\n"
|
||||||
|
"You should download and run the SSE4.1 build of PCSX2 instead, or upgrade to a CPU that supports "
|
||||||
|
"AVX2 to use this build.\n\n" COMMON_DOWNLOAD_MESSAGE;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -345,11 +339,6 @@ void VMManager::Internal::CPUThreadShutdown()
|
||||||
InputManager::CloseSources();
|
InputManager::CloseSources();
|
||||||
WaitForSaveStateFlush();
|
WaitForSaveStateFlush();
|
||||||
|
|
||||||
std::vector<u8>().swap(s_widescreen_cheats_data);
|
|
||||||
s_widescreen_cheats_loaded = false;
|
|
||||||
std::vector<u8>().swap(s_no_interlacing_cheats_data);
|
|
||||||
s_no_interlacing_cheats_loaded = false;
|
|
||||||
|
|
||||||
s_cpu_provider_pack.reset();
|
s_cpu_provider_pack.reset();
|
||||||
s_vm_memory.reset();
|
s_vm_memory.reset();
|
||||||
|
|
||||||
|
@ -395,7 +384,8 @@ void VMManager::Internal::LoadStartupSettings()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::SetDefaultSettings(SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui)
|
void VMManager::SetDefaultSettings(
|
||||||
|
SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui)
|
||||||
{
|
{
|
||||||
if (si.GetUIntValue("UI", "SettingsVersion", 0u) != SETTINGS_VERSION)
|
if (si.GetUIntValue("UI", "SettingsVersion", 0u) != SETTINGS_VERSION)
|
||||||
si.SetUIntValue("UI", "SettingsVersion", SETTINGS_VERSION);
|
si.SetUIntValue("UI", "SettingsVersion", SETTINGS_VERSION);
|
||||||
|
@ -433,6 +423,7 @@ void VMManager::LoadSettings()
|
||||||
InputManager::ReloadSources(*si, lock);
|
InputManager::ReloadSources(*si, lock);
|
||||||
InputManager::ReloadBindings(*si, *Host::GetSettingsInterfaceForBindings());
|
InputManager::ReloadBindings(*si, *Host::GetSettingsInterfaceForBindings());
|
||||||
LogSink::UpdateLogging(*si);
|
LogSink::UpdateLogging(*si);
|
||||||
|
Patch::ApplyPatchSettingOverrides();
|
||||||
|
|
||||||
// Achievements hardcore mode disallows setting some configuration options.
|
// Achievements hardcore mode disallows setting some configuration options.
|
||||||
EnforceAchievementsChallengeModeSettings();
|
EnforceAchievementsChallengeModeSettings();
|
||||||
|
@ -441,20 +432,6 @@ void VMManager::LoadSettings()
|
||||||
EmuConfig.GS.MaskUserHacks();
|
EmuConfig.GS.MaskUserHacks();
|
||||||
EmuConfig.GS.MaskUpscalingHacks();
|
EmuConfig.GS.MaskUpscalingHacks();
|
||||||
|
|
||||||
// Disable interlacing if we have no-interlacing patches active.
|
|
||||||
if (s_active_no_interlacing_patches > 0 && EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic)
|
|
||||||
EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off;
|
|
||||||
|
|
||||||
// Switch to 16:9 if widescreen patches are enabled, and AR is auto.
|
|
||||||
if (s_active_widescreen_patches > 0 && EmuConfig.GS.AspectRatio == AspectRatioType::RAuto4_3_3_2)
|
|
||||||
{
|
|
||||||
// Don't change when reloading settings in the middle of a FMV with switch.
|
|
||||||
if (EmuConfig.CurrentAspectRatio == EmuConfig.GS.AspectRatio)
|
|
||||||
EmuConfig.CurrentAspectRatio = AspectRatioType::R16_9;
|
|
||||||
|
|
||||||
EmuConfig.GS.AspectRatio = AspectRatioType::R16_9;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force MTVU off when playing back GS dumps, it doesn't get used.
|
// Force MTVU off when playing back GS dumps, it doesn't get used.
|
||||||
if (GSDumpReplayer::IsReplayingDump())
|
if (GSDumpReplayer::IsReplayingDump())
|
||||||
EmuConfig.Speedhacks.vuThread = false;
|
EmuConfig.Speedhacks.vuThread = false;
|
||||||
|
@ -517,8 +494,7 @@ std::string VMManager::GetInputProfilePath(const std::string_view& name)
|
||||||
void VMManager::Internal::UpdateEmuFolders()
|
void VMManager::Internal::UpdateEmuFolders()
|
||||||
{
|
{
|
||||||
const std::string old_cheats_directory(EmuFolders::Cheats);
|
const std::string old_cheats_directory(EmuFolders::Cheats);
|
||||||
const std::string old_cheats_ws_directory(EmuFolders::CheatsWS);
|
const std::string old_patches_directory(EmuFolders::Patches);
|
||||||
const std::string old_cheats_ni_directory(EmuFolders::CheatsNI);
|
|
||||||
const std::string old_memcards_directory(EmuFolders::MemoryCards);
|
const std::string old_memcards_directory(EmuFolders::MemoryCards);
|
||||||
const std::string old_textures_directory(EmuFolders::Textures);
|
const std::string old_textures_directory(EmuFolders::Textures);
|
||||||
const std::string old_videos_directory(EmuFolders::Videos);
|
const std::string old_videos_directory(EmuFolders::Videos);
|
||||||
|
@ -529,11 +505,8 @@ void VMManager::Internal::UpdateEmuFolders()
|
||||||
|
|
||||||
if (VMManager::HasValidVM())
|
if (VMManager::HasValidVM())
|
||||||
{
|
{
|
||||||
if (EmuFolders::Cheats != old_cheats_directory || EmuFolders::CheatsWS != old_cheats_ws_directory ||
|
if (EmuFolders::Cheats != old_cheats_directory || EmuFolders::Patches != old_patches_directory)
|
||||||
EmuFolders::CheatsNI != old_cheats_ni_directory)
|
Patch::ReloadPatches(s_game_serial, s_game_crc, true, false, true);
|
||||||
{
|
|
||||||
VMManager::ReloadPatches(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EmuFolders::MemoryCards != old_memcards_directory)
|
if (EmuFolders::MemoryCards != old_memcards_directory)
|
||||||
{
|
{
|
||||||
|
@ -679,7 +652,8 @@ bool VMManager::UpdateGameSettingsLayer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Host::Internal::SetInputSettingsLayer(input_interface ? input_interface.get() : Host::Internal::GetBaseSettingsLayer());
|
Host::Internal::SetInputSettingsLayer(
|
||||||
|
input_interface ? input_interface.get() : Host::Internal::GetBaseSettingsLayer());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -692,144 +666,6 @@ bool VMManager::UpdateGameSettingsLayer()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::LoadPatches(const std::string& serial, u32 crc, bool show_messages, bool show_messages_when_disabled)
|
|
||||||
{
|
|
||||||
const std::string crc_string(fmt::format("{:08X}", crc));
|
|
||||||
s_patches_crc = crc;
|
|
||||||
s_active_widescreen_patches = 0;
|
|
||||||
s_active_no_interlacing_patches = 0;
|
|
||||||
ForgetLoadedPatches();
|
|
||||||
|
|
||||||
std::string message;
|
|
||||||
|
|
||||||
int patch_count = 0;
|
|
||||||
if (EmuConfig.EnablePatches)
|
|
||||||
{
|
|
||||||
const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(serial);
|
|
||||||
if (game)
|
|
||||||
{
|
|
||||||
const std::string* patches = game->findPatch(crc);
|
|
||||||
if (patches && (patch_count = LoadPatchesFromString(*patches)) > 0)
|
|
||||||
{
|
|
||||||
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patch_count);
|
|
||||||
fmt::format_to(std::back_inserter(message), "{} game patches", patch_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadDynamicPatches(game->dynaPatches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// regular cheat patches
|
|
||||||
int cheat_count = 0;
|
|
||||||
if (EmuConfig.EnableCheats)
|
|
||||||
{
|
|
||||||
cheat_count = LoadPatchesFromDir(crc_string, EmuFolders::Cheats, "Cheats", true);
|
|
||||||
if (cheat_count > 0)
|
|
||||||
{
|
|
||||||
PatchesCon->WriteLn(Color_Green, "Cheats Loaded: %d", cheat_count);
|
|
||||||
fmt::format_to(std::back_inserter(message), "{}{} cheat patches", (patch_count > 0) ? " and " : "", cheat_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wide screen patches
|
|
||||||
if (EmuConfig.EnableWideScreenPatches && crc != 0)
|
|
||||||
{
|
|
||||||
if (!Achievements::ChallengeModeActive() && (s_active_widescreen_patches = LoadPatchesFromDir(crc_string, EmuFolders::CheatsWS, "Widescreen hacks", false)) > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLn(Color_Gray, "Found widescreen patches in the cheats_ws folder --> skipping cheats_ws.zip");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No ws cheat files found at the cheats_ws folder, try the ws cheats zip file.
|
|
||||||
if (!s_widescreen_cheats_loaded)
|
|
||||||
{
|
|
||||||
s_widescreen_cheats_loaded = true;
|
|
||||||
|
|
||||||
std::optional<std::vector<u8>> data = Host::ReadResourceFile("cheats_ws.zip");
|
|
||||||
if (data.has_value())
|
|
||||||
s_widescreen_cheats_data = std::move(data.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s_widescreen_cheats_data.empty())
|
|
||||||
{
|
|
||||||
s_active_widescreen_patches = LoadPatchesFromZip(crc_string, s_widescreen_cheats_data.data(), s_widescreen_cheats_data.size());
|
|
||||||
PatchesCon->WriteLn(Color_Green, "(Wide Screen Cheats DB) Patches Loaded: %d", s_active_widescreen_patches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_active_widescreen_patches > 0)
|
|
||||||
{
|
|
||||||
fmt::format_to(std::back_inserter(message), "{}{} widescreen patches", (patch_count > 0 || cheat_count > 0) ? " and " : "", s_active_widescreen_patches);
|
|
||||||
|
|
||||||
// Switch to 16:9 if widescreen patches are enabled, and AR is auto.
|
|
||||||
if (EmuConfig.GS.AspectRatio == AspectRatioType::RAuto4_3_3_2)
|
|
||||||
{
|
|
||||||
// Don't change when reloading settings in the middle of a FMV with switch.
|
|
||||||
if (EmuConfig.CurrentAspectRatio == EmuConfig.GS.AspectRatio)
|
|
||||||
EmuConfig.CurrentAspectRatio = AspectRatioType::R16_9;
|
|
||||||
|
|
||||||
EmuConfig.GS.AspectRatio = AspectRatioType::R16_9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no-interlacing patches
|
|
||||||
if (EmuConfig.EnableNoInterlacingPatches && crc != 0)
|
|
||||||
{
|
|
||||||
if (!Achievements::ChallengeModeActive() && (s_active_no_interlacing_patches = LoadPatchesFromDir(crc_string, EmuFolders::CheatsNI, "No-interlacing patches", false)) > 0)
|
|
||||||
{
|
|
||||||
Console.WriteLn(Color_Gray, "Found no-interlacing patches in the cheats_ni folder --> skipping cheats_ni.zip");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No ws cheat files found at the cheats_ws folder, try the ws cheats zip file.
|
|
||||||
if (!s_no_interlacing_cheats_loaded)
|
|
||||||
{
|
|
||||||
s_no_interlacing_cheats_loaded = true;
|
|
||||||
|
|
||||||
std::optional<std::vector<u8>> data = Host::ReadResourceFile("cheats_ni.zip");
|
|
||||||
if (data.has_value())
|
|
||||||
s_no_interlacing_cheats_data = std::move(data.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s_no_interlacing_cheats_data.empty())
|
|
||||||
{
|
|
||||||
s_active_no_interlacing_patches = LoadPatchesFromZip(crc_string, s_no_interlacing_cheats_data.data(), s_no_interlacing_cheats_data.size());
|
|
||||||
PatchesCon->WriteLn(Color_Green, "(No-Interlacing Cheats DB) Patches Loaded: %u", s_active_no_interlacing_patches);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_active_no_interlacing_patches > 0)
|
|
||||||
{
|
|
||||||
fmt::format_to(std::back_inserter(message), "{}{} no-interlacing patches", (patch_count > 0 || cheat_count > 0 || s_active_widescreen_patches > 0) ? " and " : "", s_active_no_interlacing_patches);
|
|
||||||
|
|
||||||
// Disable interlacing in GS if active.
|
|
||||||
if (EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic)
|
|
||||||
{
|
|
||||||
EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off;
|
|
||||||
GetMTGS().ApplySettings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_active_no_interlacing_patches = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_messages)
|
|
||||||
{
|
|
||||||
if (cheat_count > 0 || s_active_widescreen_patches > 0 || s_active_no_interlacing_patches > 0)
|
|
||||||
{
|
|
||||||
message += " are active.";
|
|
||||||
Host::AddIconOSDMessage("LoadPatches", ICON_FA_FILE_CODE, message, Host::OSD_INFO_DURATION);
|
|
||||||
}
|
|
||||||
else if (show_messages_when_disabled)
|
|
||||||
{
|
|
||||||
Host::AddIconOSDMessage("LoadPatches", ICON_FA_FILE_CODE, "No cheats or patches (widescreen, compatibility or others) are found / enabled.", Host::OSD_INFO_DURATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void VMManager::UpdateRunningGame(bool resetting, bool game_starting, bool swapping_disc)
|
void VMManager::UpdateRunningGame(bool resetting, bool game_starting, bool swapping_disc)
|
||||||
{
|
{
|
||||||
// The CRC can be known before the game actually starts (at the bios), so when
|
// The CRC can be known before the game actually starts (at the bios), so when
|
||||||
|
@ -887,7 +723,16 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting, bool swapp
|
||||||
Console.WriteLn(Color_StrongGreen, fmt::format(" Serial: {}", s_game_serial));
|
Console.WriteLn(Color_StrongGreen, fmt::format(" Serial: {}", s_game_serial));
|
||||||
Console.WriteLn(Color_StrongGreen, fmt::format(" CRC: {:08X}", s_game_crc));
|
Console.WriteLn(Color_StrongGreen, fmt::format(" CRC: {:08X}", s_game_crc));
|
||||||
|
|
||||||
|
// When resetting, patches need to get removed here, because there's no entry point being compiled.
|
||||||
|
if (resetting)
|
||||||
|
Patch::ReloadPatches(s_game_serial, s_game_crc, false, false, false);
|
||||||
|
|
||||||
UpdateGameSettingsLayer();
|
UpdateGameSettingsLayer();
|
||||||
|
|
||||||
|
// Must be done before ApplySettings(), so WS/NI configs are picked up.
|
||||||
|
// Actual patch files get loaded on the entry point compiling.
|
||||||
|
Patch::UpdateActivePatches(true, false, s_game_crc != 0);
|
||||||
|
|
||||||
ApplySettings();
|
ApplySettings();
|
||||||
|
|
||||||
if (!swapping_disc)
|
if (!swapping_disc)
|
||||||
|
@ -897,11 +742,8 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting, bool swapp
|
||||||
if (game_starting || resetting)
|
if (game_starting || resetting)
|
||||||
AutoEject::ClearAll();
|
AutoEject::ClearAll();
|
||||||
|
|
||||||
// Check this here, for two cases: dynarec on, and when enable cheats is set per-game.
|
MIPSAnalyst::ScanForFunctions(
|
||||||
if (s_patches_crc != s_game_crc)
|
R5900SymbolMap, ElfTextRange.first, ElfTextRange.first + ElfTextRange.second, true);
|
||||||
ReloadPatches(game_starting, false);
|
|
||||||
|
|
||||||
MIPSAnalyst::ScanForFunctions(R5900SymbolMap, ElfTextRange.first, ElfTextRange.first + ElfTextRange.second, true);
|
|
||||||
R5900SymbolMap.UpdateActiveSymbols();
|
R5900SymbolMap.UpdateActiveSymbols();
|
||||||
R3000SymbolMap.UpdateActiveSymbols();
|
R3000SymbolMap.UpdateActiveSymbols();
|
||||||
}
|
}
|
||||||
|
@ -920,11 +762,6 @@ void VMManager::UpdateRunningGame(bool resetting, bool game_starting, bool swapp
|
||||||
Host::OnGameChanged(s_disc_path, s_elf_override, s_game_serial, s_game_name, s_game_crc);
|
Host::OnGameChanged(s_disc_path, s_elf_override, s_game_serial, s_game_name, s_game_crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ReloadPatches(bool verbose, bool show_messages_when_disabled)
|
|
||||||
{
|
|
||||||
LoadPatches(s_game_serial, s_game_crc, verbose, show_messages_when_disabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
static LimiterModeType GetInitialLimiterMode()
|
static LimiterModeType GetInitialLimiterMode()
|
||||||
{
|
{
|
||||||
return EmuConfig.GS.FrameLimitEnable ? LimiterModeType::Nominal : LimiterModeType::Unlimited;
|
return EmuConfig.GS.FrameLimitEnable ? LimiterModeType::Nominal : LimiterModeType::Unlimited;
|
||||||
|
@ -1068,8 +905,10 @@ bool VMManager::CheckBIOSAvailability()
|
||||||
// TODO: When we translate core strings, translate this.
|
// TODO: When we translate core strings, translate this.
|
||||||
|
|
||||||
const char* message = "PCSX2 requires a PS2 BIOS in order to run.\n\n"
|
const char* message = "PCSX2 requires a PS2 BIOS in order to run.\n\n"
|
||||||
"For legal reasons, you *must* obtain a BIOS from an actual PS2 unit that you own (borrowing doesn't count).\n\n"
|
"For legal reasons, you *must* obtain a BIOS from an actual PS2 unit that you own (borrowing "
|
||||||
"Once dumped, this BIOS image should be placed in the bios folder within the data directory (Tools Menu -> Open Data Directory).\n\n"
|
"doesn't count).\n\n"
|
||||||
|
"Once dumped, this BIOS image should be placed in the bios folder within the data directory "
|
||||||
|
"(Tools Menu -> Open Data Directory).\n\n"
|
||||||
"Please consult the FAQs and Guides for further instructions.";
|
"Please consult the FAQs and Guides for further instructions.";
|
||||||
|
|
||||||
Host::ReportErrorAsync("Startup Error", message);
|
Host::ReportErrorAsync("Startup Error", message);
|
||||||
|
@ -1168,9 +1007,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
Host::ReportErrorAsync("Startup Error", "Failed to initialize USB.");
|
Host::ReportErrorAsync("Startup Error", "Failed to initialize USB.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedGuard close_usb = []() {
|
ScopedGuard close_usb = []() { USBclose(); };
|
||||||
USBclose();
|
|
||||||
};
|
|
||||||
|
|
||||||
Console.WriteLn("Opening FW...");
|
Console.WriteLn("Opening FW...");
|
||||||
if (FWopen() != 0)
|
if (FWopen() != 0)
|
||||||
|
@ -1204,7 +1041,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
memBindConditionalHandlers();
|
memBindConditionalHandlers();
|
||||||
|
|
||||||
ForgetLoadedPatches();
|
|
||||||
gsUpdateFrequency(EmuConfig);
|
gsUpdateFrequency(EmuConfig);
|
||||||
frameLimitReset();
|
frameLimitReset();
|
||||||
cpuReset();
|
cpuReset();
|
||||||
|
@ -1279,8 +1115,6 @@ void VMManager::Shutdown(bool save_resume_state)
|
||||||
Host::OnGameChanged(s_disc_path, s_elf_override, s_game_serial, s_game_name, 0);
|
Host::OnGameChanged(s_disc_path, s_elf_override, s_game_serial, s_game_name, 0);
|
||||||
}
|
}
|
||||||
s_active_game_fixes = 0;
|
s_active_game_fixes = 0;
|
||||||
s_active_widescreen_patches = 0;
|
|
||||||
s_active_no_interlacing_patches = 0;
|
|
||||||
|
|
||||||
UpdateGameSettingsLayer();
|
UpdateGameSettingsLayer();
|
||||||
|
|
||||||
|
@ -1292,7 +1126,7 @@ void VMManager::Shutdown(bool save_resume_state)
|
||||||
a64_setfpcr(s_mxcsr_saved);
|
a64_setfpcr(s_mxcsr_saved);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ForgetLoadedPatches();
|
Patch::UnloadPatches();
|
||||||
R3000A::ioman::reset();
|
R3000A::ioman::reset();
|
||||||
vtlb_Shutdown();
|
vtlb_Shutdown();
|
||||||
USBclose();
|
USBclose();
|
||||||
|
@ -1350,8 +1184,6 @@ void VMManager::Reset()
|
||||||
const bool game_was_started = g_GameStarted;
|
const bool game_was_started = g_GameStarted;
|
||||||
|
|
||||||
s_active_game_fixes = 0;
|
s_active_game_fixes = 0;
|
||||||
s_active_widescreen_patches = 0;
|
|
||||||
s_active_no_interlacing_patches = 0;
|
|
||||||
|
|
||||||
SysClearExecutionCache();
|
SysClearExecutionCache();
|
||||||
memBindConditionalHandlers();
|
memBindConditionalHandlers();
|
||||||
|
@ -1460,7 +1292,8 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||||
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
if (!FileSystem::RenamePath(filename, backup_filename.c_str()))
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
||||||
fmt::format("Failed to back up old save state {}.", Path::GetFileName(filename)), Host::OSD_ERROR_DURATION);
|
fmt::format("Failed to back up old save state {}.", Path::GetFileName(filename)),
|
||||||
|
Host::OSD_ERROR_DURATION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1468,9 +1301,8 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||||
{
|
{
|
||||||
// lock order here is important; the thread could exit before we resume here.
|
// lock order here is important; the thread could exit before we resume here.
|
||||||
std::unique_lock lock(s_save_state_threads_mutex);
|
std::unique_lock lock(s_save_state_threads_mutex);
|
||||||
s_save_state_threads.emplace_back(&VMManager::ZipSaveStateOnThread,
|
s_save_state_threads.emplace_back(&VMManager::ZipSaveStateOnThread, std::move(elist), std::move(screenshot),
|
||||||
std::move(elist), std::move(screenshot), std::move(osd_key), std::string(filename),
|
std::move(osd_key), std::string(filename), slot_for_message);
|
||||||
slot_for_message);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1482,35 +1314,36 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip
|
||||||
}
|
}
|
||||||
catch (Exception::BaseException& e)
|
catch (Exception::BaseException& e)
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("Failed to save save state: {}.", e.DiagMsg()),
|
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
||||||
Host::OSD_ERROR_DURATION);
|
fmt::format("Failed to save save state: {}.", e.DiagMsg()), Host::OSD_ERROR_DURATION);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
void VMManager::ZipSaveState(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key,
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, const char* filename,
|
||||||
const char* filename, s32 slot_for_message)
|
s32 slot_for_message)
|
||||||
{
|
{
|
||||||
Common::Timer timer;
|
Common::Timer timer;
|
||||||
|
|
||||||
if (SaveState_ZipToDisk(std::move(elist), std::move(screenshot), filename))
|
if (SaveState_ZipToDisk(std::move(elist), std::move(screenshot), filename))
|
||||||
{
|
{
|
||||||
if (slot_for_message >= 0 && VMManager::HasValidVM())
|
if (slot_for_message >= 0 && VMManager::HasValidVM())
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_SAVE, fmt::format("State saved to slot {}.", slot_for_message),
|
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_SAVE,
|
||||||
Host::OSD_QUICK_DURATION);
|
fmt::format("State saved to slot {}.", slot_for_message), Host::OSD_QUICK_DURATION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("Failed to save save state to slot {}.", slot_for_message),
|
Host::AddIconOSDMessage(std::move(osd_key), ICON_FA_EXCLAMATION_TRIANGLE,
|
||||||
Host::OSD_ERROR_DURATION);
|
fmt::format("Failed to save save state to slot {}.", slot_for_message), Host::OSD_ERROR_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
DevCon.WriteLn("Zipping save state to '%s' took %.2f ms", filename, timer.GetTimeMilliseconds());
|
DevCon.WriteLn("Zipping save state to '%s' took %.2f ms", filename, timer.GetTimeMilliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist, std::unique_ptr<SaveStateScreenshotData> screenshot,
|
void VMManager::ZipSaveStateOnThread(std::unique_ptr<ArchiveEntryList> elist,
|
||||||
std::string osd_key, std::string filename, s32 slot_for_message)
|
std::unique_ptr<SaveStateScreenshotData> screenshot, std::string osd_key, std::string filename,
|
||||||
|
s32 slot_for_message)
|
||||||
{
|
{
|
||||||
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename.c_str(), slot_for_message);
|
ZipSaveState(std::move(elist), std::move(screenshot), std::move(osd_key), filename.c_str(), slot_for_message);
|
||||||
|
|
||||||
|
@ -1568,8 +1401,7 @@ u32 VMManager::DeleteSaveStates(const char* game_serial, u32 game_crc, bool also
|
||||||
bool VMManager::LoadState(const char* filename)
|
bool VMManager::LoadState(const char* filename)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_ACHIEVEMENTS
|
#ifdef ENABLE_ACHIEVEMENTS
|
||||||
if (Achievements::ChallengeModeActive() &&
|
if (Achievements::ChallengeModeActive() && !Achievements::ConfirmChallengeModeDisable("Loading state"))
|
||||||
!Achievements::ConfirmChallengeModeDisable("Loading state"))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1588,19 +1420,20 @@ bool VMManager::LoadStateFromSlot(s32 slot)
|
||||||
const std::string filename(GetCurrentSaveStateFileName(slot));
|
const std::string filename(GetCurrentSaveStateFileName(slot));
|
||||||
if (filename.empty())
|
if (filename.empty())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("There is no save state in slot {}.", slot), 5.0f);
|
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||||
|
fmt::format("There is no save state in slot {}.", slot), 5.0f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_ACHIEVEMENTS
|
#ifdef ENABLE_ACHIEVEMENTS
|
||||||
if (Achievements::ChallengeModeActive() &&
|
if (Achievements::ChallengeModeActive() && !Achievements::ConfirmChallengeModeDisable("Loading state"))
|
||||||
!Achievements::ConfirmChallengeModeDisable("Loading state"))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN, fmt::format("Loading state from slot {}...", slot), Host::OSD_QUICK_DURATION);
|
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
|
||||||
|
fmt::format("Loading state from slot {}...", slot), Host::OSD_QUICK_DURATION);
|
||||||
return DoLoadState(filename.c_str());
|
return DoLoadState(filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1616,7 +1449,8 @@ bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// if it takes more than a minute.. well.. wtf.
|
// if it takes more than a minute.. well.. wtf.
|
||||||
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_SAVE, fmt::format("Saving state to slot {}...", slot), 60.0f);
|
Host::AddIconOSDMessage(
|
||||||
|
fmt::format("SaveStateSlot{}", slot), ICON_FA_SAVE, fmt::format("Saving state to slot {}...", slot), 60.0f);
|
||||||
return DoSaveState(filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate);
|
return DoSaveState(filename.c_str(), slot, zip_on_thread, EmuConfig.BackupSavestate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1665,18 +1499,21 @@ bool VMManager::ChangeDisc(CDVD_SourceType source, std::string path)
|
||||||
if (source == CDVD_SourceType::NoDisc)
|
if (source == CDVD_SourceType::NoDisc)
|
||||||
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, "Disc removed.", Host::OSD_INFO_DURATION);
|
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, "Disc removed.", Host::OSD_INFO_DURATION);
|
||||||
else
|
else
|
||||||
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, fmt::format("Disc changed to '{}'.", display_name), Host::OSD_INFO_DURATION);
|
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC,
|
||||||
|
fmt::format("Disc changed to '{}'.", display_name), Host::OSD_INFO_DURATION);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, fmt::format("Failed to open new disc image '{}'. Reverting to old image.", display_name),
|
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC,
|
||||||
|
fmt::format("Failed to open new disc image '{}'. Reverting to old image.", display_name),
|
||||||
Host::OSD_ERROR_DURATION);
|
Host::OSD_ERROR_DURATION);
|
||||||
CDVDsys_ChangeSource(old_type);
|
CDVDsys_ChangeSource(old_type);
|
||||||
if (!old_path.empty())
|
if (!old_path.empty())
|
||||||
CDVDsys_SetFile(old_type, std::move(old_path));
|
CDVDsys_SetFile(old_type, std::move(old_path));
|
||||||
if (!DoCDVDopen())
|
if (!DoCDVDopen())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, "Failed to switch back to old disc image. Removing disc.", Host::OSD_CRITICAL_ERROR_DURATION);
|
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC,
|
||||||
|
"Failed to switch back to old disc image. Removing disc.", Host::OSD_CRITICAL_ERROR_DURATION);
|
||||||
CDVDsys_ChangeSource(CDVD_SourceType::NoDisc);
|
CDVDsys_ChangeSource(CDVD_SourceType::NoDisc);
|
||||||
DoCDVDopen();
|
DoCDVDopen();
|
||||||
}
|
}
|
||||||
|
@ -1698,8 +1535,7 @@ bool VMManager::IsBlockDumpFileName(const std::string_view& path)
|
||||||
|
|
||||||
bool VMManager::IsGSDumpFileName(const std::string_view& path)
|
bool VMManager::IsGSDumpFileName(const std::string_view& path)
|
||||||
{
|
{
|
||||||
return (StringUtil::EndsWithNoCase(path, ".gs") ||
|
return (StringUtil::EndsWithNoCase(path, ".gs") || StringUtil::EndsWithNoCase(path, ".gs.xz") ||
|
||||||
StringUtil::EndsWithNoCase(path, ".gs.xz") ||
|
|
||||||
StringUtil::EndsWithNoCase(path, ".gs.zst"));
|
StringUtil::EndsWithNoCase(path, ".gs.zst"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1778,15 +1614,16 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread()
|
||||||
// until the game entry point actually runs, because that can update settings, which
|
// until the game entry point actually runs, because that can update settings, which
|
||||||
// can flush the JIT, etc. But we need to apply patches for games where the entry
|
// can flush the JIT, etc. But we need to apply patches for games where the entry
|
||||||
// point is in the patch (e.g. WRC 4). So. Gross, but the only way to handle it really.
|
// point is in the patch (e.g. WRC 4). So. Gross, but the only way to handle it really.
|
||||||
LoadPatches(SysGetDiscID(), ElfCRC, true, false);
|
Patch::ReloadPatches(SysGetDiscID(), ElfCRC, false, false, false);
|
||||||
ApplyLoadedPatches(PPT_ONCE_ON_LOAD);
|
Patch::ApplyLoadedPatches(Patch::PPT_ONCE_ON_LOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::Internal::GameStartingOnCPUThread()
|
void VMManager::Internal::GameStartingOnCPUThread()
|
||||||
{
|
{
|
||||||
|
// See note above.
|
||||||
UpdateRunningGame(false, true, false);
|
UpdateRunningGame(false, true, false);
|
||||||
ApplyLoadedPatches(PPT_ONCE_ON_LOAD);
|
Patch::ApplyLoadedPatches(Patch::PPT_ONCE_ON_LOAD);
|
||||||
ApplyLoadedPatches(PPT_COMBINED_0_1);
|
Patch::ApplyLoadedPatches(Patch::PPT_COMBINED_0_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::Internal::SwappingGameOnCPUThread()
|
void VMManager::Internal::SwappingGameOnCPUThread()
|
||||||
|
@ -1797,8 +1634,8 @@ void VMManager::Internal::SwappingGameOnCPUThread()
|
||||||
void VMManager::Internal::VSyncOnCPUThread()
|
void VMManager::Internal::VSyncOnCPUThread()
|
||||||
{
|
{
|
||||||
// TODO: Move frame limiting here to reduce CPU usage after sleeping...
|
// TODO: Move frame limiting here to reduce CPU usage after sleeping...
|
||||||
ApplyLoadedPatches(PPT_CONTINUOUSLY);
|
Patch::ApplyLoadedPatches(Patch::PPT_CONTINUOUSLY);
|
||||||
ApplyLoadedPatches(PPT_COMBINED_0_1);
|
Patch::ApplyLoadedPatches(Patch::PPT_COMBINED_0_1);
|
||||||
|
|
||||||
// Frame advance must be done *before* pumping messages, because otherwise
|
// Frame advance must be done *before* pumping messages, because otherwise
|
||||||
// we'll immediately reduce the counter we just set.
|
// we'll immediately reduce the counter we just set.
|
||||||
|
@ -1841,10 +1678,8 @@ void VMManager::Internal::VSyncOnCPUThread()
|
||||||
|
|
||||||
void VMManager::CheckForCPUConfigChanges(const Pcsx2Config& old_config)
|
void VMManager::CheckForCPUConfigChanges(const Pcsx2Config& old_config)
|
||||||
{
|
{
|
||||||
if (EmuConfig.Cpu == old_config.Cpu &&
|
if (EmuConfig.Cpu == old_config.Cpu && EmuConfig.Gamefixes == old_config.Gamefixes &&
|
||||||
EmuConfig.Gamefixes == old_config.Gamefixes &&
|
EmuConfig.Speedhacks == old_config.Speedhacks && EmuConfig.Profiler == old_config.Profiler)
|
||||||
EmuConfig.Speedhacks == old_config.Speedhacks &&
|
|
||||||
EmuConfig.Profiler == old_config.Profiler)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1904,12 +1739,18 @@ void VMManager::CheckForPatchConfigChanges(const Pcsx2Config& old_config)
|
||||||
{
|
{
|
||||||
if (EmuConfig.EnableCheats == old_config.EnableCheats &&
|
if (EmuConfig.EnableCheats == old_config.EnableCheats &&
|
||||||
EmuConfig.EnableWideScreenPatches == old_config.EnableWideScreenPatches &&
|
EmuConfig.EnableWideScreenPatches == old_config.EnableWideScreenPatches &&
|
||||||
|
EmuConfig.EnableNoInterlacingPatches == old_config.EnableNoInterlacingPatches &&
|
||||||
EmuConfig.EnablePatches == old_config.EnablePatches)
|
EmuConfig.EnablePatches == old_config.EnablePatches)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadPatches(true, true);
|
Patch::UpdateActivePatches(true, false, true);
|
||||||
|
|
||||||
|
// This is a bit messy, because the patch config update happens after the settings are loaded,
|
||||||
|
// if we disable widescreen patches, we have to reload the original settings again.
|
||||||
|
if (Patch::ReloadPatchAffectingOptions())
|
||||||
|
GetMTGS().ApplySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMManager::CheckForDEV9ConfigChanges(const Pcsx2Config& old_config)
|
void VMManager::CheckForDEV9ConfigChanges(const Pcsx2Config& old_config)
|
||||||
|
@ -1997,13 +1838,6 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config)
|
||||||
CheckForDEV9ConfigChanges(old_config);
|
CheckForDEV9ConfigChanges(old_config);
|
||||||
CheckForMemoryCardConfigChanges(old_config);
|
CheckForMemoryCardConfigChanges(old_config);
|
||||||
USB::CheckForConfigChanges(old_config);
|
USB::CheckForConfigChanges(old_config);
|
||||||
|
|
||||||
if (EmuConfig.EnableCheats != old_config.EnableCheats ||
|
|
||||||
EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches ||
|
|
||||||
EmuConfig.EnableNoInterlacingPatches != old_config.EnableNoInterlacingPatches)
|
|
||||||
{
|
|
||||||
VMManager::ReloadPatches(true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the big picture UI, we still need to update GS settings, since it's running,
|
// For the big picture UI, we still need to update GS settings, since it's running,
|
||||||
|
@ -2048,6 +1882,8 @@ bool VMManager::ReloadGameSettings()
|
||||||
if (!UpdateGameSettingsLayer())
|
if (!UpdateGameSettingsLayer())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Patches must come first, because they can affect aspect ratio/interlacing.
|
||||||
|
Patch::UpdateActivePatches(true, false, true);
|
||||||
ApplySettings();
|
ApplySettings();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2070,7 +1906,8 @@ void VMManager::EnforceAchievementsChallengeModeSettings()
|
||||||
// Can't use cheats.
|
// Can't use cheats.
|
||||||
if (EmuConfig.EnableCheats)
|
if (EmuConfig.EnableCheats)
|
||||||
{
|
{
|
||||||
Host::AddKeyedOSDMessage("ChallengeDisableCheats", "Cheats have been disabled due to achievements hardcore mode.", Host::OSD_WARNING_DURATION);
|
Host::AddKeyedOSDMessage("ChallengeDisableCheats",
|
||||||
|
"Cheats have been disabled due to achievements hardcore mode.", Host::OSD_WARNING_DURATION);
|
||||||
EmuConfig.EnableCheats = false;
|
EmuConfig.EnableCheats = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2083,7 +1920,8 @@ void VMManager::EnforceAchievementsChallengeModeSettings()
|
||||||
EmuConfig.GS.FrameratePAL = Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL;
|
EmuConfig.GS.FrameratePAL = Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL;
|
||||||
|
|
||||||
// You can overclock, but not underclock (since that might slow down the game and make it easier).
|
// You can overclock, but not underclock (since that might slow down the game and make it easier).
|
||||||
EmuConfig.Speedhacks.EECycleRate = std::max<decltype(EmuConfig.Speedhacks.EECycleRate)>(EmuConfig.Speedhacks.EECycleRate, 0);
|
EmuConfig.Speedhacks.EECycleRate =
|
||||||
|
std::max<decltype(EmuConfig.Speedhacks.EECycleRate)>(EmuConfig.Speedhacks.EECycleRate, 0);
|
||||||
EmuConfig.Speedhacks.EECycleSkip = 0;
|
EmuConfig.Speedhacks.EECycleSkip = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2114,7 +1952,8 @@ void VMManager::WarnAboutUnsafeSettings()
|
||||||
if (EmuConfig.Speedhacks.fastCDVD)
|
if (EmuConfig.Speedhacks.fastCDVD)
|
||||||
messages += ICON_FA_COMPACT_DISC " Fast CDVD is enabled, this may break games.\n";
|
messages += ICON_FA_COMPACT_DISC " Fast CDVD is enabled, this may break games.\n";
|
||||||
if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0)
|
if (EmuConfig.Speedhacks.EECycleRate != 0 || EmuConfig.Speedhacks.EECycleSkip != 0)
|
||||||
messages += ICON_FA_TACHOMETER_ALT " Cycle rate/skip is not at default, this may crash or make games run too slow.\n";
|
messages +=
|
||||||
|
ICON_FA_TACHOMETER_ALT " Cycle rate/skip is not at default, this may crash or make games run too slow.\n";
|
||||||
if (EmuConfig.SPU2.SynchMode == Pcsx2Config::SPU2Options::SynchronizationMode::ASync)
|
if (EmuConfig.SPU2.SynchMode == Pcsx2Config::SPU2Options::SynchronizationMode::ASync)
|
||||||
messages += ICON_FA_VOLUME_MUTE " Audio is using async mix, expect desynchronization in FMVs.\n";
|
messages += ICON_FA_VOLUME_MUTE " Audio is using async mix, expect desynchronization in FMVs.\n";
|
||||||
if (EmuConfig.GS.UpscaleMultiplier < 1.0f)
|
if (EmuConfig.GS.UpscaleMultiplier < 1.0f)
|
||||||
|
@ -2122,28 +1961,35 @@ void VMManager::WarnAboutUnsafeSettings()
|
||||||
if (EmuConfig.GS.HWMipmap != HWMipmapLevel::Automatic)
|
if (EmuConfig.GS.HWMipmap != HWMipmapLevel::Automatic)
|
||||||
messages += ICON_FA_IMAGES " Mipmapping is not set to automatic. This may break rendering in some games.\n";
|
messages += ICON_FA_IMAGES " Mipmapping is not set to automatic. This may break rendering in some games.\n";
|
||||||
if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2)
|
if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2)
|
||||||
messages += ICON_FA_FILTER " Texture filtering is not set to Bilinear (PS2). This will break rendering in some games.\n";
|
messages += ICON_FA_FILTER
|
||||||
|
" Texture filtering is not set to Bilinear (PS2). This will break rendering in some games.\n";
|
||||||
if (EmuConfig.GS.TriFilter != TriFiltering::Automatic)
|
if (EmuConfig.GS.TriFilter != TriFiltering::Automatic)
|
||||||
messages += ICON_FA_PAGER " Trilinear filtering is not set to automatic. This may break rendering in some games.\n";
|
messages +=
|
||||||
|
ICON_FA_PAGER " Trilinear filtering is not set to automatic. This may break rendering in some games.\n";
|
||||||
if (EmuConfig.GS.AccurateBlendingUnit <= AccBlendLevel::Minimum)
|
if (EmuConfig.GS.AccurateBlendingUnit <= AccBlendLevel::Minimum)
|
||||||
messages += ICON_FA_BLENDER " Blending is below basic, this may break effects in some games.\n";
|
messages += ICON_FA_BLENDER " Blending is below basic, this may break effects in some games.\n";
|
||||||
if (EmuConfig.GS.HWDownloadMode != GSHardwareDownloadMode::Enabled)
|
if (EmuConfig.GS.HWDownloadMode != GSHardwareDownloadMode::Enabled)
|
||||||
messages += ICON_FA_DOWNLOAD " Hardware Download Mode is not set to Accurate, this may break rendering in some games.\n";
|
messages += ICON_FA_DOWNLOAD
|
||||||
|
" Hardware Download Mode is not set to Accurate, this may break rendering in some games.\n";
|
||||||
if (EmuConfig.Cpu.sseMXCSR.GetRoundMode() != SSEround_Chop)
|
if (EmuConfig.Cpu.sseMXCSR.GetRoundMode() != SSEround_Chop)
|
||||||
messages += ICON_FA_MICROCHIP " EE FPU Round Mode is not set to default, this may break some games.\n";
|
messages += ICON_FA_MICROCHIP " EE FPU Round Mode is not set to default, this may break some games.\n";
|
||||||
if (!EmuConfig.Cpu.Recompiler.fpuOverflow || EmuConfig.Cpu.Recompiler.fpuExtraOverflow || EmuConfig.Cpu.Recompiler.fpuFullMode)
|
if (!EmuConfig.Cpu.Recompiler.fpuOverflow || EmuConfig.Cpu.Recompiler.fpuExtraOverflow ||
|
||||||
|
EmuConfig.Cpu.Recompiler.fpuFullMode)
|
||||||
messages += ICON_FA_MICROCHIP " EE FPU Clamp Mode is not set to default, this may break some games.\n";
|
messages += ICON_FA_MICROCHIP " EE FPU Clamp Mode is not set to default, this may break some games.\n";
|
||||||
if (EmuConfig.Cpu.sseVU0MXCSR.GetRoundMode() != SSEround_Chop || EmuConfig.Cpu.sseVU1MXCSR.GetRoundMode() != SSEround_Chop)
|
if (EmuConfig.Cpu.sseVU0MXCSR.GetRoundMode() != SSEround_Chop ||
|
||||||
|
EmuConfig.Cpu.sseVU1MXCSR.GetRoundMode() != SSEround_Chop)
|
||||||
messages += ICON_FA_MICROCHIP " VU Round Mode is not set to default, this may break some games.\n";
|
messages += ICON_FA_MICROCHIP " VU Round Mode is not set to default, this may break some games.\n";
|
||||||
if (!EmuConfig.Cpu.Recompiler.vu0Overflow || EmuConfig.Cpu.Recompiler.vu0ExtraOverflow || EmuConfig.Cpu.Recompiler.vu0SignOverflow ||
|
if (!EmuConfig.Cpu.Recompiler.vu0Overflow || EmuConfig.Cpu.Recompiler.vu0ExtraOverflow ||
|
||||||
!EmuConfig.Cpu.Recompiler.vu1Overflow || EmuConfig.Cpu.Recompiler.vu1ExtraOverflow || EmuConfig.Cpu.Recompiler.vu1SignOverflow)
|
EmuConfig.Cpu.Recompiler.vu0SignOverflow || !EmuConfig.Cpu.Recompiler.vu1Overflow ||
|
||||||
|
EmuConfig.Cpu.Recompiler.vu1ExtraOverflow || EmuConfig.Cpu.Recompiler.vu1SignOverflow)
|
||||||
{
|
{
|
||||||
messages += ICON_FA_MICROCHIP " VU Clamp Mode is not set to default, this may break some games.\n";
|
messages += ICON_FA_MICROCHIP " VU Clamp Mode is not set to default, this may break some games.\n";
|
||||||
}
|
}
|
||||||
if (!EmuConfig.EnableGameFixes)
|
if (!EmuConfig.EnableGameFixes)
|
||||||
messages += ICON_FA_GAMEPAD " Game Fixes are not enabled. Compatibility with some games may be affected.\n";
|
messages += ICON_FA_GAMEPAD " Game Fixes are not enabled. Compatibility with some games may be affected.\n";
|
||||||
if (!EmuConfig.EnablePatches)
|
if (!EmuConfig.EnablePatches)
|
||||||
messages += ICON_FA_GAMEPAD " Compatibility Patches are not enabled. Compatibility with some games may be affected.\n";
|
messages +=
|
||||||
|
ICON_FA_GAMEPAD " Compatibility Patches are not enabled. Compatibility with some games may be affected.\n";
|
||||||
if (EmuConfig.GS.FramerateNTSC != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_NTSC)
|
if (EmuConfig.GS.FramerateNTSC != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_NTSC)
|
||||||
messages += ICON_FA_TV " Frame rate for NTSC is not default. This may break some games.\n";
|
messages += ICON_FA_TV " Frame rate for NTSC is not default. This may break some games.\n";
|
||||||
if (EmuConfig.GS.FrameratePAL != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL)
|
if (EmuConfig.GS.FrameratePAL != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL)
|
||||||
|
@ -2164,13 +2010,17 @@ void VMManager::WarnAboutUnsafeSettings()
|
||||||
|
|
||||||
messages.clear();
|
messages.clear();
|
||||||
if (!EmuConfig.Cpu.Recompiler.EnableEE)
|
if (!EmuConfig.Cpu.Recompiler.EnableEE)
|
||||||
messages += ICON_FA_EXCLAMATION_CIRCLE " EE Recompiler is not enabled, this will significantly reduce performance.\n";
|
messages +=
|
||||||
|
ICON_FA_EXCLAMATION_CIRCLE " EE Recompiler is not enabled, this will significantly reduce performance.\n";
|
||||||
if (!EmuConfig.Cpu.Recompiler.EnableVU0)
|
if (!EmuConfig.Cpu.Recompiler.EnableVU0)
|
||||||
messages += ICON_FA_EXCLAMATION_CIRCLE " VU0 Recompiler is not enabled, this will significantly reduce performance.\n";
|
messages +=
|
||||||
|
ICON_FA_EXCLAMATION_CIRCLE " VU0 Recompiler is not enabled, this will significantly reduce performance.\n";
|
||||||
if (!EmuConfig.Cpu.Recompiler.EnableVU1)
|
if (!EmuConfig.Cpu.Recompiler.EnableVU1)
|
||||||
messages += ICON_FA_EXCLAMATION_CIRCLE " VU1 Recompiler is not enabled, this will significantly reduce performance.\n";
|
messages +=
|
||||||
|
ICON_FA_EXCLAMATION_CIRCLE " VU1 Recompiler is not enabled, this will significantly reduce performance.\n";
|
||||||
if (!EmuConfig.Cpu.Recompiler.EnableIOP)
|
if (!EmuConfig.Cpu.Recompiler.EnableIOP)
|
||||||
messages += ICON_FA_EXCLAMATION_CIRCLE " IOP Recompiler is not enabled, this will significantly reduce performance.\n";
|
messages +=
|
||||||
|
ICON_FA_EXCLAMATION_CIRCLE " IOP Recompiler is not enabled, this will significantly reduce performance.\n";
|
||||||
if (EmuConfig.Cpu.Recompiler.EnableEECache)
|
if (EmuConfig.Cpu.Recompiler.EnableEECache)
|
||||||
messages += ICON_FA_EXCLAMATION_CIRCLE " EE Cache is enabled, this will significantly reduce performance.\n";
|
messages += ICON_FA_EXCLAMATION_CIRCLE " EE Cache is enabled, this will significantly reduce performance.\n";
|
||||||
if (!EmuConfig.Speedhacks.WaitLoop)
|
if (!EmuConfig.Speedhacks.WaitLoop)
|
||||||
|
@ -2223,7 +2073,8 @@ void VMManager::SaveSessionTime()
|
||||||
if (!s_game_serial.empty() && s_game_crc != 0)
|
if (!s_game_serial.empty() && s_game_crc != 0)
|
||||||
{
|
{
|
||||||
// round up to seconds
|
// round up to seconds
|
||||||
const std::time_t etime = static_cast<std::time_t>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
|
const std::time_t etime =
|
||||||
|
static_cast<std::time_t>(std::round(Common::Timer::ConvertValueToSeconds(ctime - s_session_start_time)));
|
||||||
const std::time_t wtime = std::time(nullptr);
|
const std::time_t wtime = std::time(nullptr);
|
||||||
GameList::AddPlayedTimeForSerial(s_game_serial, wtime, etime);
|
GameList::AddPlayedTimeForSerial(s_game_serial, wtime, etime);
|
||||||
}
|
}
|
||||||
|
@ -2300,7 +2151,8 @@ static void InitializeCPUInfo()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLn(Color_StrongYellow, "Processor count: %u cores, %u processors", cpuinfo_get_cores_count(), cpuinfo_get_processors_count());
|
Console.WriteLn(Color_StrongYellow, "Processor count: %u cores, %u processors", cpuinfo_get_cores_count(),
|
||||||
|
cpuinfo_get_processors_count());
|
||||||
Console.WriteLn(Color_StrongYellow, "Cluster count: %u", cluster_count);
|
Console.WriteLn(Color_StrongYellow, "Cluster count: %u", cluster_count);
|
||||||
|
|
||||||
static std::vector<const cpuinfo_processor*> ordered_processors;
|
static std::vector<const cpuinfo_processor*> ordered_processors;
|
||||||
|
@ -2319,9 +2171,10 @@ static void InitializeCPUInfo()
|
||||||
// find the large and small clusters based on frequency
|
// find the large and small clusters based on frequency
|
||||||
// this is assuming the large cluster is always clocked higher
|
// this is assuming the large cluster is always clocked higher
|
||||||
// sort based on core, so that hyperthreads get pushed down
|
// sort based on core, so that hyperthreads get pushed down
|
||||||
std::sort(ordered_processors.begin(), ordered_processors.end(), [](const cpuinfo_processor* lhs, const cpuinfo_processor* rhs) {
|
std::sort(ordered_processors.begin(), ordered_processors.end(),
|
||||||
return (lhs->core->frequency > rhs->core->frequency || lhs->smt_id < rhs->smt_id);
|
[](const cpuinfo_processor* lhs, const cpuinfo_processor* rhs) {
|
||||||
});
|
return (lhs->core->frequency > rhs->core->frequency || lhs->smt_id < rhs->smt_id);
|
||||||
|
});
|
||||||
|
|
||||||
s_processor_list.reserve(ordered_processors.size());
|
s_processor_list.reserve(ordered_processors.size());
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -2357,14 +2210,15 @@ static void SetMTVUAndAffinityControlDefault(SettingsInterface& si)
|
||||||
for (u32 i = 0; i < cluster_count; i++)
|
for (u32 i = 0; i < cluster_count; i++)
|
||||||
{
|
{
|
||||||
const cpuinfo_cluster* cluster = cpuinfo_get_cluster(i);
|
const cpuinfo_cluster* cluster = cpuinfo_get_cluster(i);
|
||||||
Console.WriteLn(" Cluster %u: %u cores and %u processors at %u MHz",
|
Console.WriteLn(" Cluster %u: %u cores and %u processors at %u MHz", i, cluster->core_count,
|
||||||
i, cluster->core_count, cluster->processor_count, static_cast<u32>(cluster->frequency /* / 1000000u*/));
|
cluster->processor_count, static_cast<u32>(cluster->frequency /* / 1000000u*/));
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_big_little = cluster_count > 1;
|
const bool has_big_little = cluster_count > 1;
|
||||||
Console.WriteLn("Big-Little: %s", has_big_little ? "yes" : "no");
|
Console.WriteLn("Big-Little: %s", has_big_little ? "yes" : "no");
|
||||||
|
|
||||||
const u32 big_cores = cpuinfo_get_cluster(0)->core_count + ((cluster_count > 2) ? cpuinfo_get_cluster(1)->core_count : 0u);
|
const u32 big_cores =
|
||||||
|
cpuinfo_get_cluster(0)->core_count + ((cluster_count > 2) ? cpuinfo_get_cluster(1)->core_count : 0u);
|
||||||
Console.WriteLn("Guessing we have %u big/medium cores...", big_cores);
|
Console.WriteLn("Guessing we have %u big/medium cores...", big_cores);
|
||||||
|
|
||||||
if (big_cores >= 3)
|
if (big_cores >= 3)
|
||||||
|
@ -2448,8 +2302,7 @@ void VMManager::SetEmuThreadAffinities()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EmuConfig.Cpu.AffinityControlMode == 0 ||
|
if (EmuConfig.Cpu.AffinityControlMode == 0 || s_processor_list.size() < (EmuConfig.Speedhacks.vuThread ? 3 : 2))
|
||||||
s_processor_list.size() < (EmuConfig.Speedhacks.vuThread ? 3 : 2))
|
|
||||||
{
|
{
|
||||||
if (EmuConfig.Cpu.AffinityControlMode != 0)
|
if (EmuConfig.Cpu.AffinityControlMode != 0)
|
||||||
Console.Error("Insufficient processors for affinity control.");
|
Console.Error("Insufficient processors for affinity control.");
|
||||||
|
@ -2472,12 +2325,13 @@ void VMManager::SetEmuThreadAffinities()
|
||||||
};
|
};
|
||||||
|
|
||||||
// steal vu's thread if mtvu is off
|
// steal vu's thread if mtvu is off
|
||||||
const u8* this_proc_assigment = processor_assignment[EmuConfig.Cpu.AffinityControlMode][EmuConfig.Speedhacks.vuThread];
|
const u8* this_proc_assigment =
|
||||||
|
processor_assignment[EmuConfig.Cpu.AffinityControlMode][EmuConfig.Speedhacks.vuThread];
|
||||||
const u32 ee_index = s_processor_list[this_proc_assigment[0]];
|
const u32 ee_index = s_processor_list[this_proc_assigment[0]];
|
||||||
const u32 vu_index = s_processor_list[this_proc_assigment[1]];
|
const u32 vu_index = s_processor_list[this_proc_assigment[1]];
|
||||||
const u32 gs_index = s_processor_list[this_proc_assigment[2]];
|
const u32 gs_index = s_processor_list[this_proc_assigment[2]];
|
||||||
Console.WriteLn("Processor order assignment: EE=%u, VU=%u, GS=%u",
|
Console.WriteLn("Processor order assignment: EE=%u, VU=%u, GS=%u", this_proc_assigment[0], this_proc_assigment[1],
|
||||||
this_proc_assigment[0], this_proc_assigment[1], this_proc_assigment[2]);
|
this_proc_assigment[2]);
|
||||||
|
|
||||||
const u64 ee_affinity = static_cast<u64>(1) << ee_index;
|
const u64 ee_affinity = static_cast<u64>(1) << ee_index;
|
||||||
Console.WriteLn(Color_StrongGreen, "EE thread is on processor %u (0x%llx)", ee_index, ee_affinity);
|
Console.WriteLn(Color_StrongGreen, "EE thread is on processor %u (0x%llx)", ee_index, ee_affinity);
|
||||||
|
|
|
@ -107,9 +107,6 @@ namespace VMManager
|
||||||
/// Reloads game specific settings, and applys any changes present.
|
/// Reloads game specific settings, and applys any changes present.
|
||||||
bool ReloadGameSettings();
|
bool ReloadGameSettings();
|
||||||
|
|
||||||
/// Reloads cheats/patches. If verbose is set, the number of patches loaded will be shown in the OSD.
|
|
||||||
void ReloadPatches(bool verbose, bool show_messages_when_disabled);
|
|
||||||
|
|
||||||
/// Returns the save state filename for the given game serial/crc.
|
/// Returns the save state filename for the given game serial/crc.
|
||||||
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
|
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,6 @@
|
||||||
<ClCompile Include="Mdec.cpp" />
|
<ClCompile Include="Mdec.cpp" />
|
||||||
<ClCompile Include="MultipartFileReader.cpp" />
|
<ClCompile Include="MultipartFileReader.cpp" />
|
||||||
<ClCompile Include="Patch.cpp" />
|
<ClCompile Include="Patch.cpp" />
|
||||||
<ClCompile Include="Patch_Memory.cpp" />
|
|
||||||
<ClCompile Include="PrecompiledHeader.cpp">
|
<ClCompile Include="PrecompiledHeader.cpp">
|
||||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -692,9 +692,6 @@
|
||||||
<ClCompile Include="GameDatabase.cpp">
|
<ClCompile Include="GameDatabase.cpp">
|
||||||
<Filter>Misc</Filter>
|
<Filter>Misc</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="Patch_Memory.cpp">
|
|
||||||
<Filter>Misc</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="IPU\IPUdma.cpp">
|
<ClCompile Include="IPU\IPUdma.cpp">
|
||||||
<Filter>System\Ps2\IPU</Filter>
|
<Filter>System\Ps2\IPU</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -1694,7 +1694,7 @@ void recompileNextInstruction(bool delayslot, bool swapped_delay_slot)
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (EmuConfig.EnablePatches)
|
if (EmuConfig.EnablePatches)
|
||||||
ApplyDynamicPatches(pc);
|
Patch::ApplyDynamicPatches(pc);
|
||||||
|
|
||||||
// add breakpoint
|
// add breakpoint
|
||||||
if (!delayslot)
|
if (!delayslot)
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# PCSX2 - PS2 Emulator for PCs
|
||||||
|
# Copyright (C) 2023 PCSX2 Dev Team
|
||||||
|
#
|
||||||
|
# PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||||
|
# of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
# ation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE. See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with PCSX2.
|
||||||
|
# If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# pylint: disable=bare-except, disable=missing-function-docstring
|
||||||
|
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def merge_patches(srcdir, dstdir, label, desc, extralines=None):
|
||||||
|
for file in glob.glob(os.path.join(srcdir, "*.pnach")):
|
||||||
|
print(f"Reading {file}...")
|
||||||
|
|
||||||
|
name = os.path.basename(file)
|
||||||
|
with open(file, "rb") as f:
|
||||||
|
lines = f.read().decode().strip().split("\n")
|
||||||
|
|
||||||
|
gametitle_line = None
|
||||||
|
comment_line = None
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("gametitle=") and gametitle_line is None:
|
||||||
|
gametitle_line = line
|
||||||
|
elif line.startswith("comment=") and comment_line is None:
|
||||||
|
comment_line = line[8:]
|
||||||
|
|
||||||
|
# ignore gametitle if file already exists
|
||||||
|
outname = os.path.join(dstdir, name)
|
||||||
|
if os.path.exists(outname):
|
||||||
|
gametitle_line = None
|
||||||
|
|
||||||
|
with open(outname, "ab") as f:
|
||||||
|
if gametitle_line is not None:
|
||||||
|
f.write((gametitle_line + "\n\n").encode())
|
||||||
|
|
||||||
|
f.write(f"[{label}]\n".encode())
|
||||||
|
if desc is not None and comment_line is None:
|
||||||
|
f.write(f"description={desc}\n".encode())
|
||||||
|
if extralines is not None:
|
||||||
|
f.write(f"{extralines}\n".encode())
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if not line.startswith("gametitle="):
|
||||||
|
f.write((line + "\n").encode())
|
||||||
|
f.write("\n\n".encode())
|
||||||
|
|
||||||
|
print(f"Wrote/updated {outname}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) < 4:
|
||||||
|
print(f"Usage: {sys.argv[0]} <ws directory> <ni directory> <output directory>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
outdir = sys.argv[3]
|
||||||
|
if not os.path.isdir(outdir):
|
||||||
|
os.mkdir(outdir)
|
||||||
|
|
||||||
|
merge_patches(sys.argv[1], outdir, "Widescreen 16:9", "Renders the game in 16:9 aspect ratio, instead of 4:3.", "gsaspectratio=16:9")
|
||||||
|
merge_patches(sys.argv[2], outdir, "No-Interlacing", "Attempts to disable interlaced offset rendering.", "gsinterlacemode=1")
|
Loading…
Reference in New Issue