Trophy pop-up and viewer enhancements (#2493)

* Include trophy rarity icons in pop up, remove newlines from viewer

Fix layout

Update platinum.png

Fix linux and apple

* Smaller type icons, center text vertically

* use original icons

* MacOS fixes

* Address Review comments

Update build.yml

Update build.yml

Update build.yml

Update build.yml

Update build.yml

Update build.yml

Update build.yml

test

* Move trophy type to leftmost and trophy art to rightmost

* Embed resources

* Revert packaging of resources with builds

---------

Co-authored-by: rainmakerv2 <30595646+jpau02@users.noreply.github.com>
This commit is contained in:
rainmakerv2 2025-02-23 16:00:24 +08:00 committed by GitHub
parent 4f1baece33
commit 22ca57b1f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 795 additions and 27 deletions

View file

@ -941,7 +941,7 @@ int PS4_SYSV_ABI sceNpTrophyUnlockTrophy(OrbisNpTrophyContext context, OrbisNpTr
std::filesystem::path current_icon_path =
trophy_dir / "trophy00" / "Icons" / trophy_icon_file;
AddTrophyToQueue(current_icon_path, current_trophy_name);
AddTrophyToQueue(current_icon_path, current_trophy_name, current_trophy_type);
}
}
}
@ -978,7 +978,7 @@ int PS4_SYSV_ABI sceNpTrophyUnlockTrophy(OrbisNpTrophyContext context, OrbisNpTr
trophy_dir / "trophy00" / "Icons" / platinum_icon_file;
*platinumId = platinum_trophy_id;
AddTrophyToQueue(platinum_icon_path, platinum_trophy_name);
AddTrophyToQueue(platinum_icon_path, platinum_trophy_name, "P");
}
}

View file

@ -3,6 +3,7 @@
#include <chrono>
#include <mutex>
#include <cmrc/cmrc.hpp>
#include <imgui.h>
#include "common/assert.h"
#include "common/config.h"
@ -10,6 +11,8 @@
#include "imgui/imgui_std.h"
#include "trophy_ui.h"
CMRC_DECLARE(res);
using namespace ImGui;
namespace Libraries::NpTrophy {
@ -17,14 +20,34 @@ std::optional<TrophyUI> current_trophy_ui;
std::queue<TrophyInfo> trophy_queue;
std::mutex queueMtx;
TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName)
: trophy_name(trophyName) {
TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity)
: trophy_name(trophyName), trophy_type(rarity) {
if (std::filesystem::exists(trophyIconPath)) {
trophy_icon = RefCountedTexture::DecodePngFile(trophyIconPath);
} else {
LOG_ERROR(Lib_NpTrophy, "Couldnt load trophy icon at {}",
fmt::UTF(trophyIconPath.u8string()));
}
std::string pathString;
if (trophy_type == "P") {
pathString = "Resources/platinum.png";
} else if (trophy_type == "G") {
pathString = "Resources/gold.png";
} else if (trophy_type == "S") {
pathString = "Resources/silver.png";
} else if (trophy_type == "B") {
pathString = "Resources/bronze.png";
}
auto resource = cmrc::res::get_filesystem();
auto trophytypefile = resource.open(pathString);
std::filesystem::path trophyTypePath = pathString;
if (std::filesystem::exists(trophyTypePath))
trophy_type_icon = RefCountedTexture::DecodePngFile(trophyTypePath);
AddLayer(this);
}
@ -42,29 +65,49 @@ void TrophyUI::Draw() {
float AdjustWidth = io.DisplaySize.x / 1280;
float AdjustHeight = io.DisplaySize.y / 720;
const ImVec2 window_size{
std::min(io.DisplaySize.x, (300 * AdjustWidth)),
std::min(io.DisplaySize.x, (350 * AdjustWidth)),
std::min(io.DisplaySize.y, (70 * AdjustHeight)),
};
SetNextWindowSize(window_size);
SetNextWindowCollapsed(false);
SetNextWindowPos(ImVec2(io.DisplaySize.x - (300 * AdjustWidth), (50 * AdjustHeight)));
SetNextWindowPos(ImVec2(io.DisplaySize.x - (370 * AdjustWidth), (50 * AdjustHeight)));
KeepNavHighlight();
if (Begin("Trophy Window", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoInputs)) {
if (trophy_icon) {
Image(trophy_icon.GetTexture().im_id, ImVec2((50 * AdjustWidth), (50 * AdjustHeight)));
ImGui::SameLine();
if (trophy_type_icon) {
SetCursorPosY((window_size.y * 0.5f) - (25 * AdjustHeight));
Image(trophy_type_icon.GetTexture().im_id,
ImVec2((50 * AdjustWidth), (50 * AdjustHeight)));
} else {
// placeholder
const auto pos = GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddRectFilled(pos, pos + ImVec2{50.0f},
ImGui::GetWindowDrawList()->AddRectFilled(pos, pos + ImVec2{50.0f * AdjustHeight},
GetColorU32(ImVec4{0.7f}));
ImGui::Indent(60);
}
ImGui::SameLine();
SetWindowFontScale((1.2 * AdjustHeight));
char earned_text[] = "Trophy earned!\n%s";
const float text_height =
ImGui::CalcTextSize(std::strcat(earned_text, trophy_name.c_str())).y;
SetCursorPosY((window_size.y - text_height) * 0.5f);
ImGui::PushTextWrapPos(window_size.x - (60 * AdjustWidth));
TextWrapped("Trophy earned!\n%s", trophy_name.c_str());
ImGui::SameLine(window_size.x - (60 * AdjustWidth));
if (trophy_icon) {
SetCursorPosY((window_size.y * 0.5f) - (25 * AdjustHeight));
Image(trophy_icon.GetTexture().im_id, ImVec2((50 * AdjustWidth), (50 * AdjustHeight)));
} else {
// placeholder
const auto pos = GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddRectFilled(pos, pos + ImVec2{30.0f * AdjustHeight},
GetColorU32(ImVec4{0.7f}));
}
}
End();
@ -74,14 +117,16 @@ void TrophyUI::Draw() {
if (!trophy_queue.empty()) {
TrophyInfo next_trophy = trophy_queue.front();
trophy_queue.pop();
current_trophy_ui.emplace(next_trophy.trophy_icon_path, next_trophy.trophy_name);
current_trophy_ui.emplace(next_trophy.trophy_icon_path, next_trophy.trophy_name,
next_trophy.trophy_type);
} else {
current_trophy_ui.reset();
}
}
}
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName) {
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity) {
std::lock_guard<std::mutex> lock(queueMtx);
if (Config::getisTrophyPopupDisabled()) {
@ -90,10 +135,11 @@ void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::st
TrophyInfo new_trophy;
new_trophy.trophy_icon_path = trophyIconPath;
new_trophy.trophy_name = trophyName;
new_trophy.trophy_type = rarity;
trophy_queue.push(new_trophy);
} else {
current_trophy_ui.emplace(trophyIconPath, trophyName);
current_trophy_ui.emplace(trophyIconPath, trophyName, rarity);
}
}
} // namespace Libraries::NpTrophy
} // namespace Libraries::NpTrophy

View file

@ -17,7 +17,8 @@ namespace Libraries::NpTrophy {
class TrophyUI final : public ImGui::Layer {
public:
TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName);
TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity);
~TrophyUI() override;
void Finish();
@ -26,15 +27,19 @@ public:
private:
std::string trophy_name;
std::string_view trophy_type;
float trophy_timer = 5.0f;
ImGui::RefCountedTexture trophy_icon;
ImGui::RefCountedTexture trophy_type_icon;
};
struct TrophyInfo {
std::filesystem::path trophy_icon_path;
std::string trophy_name;
std::string_view trophy_type;
};
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName);
void AddTrophyToQueue(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity);
}; // namespace Libraries::NpTrophy
}; // namespace Libraries::NpTrophy

View file

@ -2,9 +2,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QMessageBox>
#include <cmrc/cmrc.hpp>
#include "common/path_util.h"
#include "trophy_viewer.h"
CMRC_DECLARE(res);
TrophyViewer::TrophyViewer(QString trophyPath, QString gameTrpPath) : QMainWindow() {
this->setWindowTitle(tr("Trophy Viewer"));
this->setAttribute(Qt::WA_DeleteOnClose);
@ -115,13 +118,34 @@ void TrophyViewer::PopulateTrophyWidget(QString title) {
item->setData(Qt::DecorationRole, icon);
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
tableWidget->setItem(row, 1, item);
const std::string filename = GetTrpType(trpType[row].at(0));
QTableWidgetItem* typeitem = new QTableWidgetItem();
auto resource = cmrc::res::get_filesystem();
std::string resourceString = "Resources/" + filename;
auto trophytypefile = resource.open(resourceString);
QImage type_icon =
QImage(QString::fromStdString(resourceString))
.scaled(QSize(64, 64), Qt::KeepAspectRatio, Qt::SmoothTransformation);
typeitem->setData(Qt::DecorationRole, type_icon);
typeitem->setFlags(typeitem->flags() & ~Qt::ItemIsEditable);
tableWidget->setItem(row, 6, typeitem);
std::string detailString = trophyDetails[row].toStdString();
std::size_t newline_pos = 0;
while ((newline_pos = detailString.find("\n", newline_pos)) != std::string::npos) {
detailString.replace(newline_pos, 1, " ");
++newline_pos;
}
if (!trophyNames.isEmpty() && !trophyDetails.isEmpty()) {
SetTableItem(tableWidget, row, 0, trpUnlocked[row]);
SetTableItem(tableWidget, row, 2, trophyNames[row]);
SetTableItem(tableWidget, row, 3, trophyDetails[row]);
SetTableItem(tableWidget, row, 3, QString::fromStdString(detailString));
SetTableItem(tableWidget, row, 4, trpId[row]);
SetTableItem(tableWidget, row, 5, trpHidden[row]);
SetTableItem(tableWidget, row, 6, GetTrpType(trpType[row].at(0)));
SetTableItem(tableWidget, row, 7, trpPid[row]);
}
tableWidget->verticalHeader()->resizeSection(row, icon.height());
@ -157,7 +181,7 @@ void TrophyViewer::SetTableItem(QTableWidget* parent, int row, int column, QStri
label->setGraphicsEffect(shadowEffect); // Apply shadow effect to the QLabel
layout->addWidget(label);
if (column != 1 && column != 2)
if (column != 1 && column != 2 && column != 3)
layout->setAlignment(Qt::AlignCenter);
widget->setLayout(layout);
parent->setItem(row, column, item);

View file

@ -32,17 +32,17 @@ private:
QString gameTrpPath_;
TRP trp;
QString GetTrpType(const QChar trp_) {
std::string GetTrpType(const QChar trp_) {
switch (trp_.toLatin1()) {
case 'B':
return "Bronze";
return "bronze.png";
case 'S':
return "Silver";
return "silver.png";
case 'G':
return "Gold";
return "gold.png";
case 'P':
return "Platinum";
return "platinum.png";
}
return "Unknown";
}
};
};