Make a basic trophy notification dialog (#3204)

* Make trophy notification dialog.

* Fix bug where trophy state doesn't persist with game reboot.
This commit is contained in:
Robbie 2017-10-24 10:43:05 -05:00 committed by kd-11
parent 779ed75a19
commit b0737d1c90
17 changed files with 217 additions and 21 deletions

View File

@ -16,6 +16,10 @@
logs::channel sceNpTrophy("sceNpTrophy");
TrophyNotificationBase::~TrophyNotificationBase()
{
}
struct trophy_context_t
{
static const u32 id_base = 1;
@ -490,6 +494,40 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt
*platinumId = SCE_NP_TROPHY_INVALID_TROPHY_ID; // TODO
}
if (g_cfg.misc.show_trophy_popups)
{
// Figure out how many zeros are needed for padding. (either 0, 1, or 2)
std::string padding = "";
if (trophyId < 10)
{
padding = "00";
}
else if (trophyId < 100)
{
padding = "0";
}
// Get icon for the notification.
std::string trophyIconPath = "/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROP" + padding + std::to_string(trophyId) + ".PNG";
fs::file trophyIconFile = fs::file(vfs::get(trophyIconPath));
u32 iconSize = trophyIconFile.size();
std::vector<uchar> trophyIconData;
trophyIconFile.read(trophyIconData, iconSize);
vm::ptr<SceNpTrophyDetails> details = vm::make_var(SceNpTrophyDetails());
vm::ptr<SceNpTrophyData> _ = vm::make_var(SceNpTrophyData());
s32 ret = sceNpTrophyGetTrophyInfo(context, handle, trophyId, details, _);
if (ret != CELL_OK)
{
sceNpTrophy.error("Failed to get info for trophy dialog. Error code %x", ret);
*details = SceNpTrophyDetails();
}
Emu.CallAfter([det = *details, trophyIconData]() {
Emu.GetCallbacks().get_trophy_notification_dialog()->ShowTrophyNotification(det, trophyIconData);
});
}
return CELL_OK;
}

View File

@ -137,3 +137,14 @@ enum
};
using SceNpTrophyStatusCallback = s32(u32 context, u32 status, s32 completed, s32 total, vm::ptr<void> arg);
// Forward declare this function since trophyunlock needs it
error_code sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr<SceNpTrophyDetails> details, vm::ptr<SceNpTrophyData> data);
class TrophyNotificationBase
{
public:
virtual ~TrophyNotificationBase();
virtual s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophyIconBfr) = 0;
};

View File

@ -165,6 +165,7 @@ struct EmuCallbacks
std::function<std::shared_ptr<class AudioThread>()> get_audio;
std::function<std::shared_ptr<class MsgDialogBase>()> get_msg_dialog;
std::function<std::unique_ptr<class SaveDialogBase>()> get_save_dialog;
std::function<std::unique_ptr<class TrophyNotificationBase>()> get_trophy_notification_dialog;
};
class Emulator final
@ -402,6 +403,7 @@ struct cfg_root : cfg::node
cfg::_bool autoexit{this, "Exit RPCS3 when process finishes"};
cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode" };
cfg::_bool show_fps_in_title{ this, "Show FPS counter in window title", true};
cfg::_bool show_trophy_popups{ this, "Show trophy popups", true};
cfg::_int<1, 65535> gdb_server_port{this, "Port", 2345};
} misc{this};

View File

@ -62,6 +62,7 @@
"startGameFullscreen": "Automatically puts the game window in fullscreen.\nDouble click on the game window or press alt+enter to toggle fullscreen and windowed mode.",
"showFPSInTitle": "Shows the framerate in the game window title. May cause buggy or outdated recording software to not notice RPCS3.",
"gs_resizeOnBoot": "Automatically resizes the game window on boot.\nThis does not change the internal game resolution.",
"showTrophyPopups": "Show trophy popups when a trophy is unlocked.",
"gs_disableMouse": "Disables the activation of fullscreen mode per doubleclick while the game screen is active.\nCheck this if you want to play with mouse and keyboard (for example with UCR)."
}
},

View File

@ -9,14 +9,12 @@ bool TROPUSRLoader::Load(const std::string& filepath, const std::string& configp
{
const std::string& path = vfs::get(filepath);
if (!m_file.open(path, fs::read))
{
if (!Generate(filepath, configpath))
{
return false;
}
if (!m_file.open(path, fs::read))
{
return false;
}
if (!LoadHeader() || !LoadTableHeaders() || !LoadTables())

View File

@ -897,6 +897,8 @@
<ClCompile Include="rpcs3qt\syntax_highlighter.cpp" />
<ClCompile Include="rpcs3qt\save_data_info_dialog.cpp" />
<ClCompile Include="rpcs3qt\save_manager_dialog.cpp" />
<ClCompile Include="rpcs3qt\trophy_notification_frame.cpp" />
<ClCompile Include="rpcs3qt\trophy_notification_helper.cpp" />
<ClCompile Include="rpcs3qt\vfs_dialog.cpp" />
<ClCompile Include="rpcs3qt\vfs_dialog_tab.cpp" />
<ClCompile Include="rpcs3qt\welcome_dialog.cpp" />
@ -1431,6 +1433,8 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DLLVM_AVAILABLE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE "-I.\..\Vulkan\Vulkan-LoaderAndValidationLayers\include" "-I.\.." "-I.\..\3rdparty\minidx12\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtQuick" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtQml" "-I$(QTDIR)\include\QtNetwork" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)\." "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(NOINHERIT)\."</Command>
</CustomBuild>
<ClInclude Include="rpcs3qt\trophy_notification_frame.h" />
<ClInclude Include="rpcs3qt\trophy_notification_helper.h" />
<ClInclude Include="xinput_pad_handler.h" />
<ClInclude Include="\rpcs3qt\*.h" />
</ItemGroup>

View File

@ -60,7 +60,10 @@
<Extensions>ui</Extensions>
<ParseFiles>true</ParseFiles>
</Filter>
<Filter Include="Gui\saves">
<Filter Include="Gui\trophy">
<UniqueIdentifier>{d49ebf7f-ea65-4006-943a-2c47f25c9aa7}</UniqueIdentifier>
</Filter>
<Filter Include="Gui\save">
<UniqueIdentifier>{31799965-1274-4c87-83a3-3bff31e8715d}</UniqueIdentifier>
</Filter>
<Filter Include="Gui\vfs">
@ -426,16 +429,19 @@
<Filter>Generated Files\Debug - LLVM</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\save_data_dialog.cpp">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\save_data_info_dialog.cpp">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\save_data_list_dialog.cpp">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\save_manager_dialog.cpp">
<Filter>Gui\saves</Filter>
<ClCompile Include="rpcs3qt\trophy_notification_helper.cpp">
<Filter>Gui\trophy</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\trophy_notification_frame.cpp">
<Filter>Gui\trophy</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_save_manager_dialog.cpp">
<Filter>Generated Files\Release - LLVM</Filter>
@ -548,6 +554,9 @@
<ClCompile Include="rpcs3qt\syntax_highlighter.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\save_manager_dialog.cpp">
<Filter>Gui\save</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="\rpcs3qt\*.h">
@ -581,7 +590,13 @@
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\save_data_dialog.h">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\trophy_notification_helper.h">
<Filter>Gui\trophy</Filter>
</ClInclude>
<ClInclude Include="rpcs3qt\trophy_notification_frame.h">
<Filter>Gui\trophy</Filter>
</ClInclude>
<ClInclude Include="pad_thread.h">
<Filter>Io</Filter>
@ -649,13 +664,10 @@
<Filter>Form Files</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\save_data_info_dialog.h">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\save_data_list_dialog.h">
<Filter>Gui\saves</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\save_manager_dialog.h">
<Filter>Gui\saves</Filter>
<Filter>Gui\save</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\syntax_highlighter.h">
<Filter>Gui\syntax highlighter</Filter>
@ -723,6 +735,9 @@
<CustomBuild Include="rpcs3qt\syntax_highlighter.h">
<Filter>Generated Files</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\save_manager_dialog.h">
<Filter>Gui\save</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="rpcs3.ico" />

View File

@ -6,6 +6,9 @@
#include "rpcs3qt/gs_frame.h"
#include "rpcs3qt/gl_gs_frame.h"
#include "Emu/Cell/Modules/sceNpTrophy.h"
#include "rpcs3qt/trophy_notification_helper.h"
#include "Emu/Cell/Modules/cellSaveData.h"
#include "rpcs3qt/save_data_dialog.h"
@ -241,6 +244,11 @@ void rpcs3_app::InitializeCallbacks()
return std::make_unique<save_data_dialog>();
};
callbacks.get_trophy_notification_dialog = [=]() -> std::unique_ptr<TrophyNotificationBase>
{
return std::make_unique<trophy_notification_helper>(gameWindow);
};
callbacks.on_run = [=]() { OnEmulatorRun(); };
callbacks.on_pause = [=]() { OnEmulatorPause(); };
callbacks.on_resume = [=]() { OnEmulatorResume(); };

View File

@ -82,6 +82,7 @@ public:
StartOnBoot,
StartGameFullscreen,
ShowFPSInTitle,
ShowTrophyPopups,
ShowWelcomeScreen,
// Network
@ -236,6 +237,7 @@ private:
{StartOnBoot, { "Miscellaneous", "Automatically start games after boot" }},
{StartGameFullscreen, { "Miscellaneous", "Start games in fullscreen mode"}},
{ShowFPSInTitle, { "Miscellaneous", "Show FPS counter in window title"}},
{ShowTrophyPopups, { "Miscellaneous", "Show trophy popups"}},
{ShowWelcomeScreen, { "Miscellaneous", "Show Welcome Screen"}},
// Networking

View File

@ -1,6 +1,3 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "save_data_dialog.h"
#include "save_data_list_dialog.h"

View File

@ -1,5 +1,7 @@
#pragma once
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/Modules/cellSaveData.h"
class save_data_dialog : public SaveDialogBase

View File

@ -715,6 +715,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> guiSettings, std:
xemu_settings->EnhanceCheckBox(ui->showFPSInTitle, emu_settings::ShowFPSInTitle);
SubscribeTooltip(ui->showFPSInTitle, json_emu_misc["showFPSInTitle"].toString());
xemu_settings->EnhanceCheckBox(ui->showTrophyPopups, emu_settings::ShowTrophyPopups);
SubscribeTooltip(ui->showTrophyPopups, json_emu_misc["showTrophyPopups"].toString());
if (game)
{
ui->gb_stylesheets->setEnabled(false);

View File

@ -1161,6 +1161,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showTrophyPopups">
<property name="text">
<string>Show trophy popups</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -0,0 +1,65 @@
#include "trophy_notification_frame.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QTimer>
static const int TROPHY_TIMEOUT_MS = 7500;
inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); }
trophy_notification_frame::trophy_notification_frame(const std::vector<uchar>& imgBuffer, const SceNpTrophyDetails& trophy, int height) : QWidget()
{
setWindowFlags(Qt::FramelessWindowHint);
// Fill the background with black
QPalette black_background;
black_background.setColor(QPalette::Window, Qt::black);
black_background.setColor(QPalette::WindowText, Qt::white);
// Make the label
QLabel* trophyImgLabel = new QLabel;
trophyImgLabel->setAutoFillBackground(true);
trophyImgLabel->setPalette(black_background);
QImage trophyImg;
if (imgBuffer.size() > 0 && trophyImg.loadFromData((uchar*)&imgBuffer[0], imgBuffer.size(), "PNG"))
{
trophyImg = trophyImg.scaledToHeight(height); // I might consider adding ability to change size since on hidpi this will be rather small.
trophyImgLabel->setPixmap(QPixmap::fromImage(trophyImg));
}
else
{
// This looks hideous, but it's a good placeholder.
trophyImgLabel->setPixmap(QPixmap::fromImage(QImage(":/rpcs3.ico")));
}
QLabel* trophyName = new QLabel;
trophyName->setWordWrap(true);
trophyName->setAlignment(Qt::AlignCenter);
QString trophyType = "";
switch (trophy.trophyGrade)
{
case SCE_NP_TROPHY_GRADE_BRONZE: trophyType = "bronze"; break;
case SCE_NP_TROPHY_GRADE_SILVER: trophyType = "silver"; break;
case SCE_NP_TROPHY_GRADE_GOLD: trophyType = "gold"; break;
case SCE_NP_TROPHY_GRADE_PLATINUM: trophyType = "platinum"; break;
default: break;
}
trophyName->setText("You have earned the " + trophyType + " trophy\n" + qstr(trophy.name));
trophyName->setAutoFillBackground(true);
trophyName->setPalette(black_background);
QHBoxLayout* globalLayout = new QHBoxLayout;
globalLayout->addWidget(trophyImgLabel);
globalLayout->addWidget(trophyName);
setLayout(globalLayout);
setPalette(black_background);
// I may consider moving this code later to be done at a better location.
QTimer::singleShot(TROPHY_TIMEOUT_MS, [this]() {
deleteLater();
});
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/Modules/sceNpTrophy.h"
#include <QWidget>
class trophy_notification_frame : public QWidget
{
public:
trophy_notification_frame(const std::vector<uchar>& imgBuffer, const SceNpTrophyDetails& trophy, int height);
};

View File

@ -0,0 +1,14 @@
#include "trophy_notification_helper.h"
#include "trophy_notification_frame.h"
s32 trophy_notification_helper::ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer)
{
trophy_notification_frame* trophy_notification = new trophy_notification_frame(trophy_icon_buffer, trophy, m_game_window->frameGeometry().height()/10);
// Move notification to upper lefthand corner
trophy_notification->move(m_game_window->mapToGlobal(QPoint(0, 0)));
trophy_notification->show();
return 0;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/Modules/sceNpTrophy.h"
#include <QWindow>
class trophy_notification_helper : public TrophyNotificationBase
{
public:
trophy_notification_helper(QWindow* game_window) : m_game_window(game_window) { };
s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer) override;
private:
QWindow* m_game_window;
};