From 7cce3a84363bc344c363f1d21aedb4d35c11ce62 Mon Sep 17 00:00:00 2001 From: Robbie Date: Tue, 4 Jul 2017 06:38:40 -0500 Subject: [PATCH 01/12] Add the save icons to the save data entry and manager. --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 16 ++++++++++++++-- rpcs3/Emu/Cell/Modules/cellSaveData.h | 4 ++-- rpcs3/rpcs3qt/save_data_utility.cpp | 16 +++++++++++++++- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 5e75f755ee69..28af7e2fbed4 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -141,8 +141,20 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, save_entry2.atime = entry.atime; save_entry2.mtime = entry.mtime; save_entry2.ctime = entry.ctime; - //save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer - //save_entry2.iconBufSize = 0; // TODO: Size of the PNG file + if (fs::is_file(base_dir + entry.name + "/ICON0.PNG")) + { + fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG"); + u32 iconSize = icon.size(); + void* iconData = new uchar[iconSize]; + icon.read(iconData, iconSize); + save_entry2.iconBuf = iconData; + save_entry2.iconBufSize = iconSize; + } + else + { + save_entry2.iconBuf = nullptr; + save_entry2.iconBufSize = 0; + } save_entry2.isNew = false; save_entries.push_back(save_entry2); diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index 289c1e9dc576..bb8be59cc19b 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -282,8 +282,8 @@ struct SaveDataEntry s64 atime; s64 mtime; s64 ctime; - //void* iconBuf; - //u32 iconBufSize; + void* iconBuf; + u32 iconBufSize; bool isNew; }; diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index d26ce09775ce..bf790d87a192 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -45,7 +45,21 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* void save_data_info_dialog::UpdateData() { m_list->clearContents(); - m_list->setRowCount(4); // set this to nr of members in struct + int num_entries = 5; // set this to number of members in struct + m_list->setRowCount(num_entries); + + QImage img; + if ((m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf, m_entry.iconBufSize, "PNG")) == false) + { + m_list->setRowCount(num_entries-1); // Image failed so don't show it. + } + else + { + QTableWidgetItem* img_item = new QTableWidgetItem(); + img_item->setData(Qt::DecorationRole, QPixmap::fromImage(img)); + m_list->setItem(4, 0, new QTableWidgetItem(tr("Icon"))); + m_list->setItem(4, 1, img_item); + } //Maybe there should be more details of save data. m_list->setItem(0, 0, new QTableWidgetItem(tr("User ID"))); From 27f388999c16f7bb066274457daac6edf2951dc1 Mon Sep 17 00:00:00 2001 From: Robbie Date: Tue, 4 Jul 2017 06:44:53 -0500 Subject: [PATCH 02/12] Simplify code slightly since I have an else now so no need for == false --- rpcs3/rpcs3qt/save_data_utility.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 185581876107..00f445de235d 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -49,17 +49,17 @@ void save_data_info_dialog::UpdateData() m_list->setRowCount(num_entries); QImage img; - if ((m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf, m_entry.iconBufSize, "PNG")) == false) - { - m_list->setRowCount(num_entries-1); // Image failed so don't show it. - } - else + if (m_entry.iconBuf && img.loadFromData((uchar*) m_entry.iconBuf, m_entry.iconBufSize, "PNG")) { QTableWidgetItem* img_item = new QTableWidgetItem(); img_item->setData(Qt::DecorationRole, QPixmap::fromImage(img)); m_list->setItem(4, 0, new QTableWidgetItem(tr("Icon"))); m_list->setItem(4, 1, img_item); } + else + { + m_list->setRowCount(num_entries - 1); // Image failed so don't show it. + } //Maybe there should be more details of save data. m_list->setItem(0, 0, new QTableWidgetItem(tr("User ID"))); From 1447d06cc637087847881d3b1881e7eaff3335b7 Mon Sep 17 00:00:00 2001 From: Robbie Date: Tue, 4 Jul 2017 19:58:12 -0500 Subject: [PATCH 03/12] Move the icon to the top of the list because it looks better. Remove redundant settitle. --- rpcs3/rpcs3qt/save_data_utility.cpp | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 00f445de235d..f633d4bb5d1f 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -35,8 +35,8 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* vbox_main->setAlignment(Qt::AlignCenter); setLayout(vbox_main); - // resize to minimum view size - resize(minimumSize().expandedTo(sizeHint())); + // resize to a slightly larger than minimum size because the save icon is large. + resize(QSize(600, 400).expandedTo(sizeHint())); UpdateData(); } @@ -45,22 +45,9 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* void save_data_info_dialog::UpdateData() { m_list->clearContents(); - int num_entries = 5; // set this to number of members in struct + int num_entries = 4; // set this to number of members in struct m_list->setRowCount(num_entries); - QImage img; - if (m_entry.iconBuf && img.loadFromData((uchar*) m_entry.iconBuf, m_entry.iconBufSize, "PNG")) - { - QTableWidgetItem* img_item = new QTableWidgetItem(); - img_item->setData(Qt::DecorationRole, QPixmap::fromImage(img)); - m_list->setItem(4, 0, new QTableWidgetItem(tr("Icon"))); - m_list->setItem(4, 1, img_item); - } - else - { - m_list->setRowCount(num_entries - 1); // Image failed so don't show it. - } - //Maybe there should be more details of save data. m_list->setItem(0, 0, new QTableWidgetItem(tr("User ID"))); m_list->setItem(0, 1, new QTableWidgetItem("00000001 (Default)")); @@ -74,6 +61,16 @@ void save_data_info_dialog::UpdateData() m_list->setItem(3, 0, new QTableWidgetItem(tr("Detail"))); m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details))); + QImage img; + if (m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf, m_entry.iconBufSize, "PNG")) + { + m_list->insertRow(0); + QTableWidgetItem* img_item = new QTableWidgetItem(); + img_item->setData(Qt::DecorationRole, QPixmap::fromImage(img)); + m_list->setItem(0, 0, new QTableWidgetItem(tr("Icon"))); + m_list->setItem(0, 1, img_item); + } + m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); } @@ -83,7 +80,7 @@ void save_data_info_dialog::UpdateData() save_data_list_dialog::save_data_list_dialog(const std::vector& entries, s32 focusedEntry, bool is_saving, QWidget* parent) : QDialog(parent), m_save_entries(entries), m_selectedEntry(-1), selectedEntryLabel(nullptr) { - setWindowTitle(tr("Save Data Utility")); + setWindowTitle(tr("Save Data Chooser")); setMinimumSize(QSize(400, 400)); // Table @@ -106,7 +103,6 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept); hbox_action->addWidget(push_select); - setWindowTitle(tr("Save Data Chooser")); selectedEntryLabel = new QLabel(this); UpdateSelectionLabel(); From 1b3b9c25f3afb636d588c78a1e7ab1bce5a2bd5a Mon Sep 17 00:00:00 2001 From: Robbie Date: Wed, 5 Jul 2017 18:33:35 -0500 Subject: [PATCH 04/12] Fix size. It's a bit forced but there wasn't any better way as far as I could see on stack overflow. Also, add an error dialog if you have no entries. Simplify the logic slightly for the selected since with the no data case handled, I can make more assumptions about the return value. --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 44 +++++++++++++++------- rpcs3/rpcs3qt/save_data_utility.cpp | 49 +++++++++++++++---------- 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index b8146507856e..1dbb95db3156 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -3,6 +3,7 @@ #include "Emu/Cell/PPUModule.h" #include "cellSaveData.h" +#include "cellMsgDialog.h" #include "Loader/PSF.h" #include "Utilities/StrUtil.h" @@ -305,10 +306,36 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } - // Display Save Data List but do so asynchronously in the GUI thread. For, qTimers only work using main UI thread. + // Display Save Data List but do so asynchronously in the GUI thread atomic_t dlg_result(false); bool hasNewData = (bool) listSet->newData; // Are we saving? + if (save_entries.size() == 0 && !hasNewData) + { // Don't show an empty dialog that isn't saving something new. But, do show an error dialog. + std::shared_ptr dlg = Emu.GetCallbacks().get_msg_dialog(); + dlg->type.bg_invisible = true; + dlg->type.button_type = 2; // OK + dlg->type.disable_cancel = true; + dlg->on_close = [&](s32 status) + { + dlg_result = true; + }; + Emu.CallAfter([&]() { + std::string res = ""; + for (std::string prefix : prefix_list) + { + res += (" " + prefix); + } + // The prefix(s) should be shown because some games like Disgaea 4 try to load games twice-- once for Disgaea 4 saves, and once for Disgaea 3 saves to import. + dlg->Create("Could not find save data for game prefix(s):" + res + "."); + }); + // I *really* want to do this without waiting for results... But if I do, the destructor of dlg will be called when this scope exits meaning the dialog will get destroyed. + while (!dlg_result) + { + thread_ctrl::wait_for(1000); + } + return CELL_SAVEDATA_ERROR_NODATA; + } Emu.CallAfter([&]() { @@ -322,20 +349,11 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } if (selected == -1) - { - if (hasNewData) - { - save_entry.dirName = listSet->newData->dirName.get_ptr(); - } - else - { - // This happens if someone tries to load but there is no data selected. Some games will throw errors (Akiba) if cell_ok is returned - return CELL_CANCEL; - } + { // New save is requested. + save_entry.dirName = listSet->newData->dirName.get_ptr(); } - // Cancel selected in UI else if (selected == -2) - { + { // Cancel selected in UI. return CELL_CANCEL; } diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index f633d4bb5d1f..ec6edd9c2734 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -13,6 +13,9 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* // Table m_list = new QTableWidget(this); + m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of item selection rectangles include "table_item_delegate.h" m_list->setSelectionBehavior(QAbstractItemView::SelectRows); // enable to only select whole rows instead of items m_list->setEditTriggers(QAbstractItemView::NoEditTriggers); @@ -35,10 +38,11 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* vbox_main->setAlignment(Qt::AlignCenter); setLayout(vbox_main); - // resize to a slightly larger than minimum size because the save icon is large. - resize(QSize(600, 400).expandedTo(sizeHint())); - UpdateData(); + + // If there's a better way, let me know : https://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget + resize(75 + m_list->horizontalHeader()->length() + m_list->verticalHeader()->width(), + 75 + m_list->verticalHeader()->length() + m_list->horizontalHeader()->height()); } //This is intended to write the information of save data to QTableView. @@ -70,9 +74,6 @@ void save_data_info_dialog::UpdateData() m_list->setItem(0, 0, new QTableWidgetItem(tr("Icon"))); m_list->setItem(0, 1, img_item); } - - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); } //Show up the savedata list, either to choose one to save/load or to manage saves. @@ -80,11 +81,14 @@ void save_data_info_dialog::UpdateData() save_data_list_dialog::save_data_list_dialog(const std::vector& entries, s32 focusedEntry, bool is_saving, QWidget* parent) : QDialog(parent), m_save_entries(entries), m_selectedEntry(-1), selectedEntryLabel(nullptr) { - setWindowTitle(tr("Save Data Chooser")); + setWindowTitle(tr("Save Data Interface")); setMinimumSize(QSize(400, 400)); // Table m_list = new QTableWidget(this); + m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of cell selection rectangles include "table_item_delegate.h" m_list->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); m_list->setSelectionBehavior(QAbstractItemView::SelectRows); @@ -95,17 +99,18 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e // Button Layout QHBoxLayout* hbox_action = new QHBoxLayout(); - QPushButton *push_cancel = new QPushButton(tr("&Cancel"), this); - push_cancel->setAutoDefault(false); - QPushButton *push_select = new QPushButton(tr("&Select Entry"), this); - push_select->setAutoDefault(true); - push_select->setDefault(true); - connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept); - hbox_action->addWidget(push_select); + if (entries.size() > 0) + { // If there are no entries, don't add the selection widget or the selection label to the UI. + QPushButton *push_select = new QPushButton(tr("&Select Entry"), this); + connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept); + push_select->setAutoDefault(true); + push_select->setDefault(true); + hbox_action->addWidget(push_select); - selectedEntryLabel = new QLabel(this); - UpdateSelectionLabel(); + selectedEntryLabel = new QLabel(this); + UpdateSelectionLabel(); + } if (is_saving) { @@ -118,6 +123,9 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e } hbox_action->addStretch(); + + QPushButton *push_cancel = new QPushButton(tr("&Cancel"), this); + push_cancel->setAutoDefault(false); hbox_action->addWidget(push_cancel); // events @@ -130,7 +138,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e // TODO: Unstub functions inside of this context menu so it makes sense to show this menu //connect(m_list, &QTableWidget::customContextMenuRequested, this, &save_data_list_dialog::ShowContextMenu); - connect(m_list->horizontalHeader(), &QHeaderView::sectionClicked, [=](int col){ + connect(m_list->horizontalHeader(), &QHeaderView::sectionClicked, [=](int col) { OnSort(col); }); @@ -149,8 +157,13 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e UpdateList(); m_list->setCurrentCell(focusedEntry, 0); + + // If there's a better way, let me know : https://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget + resize(50 + m_list->horizontalHeader()->length() + m_list->verticalHeader()->width(), + 50 + m_list->verticalHeader()->length() + m_list->horizontalHeader()->height()); } + void save_data_list_dialog::UpdateSelectionLabel() { if (selectedEntryLabel != nullptr) @@ -289,8 +302,6 @@ void save_data_list_dialog::UpdateList(void) { m_list->clearContents(); m_list->setRowCount(m_save_entries.size()); - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); int row = 0; for (SaveDataEntry entry: m_save_entries) From fccaebcb22249ac13d3b0f6ccc12f3033ba77b24 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 6 Jul 2017 16:11:10 +0200 Subject: [PATCH 05/12] save_data_utility: fix dialog sizes --- rpcs3/rpcs3qt/save_data_utility.cpp | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index ec6edd9c2734..4c9f9ccf7c37 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -9,12 +9,9 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* : QDialog(parent), m_entry(save) { setWindowTitle(tr("Save Data Information")); - setMinimumSize(QSize(400, 300)); // Table m_list = new QTableWidget(this); - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of item selection rectangles include "table_item_delegate.h" m_list->setSelectionBehavior(QAbstractItemView::SelectRows); // enable to only select whole rows instead of items @@ -40,9 +37,16 @@ save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* UpdateData(); - // If there's a better way, let me know : https://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget - resize(75 + m_list->horizontalHeader()->length() + m_list->verticalHeader()->width(), - 75 + m_list->verticalHeader()->length() + m_list->horizontalHeader()->height()); + m_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); + m_list->verticalHeader()->resizeSections(QHeaderView::ResizeToContents); + + QSize tableSize = QSize( + m_list->verticalHeader()->width() + m_list->horizontalHeader()->length() + m_list->frameWidth() * 2, + m_list->horizontalHeader()->height() + m_list->verticalHeader()->length() + m_list->frameWidth() * 2); + + // no minimum size needed because we always have same table size and row count + resize(sizeHint() - m_list->sizeHint() + tableSize); + } //This is intended to write the information of save data to QTableView. @@ -86,8 +90,6 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e // Table m_list = new QTableWidget(this); - m_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_list->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); //m_list->setItemDelegate(new table_item_delegate(this)); // to get rid of cell selection rectangles include "table_item_delegate.h" m_list->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); @@ -157,10 +159,6 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e UpdateList(); m_list->setCurrentCell(focusedEntry, 0); - - // If there's a better way, let me know : https://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget - resize(50 + m_list->horizontalHeader()->length() + m_list->verticalHeader()->width(), - 50 + m_list->verticalHeader()->length() + m_list->horizontalHeader()->height()); } @@ -314,4 +312,14 @@ void save_data_list_dialog::UpdateList(void) ++row; } + + m_list->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); + m_list->verticalHeader()->resizeSections(QHeaderView::ResizeToContents); + + QSize tableSize = QSize( + m_list->verticalHeader()->width() + m_list->horizontalHeader()->length() + m_list->frameWidth() * 2, + m_list->horizontalHeader()->height() + m_list->verticalHeader()->length() + m_list->frameWidth() * 2); + + resize(minimumSize().expandedTo(sizeHint() - m_list->sizeHint() + tableSize)); + } From ea8f39691b0269cdc4e25ef0b7728d62f88bf7e7 Mon Sep 17 00:00:00 2001 From: Robbie Date: Thu, 6 Jul 2017 16:50:27 -0500 Subject: [PATCH 06/12] CELL_OK --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 1dbb95db3156..37afcd173102 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -334,7 +334,9 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { thread_ctrl::wait_for(1000); } - return CELL_SAVEDATA_ERROR_NODATA; + // This feels like it should be an error code, but BLES-01092 (Prince of Persia Trilogy) will launch a blocking error dialog on error. + // Nier and a couple other games also behave strangely. + return CELL_OK; } Emu.CallAfter([&]() From 9917713da258ee6c124485dd102974665e8bdc96 Mon Sep 17 00:00:00 2001 From: Robbie Date: Thu, 6 Jul 2017 19:44:32 -0500 Subject: [PATCH 07/12] Retcon dialog to instead be error in log. --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 29 ++++++------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 37afcd173102..8a7efcec43f4 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -3,7 +3,6 @@ #include "Emu/Cell/PPUModule.h" #include "cellSaveData.h" -#include "cellMsgDialog.h" #include "Loader/PSF.h" #include "Utilities/StrUtil.h" @@ -311,29 +310,15 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, bool hasNewData = (bool) listSet->newData; // Are we saving? if (save_entries.size() == 0 && !hasNewData) - { // Don't show an empty dialog that isn't saving something new. But, do show an error dialog. - std::shared_ptr dlg = Emu.GetCallbacks().get_msg_dialog(); - dlg->type.bg_invisible = true; - dlg->type.button_type = 2; // OK - dlg->type.disable_cancel = true; - dlg->on_close = [&](s32 status) - { - dlg_result = true; - }; - Emu.CallAfter([&]() { - std::string res = ""; - for (std::string prefix : prefix_list) - { - res += (" " + prefix); - } - // The prefix(s) should be shown because some games like Disgaea 4 try to load games twice-- once for Disgaea 4 saves, and once for Disgaea 3 saves to import. - dlg->Create("Could not find save data for game prefix(s):" + res + "."); - }); - // I *really* want to do this without waiting for results... But if I do, the destructor of dlg will be called when this scope exits meaning the dialog will get destroyed. - while (!dlg_result) + { + std::string res = ""; + for (std::string prefix : prefix_list) { - thread_ctrl::wait_for(1000); + res += (" " + prefix); } + // The prefix(s) should be shown because some games like Disgaea 4 try to load games twice-- once for Disgaea 4 saves, and once for Disgaea 3 saves to import. + cellSaveData.error("Could not find save data for game prefix(s): %s", res); + // This feels like it should be an error code, but BLES-01092 (Prince of Persia Trilogy) will launch a blocking error dialog on error. // Nier and a couple other games also behave strangely. return CELL_OK; From 39f1a63fe22e45e610baf28e40b1f924370fa4c9 Mon Sep 17 00:00:00 2001 From: Robbie Date: Fri, 7 Jul 2017 14:16:10 -0500 Subject: [PATCH 08/12] Dangle92 and I had some fun. Everything should be good now. --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 39 ++++++++++--------------- rpcs3/rpcs3qt/save_data_utility.cpp | 7 ++++- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 8a7efcec43f4..cb0ef088e67f 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -222,6 +222,13 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, return CELL_SAVEDATA_ERROR_CBRESULT; } + // if the callback has returned ok, lets return OK. + // typically used at game launch when no list is actually required. + if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) + { + return CELL_OK; + } + // Clean save data list save_entries.erase(std::remove_if(save_entries.begin(), save_entries.end(), [&listSet](const SaveDataEntry& entry) -> bool { @@ -305,24 +312,9 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, } } - // Display Save Data List but do so asynchronously in the GUI thread + // Display Save Data List but do so asynchronously in the GUI thread. + bool hasNewData = (bool)listSet->newData; // newData atomic_t dlg_result(false); - bool hasNewData = (bool) listSet->newData; // Are we saving? - - if (save_entries.size() == 0 && !hasNewData) - { - std::string res = ""; - for (std::string prefix : prefix_list) - { - res += (" " + prefix); - } - // The prefix(s) should be shown because some games like Disgaea 4 try to load games twice-- once for Disgaea 4 saves, and once for Disgaea 3 saves to import. - cellSaveData.error("Could not find save data for game prefix(s): %s", res); - - // This feels like it should be an error code, but BLES-01092 (Prince of Persia Trilogy) will launch a blocking error dialog on error. - // Nier and a couple other games also behave strangely. - return CELL_OK; - } Emu.CallAfter([&]() { @@ -335,19 +327,18 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, thread_ctrl::wait_for(1000); } + // UI returns -1 for new save games if (selected == -1) - { // New save is requested. + { save_entry.dirName = listSet->newData->dirName.get_ptr(); } - else if (selected == -2) - { // Cancel selected in UI. - return CELL_CANCEL; - } - if ((result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) || (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM)) + // Cancel selected in UI + if (selected == -2) { - return CELL_OK; + return CELL_CANCEL; } + } if (funcFixed) diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 4c9f9ccf7c37..9ac7585450a9 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "save_data_utility.h" inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); } @@ -112,6 +112,11 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e selectedEntryLabel = new QLabel(this); UpdateSelectionLabel(); + + if (entries.size() == 0) + { + push_select->setDisabled(true); + } } if (is_saving) From ecf0cea5bf196c7c7f13811e68e8f42156b6c850 Mon Sep 17 00:00:00 2001 From: Robbie Date: Fri, 7 Jul 2017 17:00:48 -0500 Subject: [PATCH 09/12] In dangle's code he disabled the icon, in mine I hide it if there is nothing. Having both isn't needed. Yay merges resulting in doing stupid things. --- rpcs3/rpcs3qt/save_data_utility.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 9ac7585450a9..96dfa7b68433 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -112,11 +112,6 @@ save_data_list_dialog::save_data_list_dialog(const std::vector& e selectedEntryLabel = new QLabel(this); UpdateSelectionLabel(); - - if (entries.size() == 0) - { - push_select->setDisabled(true); - } } if (is_saving) From 28de0f6ab7d72305e9a2a0d833fc397465cef65d Mon Sep 17 00:00:00 2001 From: Robbie Date: Sun, 9 Jul 2017 16:28:45 -0500 Subject: [PATCH 10/12] Fix leek --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 9 ++------- rpcs3/Emu/Cell/Modules/cellSaveData.h | 2 +- rpcs3/rpcs3qt/save_data_utility.cpp | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index cb0ef088e67f..7ebb377fbe1c 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -145,16 +145,11 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG"); u32 iconSize = icon.size(); - void* iconData = new uchar[iconSize]; + uchar* iconData = new uchar[iconSize]; icon.read(iconData, iconSize); - save_entry2.iconBuf = iconData; + save_entry2.iconBuf.reset(iconData); save_entry2.iconBufSize = iconSize; } - else - { - save_entry2.iconBuf = nullptr; - save_entry2.iconBufSize = 0; - } save_entry2.isNew = false; save_entries.push_back(save_entry2); diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index bb8be59cc19b..17ccb6e78f36 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -282,7 +282,7 @@ struct SaveDataEntry s64 atime; s64 mtime; s64 ctime; - void* iconBuf; + std::shared_ptr iconBuf; u32 iconBufSize; bool isNew; }; diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 96dfa7b68433..72229b893046 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -70,7 +70,7 @@ void save_data_info_dialog::UpdateData() m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details))); QImage img; - if (m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf, m_entry.iconBufSize, "PNG")) + if (m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf.get(), m_entry.iconBufSize, "PNG")) { m_list->insertRow(0); QTableWidgetItem* img_item = new QTableWidgetItem(); From 96bdfc275db80380db30b6f3cadab43983627563 Mon Sep 17 00:00:00 2001 From: Robbie Date: Sun, 9 Jul 2017 16:38:10 -0500 Subject: [PATCH 11/12] Default size to zero for sanity. Shared pointer is fine handling null (tested with disgaea and renaming icon file) --- rpcs3/Emu/Cell/Modules/cellSaveData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index 17ccb6e78f36..e9549422786c 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -283,7 +283,7 @@ struct SaveDataEntry s64 mtime; s64 ctime; std::shared_ptr iconBuf; - u32 iconBufSize; + u32 iconBufSize = 0; bool isNew; }; From ee67a82532eef44099d8665ec67443437f3a845c Mon Sep 17 00:00:00 2001 From: Robbie Date: Mon, 10 Jul 2017 15:33:21 -0500 Subject: [PATCH 12/12] Simplifying. Thanks for review and advice all --- rpcs3/Emu/Cell/Modules/cellSaveData.cpp | 8 +++----- rpcs3/Emu/Cell/Modules/cellSaveData.h | 3 +-- rpcs3/rpcs3qt/save_data_utility.cpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 7ebb377fbe1c..4d2f57948a0e 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -145,14 +145,12 @@ static NEVER_INLINE s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, { fs::file icon = fs::file(base_dir + entry.name + "/ICON0.PNG"); u32 iconSize = icon.size(); - uchar* iconData = new uchar[iconSize]; + std::vector iconData; icon.read(iconData, iconSize); - save_entry2.iconBuf.reset(iconData); - save_entry2.iconBufSize = iconSize; + save_entry2.iconBuf = iconData; } save_entry2.isNew = false; - - save_entries.push_back(save_entry2); + save_entries.emplace_back(save_entry2); } break; diff --git a/rpcs3/Emu/Cell/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h index e9549422786c..d10e0d68f9f0 100644 --- a/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -282,8 +282,7 @@ struct SaveDataEntry s64 atime; s64 mtime; s64 ctime; - std::shared_ptr iconBuf; - u32 iconBufSize = 0; + std::vector iconBuf; bool isNew; }; diff --git a/rpcs3/rpcs3qt/save_data_utility.cpp b/rpcs3/rpcs3qt/save_data_utility.cpp index 72229b893046..c132ff9235d7 100644 --- a/rpcs3/rpcs3qt/save_data_utility.cpp +++ b/rpcs3/rpcs3qt/save_data_utility.cpp @@ -70,7 +70,7 @@ void save_data_info_dialog::UpdateData() m_list->setItem(3, 1, new QTableWidgetItem(qstr(m_entry.details))); QImage img; - if (m_entry.iconBuf && img.loadFromData((uchar*)m_entry.iconBuf.get(), m_entry.iconBufSize, "PNG")) + if (m_entry.iconBuf.size() > 0 && img.loadFromData((uchar*) &m_entry.iconBuf[0], m_entry.iconBuf.size(), "PNG")) { m_list->insertRow(0); QTableWidgetItem* img_item = new QTableWidgetItem();