mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-15 18:40:00 +00:00
overlays: add trophy list dialog
This commit is contained in:
parent
0bb2f72ee2
commit
1c22cc2f52
@ -528,6 +528,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||||||
RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp
|
RSX/Overlays/HomeMenu/overlay_home_menu_savestate.cpp
|
||||||
RSX/Overlays/Network/overlay_recvmessage_dialog.cpp
|
RSX/Overlays/Network/overlay_recvmessage_dialog.cpp
|
||||||
RSX/Overlays/Network/overlay_sendmessage_dialog.cpp
|
RSX/Overlays/Network/overlay_sendmessage_dialog.cpp
|
||||||
|
RSX/Overlays/Trophies/overlay_trophy_list_dialog.cpp
|
||||||
RSX/Overlays/overlays.cpp
|
RSX/Overlays/overlays.cpp
|
||||||
RSX/Overlays/overlay_animated_icon.cpp
|
RSX/Overlays/overlay_animated_icon.cpp
|
||||||
RSX/Overlays/overlay_animation.cpp
|
RSX/Overlays/overlay_animation.cpp
|
||||||
|
@ -5214,7 +5214,7 @@ error_code sceNpProfileCallGui(vm::cptr<SceNpId> npid, vm::ptr<SceNpProfileResul
|
|||||||
|
|
||||||
if (!nph.is_NP_init)
|
if (!nph.is_NP_init)
|
||||||
{
|
{
|
||||||
return SCE_NP_ERROR_NOT_INITIALIZED;
|
return SCE_NP_PROFILE_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SCE_NP_PROFILE_ERROR_BUSY
|
// TODO: SCE_NP_PROFILE_ERROR_BUSY
|
||||||
@ -5240,7 +5240,7 @@ error_code sceNpProfileAbortGui()
|
|||||||
|
|
||||||
if (!nph.is_NP_init)
|
if (!nph.is_NP_init)
|
||||||
{
|
{
|
||||||
return SCE_NP_ERROR_NOT_INITIALIZED;
|
return SCE_NP_FRIENDLIST_ERROR_NOT_INITIALIZED; // Not SCE_NP_PROFILE_ERROR_NOT_INITIALIZED !
|
||||||
}
|
}
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -504,10 +504,17 @@ error_code sceNpTrophyCreateContext(vm::ptr<u32> context, vm::cptr<SceNpCommunic
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set trophy context parameters (could be passed to constructor through make_ptr call)
|
// set trophy context parameters (could be passed to constructor through make_ptr call)
|
||||||
ctxt->trp_name = std::move(name);
|
ctxt->trp_name = name;
|
||||||
ctxt->read_only = !!(options & SCE_NP_TROPHY_OPTIONS_CREATE_CONTEXT_READ_ONLY);
|
ctxt->read_only = !!(options & SCE_NP_TROPHY_OPTIONS_CREATE_CONTEXT_READ_ONLY);
|
||||||
*context = idm::last_id();
|
*context = idm::last_id();
|
||||||
|
|
||||||
|
// set current trophy name for trophy list overlay
|
||||||
|
{
|
||||||
|
current_trophy_name& current_id = g_fxo->get<current_trophy_name>();
|
||||||
|
std::lock_guard lock(current_id.mtx);
|
||||||
|
current_id.name = std::move(name);
|
||||||
|
}
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,3 +168,9 @@ public:
|
|||||||
|
|
||||||
virtual s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophyIconBfr) = 0;
|
virtual s32 ShowTrophyNotification(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophyIconBfr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct current_trophy_name
|
||||||
|
{
|
||||||
|
std::mutex mtx;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
@ -217,7 +217,7 @@ namespace gl
|
|||||||
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid)
|
gl::texture_view* ui_overlay_renderer::load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid)
|
||||||
{
|
{
|
||||||
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, GL_RGBA8);
|
auto tex = std::make_unique<gl::texture>(GL_TEXTURE_2D, desc->w, desc->h, 1, 1, GL_RGBA8);
|
||||||
tex->copy_from(desc->data, gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
tex->copy_from(desc->get_data(), gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, {});
|
||||||
|
|
||||||
GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
GLenum remap[] = { GL_RED, GL_ALPHA, GL_BLUE, GL_GREEN };
|
||||||
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
auto view = std::make_unique<gl::texture_view>(tex.get(), remap);
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
#include "overlay_home_menu_settings.h"
|
#include "overlay_home_menu_settings.h"
|
||||||
#include "overlay_home_menu_savestate.h"
|
#include "overlay_home_menu_savestate.h"
|
||||||
#include "Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.h"
|
#include "Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.h"
|
||||||
|
#include "Emu/RSX/Overlays/Trophies/overlay_trophy_list_dialog.h"
|
||||||
#include "Emu/RSX/Overlays/overlay_manager.h"
|
#include "Emu/RSX/Overlays/overlay_manager.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/system_config.h"
|
#include "Emu/system_config.h"
|
||||||
|
#include "Emu/Cell/Modules/sceNpTrophy.h"
|
||||||
|
|
||||||
extern atomic_t<bool> g_user_asked_for_recording;
|
extern atomic_t<bool> g_user_asked_for_recording;
|
||||||
extern atomic_t<bool> g_user_asked_for_screenshot;
|
extern atomic_t<bool> g_user_asked_for_screenshot;
|
||||||
@ -55,6 +57,32 @@ namespace rsx
|
|||||||
return page_navigation::stay;
|
return page_navigation::stay;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// get current trophy name for trophy list overlay
|
||||||
|
std::string trop_name;
|
||||||
|
{
|
||||||
|
current_trophy_name& current_id = g_fxo->get<current_trophy_name>();
|
||||||
|
std::lock_guard lock(current_id.mtx);
|
||||||
|
trop_name = current_id.name;
|
||||||
|
}
|
||||||
|
if (!trop_name.empty())
|
||||||
|
{
|
||||||
|
std::unique_ptr<overlay_element> trophies = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_TROPHIES));
|
||||||
|
add_item(trophies, [trop_name = std::move(trop_name)](pad_button btn) -> page_navigation
|
||||||
|
{
|
||||||
|
if (btn != pad_button::cross) return page_navigation::stay;
|
||||||
|
|
||||||
|
rsx_log.notice("User selected trophies in home menu");
|
||||||
|
Emu.CallFromMainThread([trop_name = std::move(trop_name)]()
|
||||||
|
{
|
||||||
|
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||||
|
{
|
||||||
|
manager->create<rsx::overlays::trophy_list_dialog>()->show(trop_name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return page_navigation::stay;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<overlay_element> screenshot = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_SCREENSHOT));
|
std::unique_ptr<overlay_element> screenshot = std::make_unique<home_menu_entry>(get_localized_string(localized_string_id::HOME_MENU_SCREENSHOT));
|
||||||
add_item(screenshot, [](pad_button btn) -> page_navigation
|
add_item(screenshot, [](pad_button btn) -> page_navigation
|
||||||
{
|
{
|
||||||
|
356
rpcs3/Emu/RSX/Overlays/Trophies/overlay_trophy_list_dialog.cpp
Normal file
356
rpcs3/Emu/RSX/Overlays/Trophies/overlay_trophy_list_dialog.cpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "../overlay_manager.h"
|
||||||
|
#include "overlay_trophy_list_dialog.h"
|
||||||
|
#include "Emu/Cell/Modules/sceNpTrophy.h"
|
||||||
|
#include "Emu/System.h"
|
||||||
|
#include "Emu/VFS.h"
|
||||||
|
|
||||||
|
namespace rsx
|
||||||
|
{
|
||||||
|
namespace overlays
|
||||||
|
{
|
||||||
|
trophy_list_dialog::trophy_list_entry::trophy_list_entry(const std::string& name, const std::string& description, const std::string& trophy_type, const std::string& icon_path, bool hidden, bool locked, bool platinum_relevant)
|
||||||
|
{
|
||||||
|
std::unique_ptr<overlay_element> image = std::make_unique<image_view>();
|
||||||
|
image->set_size(160, 110);
|
||||||
|
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||||
|
|
||||||
|
if (fs::exists(icon_path))
|
||||||
|
{
|
||||||
|
icon_data = std::make_unique<image_info>(icon_path.c_str(), hidden || locked);
|
||||||
|
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Fallback
|
||||||
|
// TODO: use proper icon
|
||||||
|
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::square);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
|
||||||
|
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
|
||||||
|
std::unique_ptr<overlay_element> header_text = std::make_unique<label>(fmt::format("%s (%s%s)", (locked && !hidden) ? get_localized_string(localized_string_id::HOME_MENU_TROPHY_LOCKED_TITLE, name.c_str()) : name, trophy_type, platinum_relevant ? " - " + get_localized_string(localized_string_id::HOME_MENU_TROPHY_PLATINUM_RELEVANT) : ""));
|
||||||
|
std::unique_ptr<overlay_element> subtext = std::make_unique<label>(description);
|
||||||
|
|
||||||
|
padding->set_size(1, 1);
|
||||||
|
header_text->set_size(800, 40);
|
||||||
|
header_text->set_font("Arial", 16);
|
||||||
|
header_text->set_wrap_text(true);
|
||||||
|
|
||||||
|
subtext->set_size(800, 0);
|
||||||
|
subtext->set_font("Arial", 14);
|
||||||
|
subtext->set_wrap_text(true);
|
||||||
|
static_cast<label*>(subtext.get())->auto_resize(true);
|
||||||
|
|
||||||
|
// Make back color transparent for text
|
||||||
|
header_text->back_color.a = 0.f;
|
||||||
|
subtext->back_color.a = 0.f;
|
||||||
|
|
||||||
|
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
|
||||||
|
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
|
||||||
|
static_cast<vertical_layout*>(text_stack.get())->add_element(header_text);
|
||||||
|
static_cast<vertical_layout*>(text_stack.get())->add_element(subtext);
|
||||||
|
|
||||||
|
if (text_stack->h > image->h)
|
||||||
|
{
|
||||||
|
std::unique_ptr<overlay_element> padding2 = std::make_unique<spacer>();
|
||||||
|
padding2->set_size(1, 5);
|
||||||
|
static_cast<vertical_layout*>(text_stack.get())->add_element(padding2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack
|
||||||
|
this->pack_padding = 15;
|
||||||
|
add_element(image);
|
||||||
|
add_element(text_stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
trophy_list_dialog::trophy_list_dialog()
|
||||||
|
{
|
||||||
|
m_dim_background = std::make_unique<overlay_element>();
|
||||||
|
m_dim_background->set_size(virtual_width, virtual_height);
|
||||||
|
m_dim_background->back_color.a = 0.5f;
|
||||||
|
|
||||||
|
m_list = std::make_unique<list_view>(virtual_width - 2 * 20, 540);
|
||||||
|
m_list->set_pos(20, 85);
|
||||||
|
m_list->set_cancel_only(true);
|
||||||
|
|
||||||
|
m_description = std::make_unique<label>();
|
||||||
|
m_description->set_font("Arial", 20);
|
||||||
|
m_description->set_pos(20, 37);
|
||||||
|
m_description->set_text("Select trophy"); // Fallback. I don't think this will ever be used, so I won't localize it.
|
||||||
|
m_description->auto_resize();
|
||||||
|
m_description->back_color.a = 0.f;
|
||||||
|
|
||||||
|
fade_animation.duration_sec = 0.15f;
|
||||||
|
|
||||||
|
return_code = selection_code::canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trophy_list_dialog::update(u64 timestamp_us)
|
||||||
|
{
|
||||||
|
if (fade_animation.active)
|
||||||
|
{
|
||||||
|
fade_animation.update(timestamp_us);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void trophy_list_dialog::on_button_pressed(pad_button button_press, bool is_auto_repeat)
|
||||||
|
{
|
||||||
|
if (fade_animation.active) return;
|
||||||
|
|
||||||
|
bool close_dialog = false;
|
||||||
|
|
||||||
|
switch (button_press)
|
||||||
|
{
|
||||||
|
case pad_button::circle:
|
||||||
|
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cancel.wav");
|
||||||
|
close_dialog = true;
|
||||||
|
break;
|
||||||
|
case pad_button::dpad_up:
|
||||||
|
case pad_button::ls_up:
|
||||||
|
m_list->select_previous();
|
||||||
|
break;
|
||||||
|
case pad_button::dpad_down:
|
||||||
|
case pad_button::ls_down:
|
||||||
|
m_list->select_next();
|
||||||
|
break;
|
||||||
|
case pad_button::L1:
|
||||||
|
m_list->select_previous(10);
|
||||||
|
break;
|
||||||
|
case pad_button::R1:
|
||||||
|
m_list->select_next(10);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rsx_log.trace("[ui] Button %d pressed", static_cast<u8>(button_press));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close_dialog)
|
||||||
|
{
|
||||||
|
fade_animation.current = color4f(1.f);
|
||||||
|
fade_animation.end = color4f(0.f);
|
||||||
|
fade_animation.active = true;
|
||||||
|
|
||||||
|
fade_animation.on_finish = [this]
|
||||||
|
{
|
||||||
|
close(true, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Play a sound unless this is a fast auto repeat which would induce a nasty noise
|
||||||
|
else if (!is_auto_repeat || m_auto_repeat_ms_interval >= m_auto_repeat_ms_interval_default)
|
||||||
|
{
|
||||||
|
Emu.GetCallbacks().play_sound(fs::get_config_dir() + "sounds/snd_cursor.wav");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_resource trophy_list_dialog::get_compiled()
|
||||||
|
{
|
||||||
|
if (!visible)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
compiled_resource result;
|
||||||
|
result.add(m_dim_background->get_compiled());
|
||||||
|
result.add(m_list->get_compiled());
|
||||||
|
result.add(m_description->get_compiled());
|
||||||
|
|
||||||
|
fade_animation.apply(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trophy_list_dialog::show(const std::string& trop_name)
|
||||||
|
{
|
||||||
|
visible = false;
|
||||||
|
|
||||||
|
std::unique_ptr<trophy_data> data = load_trophies(trop_name);
|
||||||
|
ensure(data && data->trop_usr);
|
||||||
|
|
||||||
|
rsx_log.trace("Populating Trophy List Overlay with %s %s", data->game_name, data->path);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<overlay_element>> entries;
|
||||||
|
|
||||||
|
const int all_trophies = data->trop_usr->GetTrophiesCount();
|
||||||
|
const int unlocked_trophies = data->trop_usr->GetUnlockedTrophiesCount();
|
||||||
|
const int percentage = (all_trophies > 0) ? (100 * unlocked_trophies / all_trophies) : 0;
|
||||||
|
|
||||||
|
std::shared_ptr<rXmlNode> trophy_base = data->trop_config.GetRoot();
|
||||||
|
if (!trophy_base)
|
||||||
|
{
|
||||||
|
rsx_log.error("Populating Trophy List Overlay failed (root is null): %s %s", data->game_name, data->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string hidden_title = get_localized_string(localized_string_id::HOME_MENU_TROPHY_HIDDEN_TITLE);
|
||||||
|
const std::string hidden_description = get_localized_string(localized_string_id::HOME_MENU_TROPHY_HIDDEN_DESCRIPTION);
|
||||||
|
|
||||||
|
for (std::shared_ptr<rXmlNode> n = trophy_base ? trophy_base->GetChildren() : nullptr; n; n = n->GetNext())
|
||||||
|
{
|
||||||
|
// Only show trophies.
|
||||||
|
if (n->GetName() != "trophy")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get data (stolen graciously from sceNpTrophy.cpp)
|
||||||
|
SceNpTrophyDetails details{};
|
||||||
|
|
||||||
|
// Get trophy id
|
||||||
|
const s32 trophy_id = atoi(n->GetAttribute("id").c_str());
|
||||||
|
details.trophyId = trophy_id;
|
||||||
|
|
||||||
|
// Get platinum link id (we assume there only exists one platinum trophy per game for now)
|
||||||
|
const s32 platinum_link_id = atoi(n->GetAttribute("pid").c_str());
|
||||||
|
const bool platinum_relevant = platinum_link_id >= 0;
|
||||||
|
|
||||||
|
// Get trophy type
|
||||||
|
std::string trophy_type;
|
||||||
|
|
||||||
|
switch (n->GetAttribute("ttype")[0])
|
||||||
|
{
|
||||||
|
case 'B': details.trophyGrade = SCE_NP_TROPHY_GRADE_BRONZE; trophy_type = get_localized_string(localized_string_id::HOME_MENU_TROPHY_GRADE_BRONZE); break;
|
||||||
|
case 'S': details.trophyGrade = SCE_NP_TROPHY_GRADE_SILVER; trophy_type = get_localized_string(localized_string_id::HOME_MENU_TROPHY_GRADE_SILVER); break;
|
||||||
|
case 'G': details.trophyGrade = SCE_NP_TROPHY_GRADE_GOLD; trophy_type = get_localized_string(localized_string_id::HOME_MENU_TROPHY_GRADE_GOLD); break;
|
||||||
|
case 'P': details.trophyGrade = SCE_NP_TROPHY_GRADE_PLATINUM; trophy_type = get_localized_string(localized_string_id::HOME_MENU_TROPHY_GRADE_PLATINUM); break;
|
||||||
|
default: rsx_log.warning("Unknown trophy grade %s", n->GetAttribute("ttype")); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hidden state
|
||||||
|
const bool hidden = n->GetAttribute("hidden")[0] == 'y';
|
||||||
|
details.hidden = hidden;
|
||||||
|
|
||||||
|
// Get name and detail
|
||||||
|
if (hidden)
|
||||||
|
{
|
||||||
|
strcpy_trunc(details.name, hidden_title);
|
||||||
|
strcpy_trunc(details.description, hidden_description);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (std::shared_ptr<rXmlNode> n2 = n->GetChildren(); n2; n2 = n2->GetNext())
|
||||||
|
{
|
||||||
|
const std::string name = n2->GetName();
|
||||||
|
if (name == "name")
|
||||||
|
{
|
||||||
|
strcpy_trunc(details.name, n2->GetNodeContent());
|
||||||
|
}
|
||||||
|
else if (name == "detail")
|
||||||
|
{
|
||||||
|
strcpy_trunc(details.description, n2->GetNodeContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool unlocked = data->trop_usr->GetTrophyUnlockState(trophy_id);
|
||||||
|
const auto icon_path_it = data->trophy_image_paths.find(trophy_id);
|
||||||
|
|
||||||
|
std::unique_ptr<overlay_element> entry = std::make_unique<trophy_list_entry>(details.name, details.description, trophy_type, icon_path_it != data->trophy_image_paths.cend() ? icon_path_it->second : "", hidden, !unlocked, platinum_relevant);
|
||||||
|
entries.emplace_back(std::move(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& entry : entries)
|
||||||
|
{
|
||||||
|
m_list->add_entry(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_list->m_items.empty())
|
||||||
|
{
|
||||||
|
m_list->select_entry(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_description->set_text(get_localized_string(localized_string_id::HOME_MENU_TROPHY_LIST_TITLE, fmt::format("%d%% (%d/%d)", percentage, unlocked_trophies, all_trophies).c_str()));
|
||||||
|
m_description->auto_resize();
|
||||||
|
|
||||||
|
fade_animation.current = color4f(0.f);
|
||||||
|
fade_animation.end = color4f(1.f);
|
||||||
|
fade_animation.active = true;
|
||||||
|
|
||||||
|
this->on_close = std::move(on_close);
|
||||||
|
visible = true;
|
||||||
|
|
||||||
|
const auto notify = std::make_shared<atomic_t<u32>>(0);
|
||||||
|
auto& overlayman = g_fxo->get<display_manager>();
|
||||||
|
|
||||||
|
overlayman.attach_thread_input(
|
||||||
|
uid, "Trophy list dialog",
|
||||||
|
[notify]() { *notify = true; notify->notify_one(); }
|
||||||
|
);
|
||||||
|
|
||||||
|
while (!Emu.IsStopped() && !*notify)
|
||||||
|
{
|
||||||
|
notify->wait(0, atomic_wait_timeout{1'000'000});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<trophy_data> trophy_list_dialog::load_trophies(const std::string& trop_name) const
|
||||||
|
{
|
||||||
|
// Populate GameTrophiesData
|
||||||
|
std::unique_ptr<trophy_data> game_trophy_data = std::make_unique<trophy_data>();
|
||||||
|
game_trophy_data->trop_usr = std::make_unique<TROPUSRLoader>();
|
||||||
|
|
||||||
|
const std::string trophy_path = "/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + trop_name;
|
||||||
|
const std::string vfs_path = vfs::get(trophy_path + "/");
|
||||||
|
|
||||||
|
if (vfs_path.empty())
|
||||||
|
{
|
||||||
|
rsx_log.error("Failed to load trophy database for %s. Path empty!", trop_name);
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
game_trophy_data->path = vfs_path;
|
||||||
|
const std::string tropusr_path = trophy_path + "/TROPUSR.DAT";
|
||||||
|
const std::string tropconf_path = trophy_path + "/TROPCONF.SFM";
|
||||||
|
const bool success = game_trophy_data->trop_usr->Load(tropusr_path, tropconf_path).success;
|
||||||
|
|
||||||
|
fs::file config(vfs::get(tropconf_path));
|
||||||
|
|
||||||
|
if (!success || !config)
|
||||||
|
{
|
||||||
|
rsx_log.error("Failed to load trophy database for %s", trop_name);
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 trophy_count = game_trophy_data->trop_usr->GetTrophiesCount();
|
||||||
|
|
||||||
|
if (trophy_count == 0)
|
||||||
|
{
|
||||||
|
rsx_log.error("Warning game %s in trophy folder %s usr file reports zero trophies. Cannot load in trophy manager.", game_trophy_data->game_name, game_trophy_data->path);
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 trophy_id = 0; trophy_id < trophy_count; ++trophy_id)
|
||||||
|
{
|
||||||
|
// A trophy icon has 3 digits from 000 to 999, for example TROP001.PNG
|
||||||
|
game_trophy_data->trophy_image_paths[trophy_id] = fmt::format("%sTROP%03d.PNG", game_trophy_data->path, trophy_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get game name
|
||||||
|
pugi::xml_parse_result res = game_trophy_data->trop_config.Read(config.to_string());
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
rsx_log.error("Failed to read trophy xml: %s", tropconf_path);
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<rXmlNode> trophy_base = game_trophy_data->trop_config.GetRoot();
|
||||||
|
if (!trophy_base)
|
||||||
|
{
|
||||||
|
rsx_log.error("Failed to read trophy xml (root is null): %s", tropconf_path);
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::shared_ptr<rXmlNode> n = trophy_base->GetChildren(); n; n = n->GetNext())
|
||||||
|
{
|
||||||
|
if (n->GetName() == "title-name")
|
||||||
|
{
|
||||||
|
game_trophy_data->game_name = n->GetNodeContent();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.release();
|
||||||
|
|
||||||
|
return game_trophy_data;
|
||||||
|
}
|
||||||
|
} // namespace overlays
|
||||||
|
} // namespace RSX
|
54
rpcs3/Emu/RSX/Overlays/Trophies/overlay_trophy_list_dialog.h
Normal file
54
rpcs3/Emu/RSX/Overlays/Trophies/overlay_trophy_list_dialog.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../overlays.h"
|
||||||
|
#include "../overlay_list_view.hpp"
|
||||||
|
|
||||||
|
#include "Loader/TROPUSR.h"
|
||||||
|
|
||||||
|
class TROPUSRLoader;
|
||||||
|
|
||||||
|
namespace rsx
|
||||||
|
{
|
||||||
|
namespace overlays
|
||||||
|
{
|
||||||
|
struct trophy_data
|
||||||
|
{
|
||||||
|
std::unique_ptr<TROPUSRLoader> trop_usr;
|
||||||
|
trophy_xml_document trop_config;
|
||||||
|
std::unordered_map<int, std::string> trophy_image_paths;
|
||||||
|
std::string game_name;
|
||||||
|
std::string path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct trophy_list_dialog : public user_interface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct trophy_list_entry : horizontal_layout
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::unique_ptr<image_info> icon_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
trophy_list_entry(const std::string& name, const std::string& description, const std::string& trophy_type, const std::string& icon_path, bool hidden, bool locked, bool platinum_relevant);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<trophy_data> load_trophies(const std::string& trop_name) const;
|
||||||
|
|
||||||
|
std::unique_ptr<overlay_element> m_dim_background;
|
||||||
|
std::unique_ptr<list_view> m_list;
|
||||||
|
std::unique_ptr<label> m_description;
|
||||||
|
|
||||||
|
animation_color_interpolate fade_animation;
|
||||||
|
|
||||||
|
public:
|
||||||
|
trophy_list_dialog();
|
||||||
|
|
||||||
|
void update(u64 timestamp_us) override;
|
||||||
|
void on_button_pressed(pad_button button_press, bool is_auto_repeat) override;
|
||||||
|
|
||||||
|
compiled_resource get_compiled() override;
|
||||||
|
|
||||||
|
void show(const std::string& trop_name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -53,7 +53,7 @@ namespace rsx
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_info::image_info(const char* filename)
|
image_info::image_info(const char* filename, bool grayscaled)
|
||||||
{
|
{
|
||||||
fs::file f(filename, fs::read + fs::isfile);
|
fs::file f(filename, fs::read + fs::isfile);
|
||||||
|
|
||||||
@ -64,12 +64,12 @@ namespace rsx
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<u8> bytes = f.to_vector<u8>();
|
const std::vector<u8> bytes = f.to_vector<u8>();
|
||||||
load_data(bytes);
|
load_data(bytes, grayscaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
image_info::image_info(const std::vector<u8>& bytes)
|
image_info::image_info(const std::vector<u8>& bytes, bool grayscaled)
|
||||||
{
|
{
|
||||||
load_data(bytes);
|
load_data(bytes, grayscaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
image_info::~image_info()
|
image_info::~image_info()
|
||||||
@ -77,9 +77,30 @@ namespace rsx
|
|||||||
if (data) stbi_image_free(data);
|
if (data) stbi_image_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void image_info::load_data(const std::vector<u8>& bytes)
|
void image_info::load_data(const std::vector<u8>& bytes, bool grayscaled)
|
||||||
{
|
{
|
||||||
data = stbi_load_from_memory(bytes.data(), ::narrow<int>(bytes.size()), &w, &h, &bpp, STBI_rgb_alpha);
|
data = stbi_load_from_memory(bytes.data(), ::narrow<int>(bytes.size()), &w, &h, &bpp, grayscaled ? STBI_grey_alpha : STBI_rgb_alpha);
|
||||||
|
channels = grayscaled ? 2 : 4;
|
||||||
|
|
||||||
|
if (data && grayscaled)
|
||||||
|
{
|
||||||
|
data_grey.resize(4 * w * h);
|
||||||
|
|
||||||
|
for (usz i = 0, n = 0; i < data_grey.size(); i += 4, n += 2)
|
||||||
|
{
|
||||||
|
const u8 grey = data[n];
|
||||||
|
const u8 alpha = data[n + 1];
|
||||||
|
|
||||||
|
data_grey[i + 0] = grey;
|
||||||
|
data_grey[i + 1] = grey;
|
||||||
|
data_grey[i + 2] = grey;
|
||||||
|
data_grey[i + 3] = alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data_grey.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource_config::resource_config()
|
resource_config::resource_config()
|
||||||
@ -114,7 +135,7 @@ namespace rsx
|
|||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__) && defined(DATADIR)
|
#if !defined(_WIN32) && !defined(__APPLE__) && defined(DATADIR)
|
||||||
// Check the DATADIR if defined
|
// Check the DATADIR if defined
|
||||||
if (info->data == nullptr)
|
if (info->get_data() == nullptr)
|
||||||
{
|
{
|
||||||
const std::string data_dir (DATADIR);
|
const std::string data_dir (DATADIR);
|
||||||
const std::string image_data = data_dir + "/Icons/ui/" + res;
|
const std::string image_data = data_dir + "/Icons/ui/" + res;
|
||||||
@ -122,7 +143,7 @@ namespace rsx
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (info->data == nullptr)
|
if (info->get_data() == nullptr)
|
||||||
{
|
{
|
||||||
// Resource was not found in the DATADIR or config dir, try and grab from relative path (linux)
|
// Resource was not found in the DATADIR or config dir, try and grab from relative path (linux)
|
||||||
std::string src = "Icons/ui/" + res;
|
std::string src = "Icons/ui/" + res;
|
||||||
@ -130,12 +151,12 @@ namespace rsx
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
// Check for Icons in ../share/rpcs3 for AppImages,
|
// Check for Icons in ../share/rpcs3 for AppImages,
|
||||||
// in rpcs3.app/Contents/Resources for App Bundles, and /usr/bin.
|
// in rpcs3.app/Contents/Resources for App Bundles, and /usr/bin.
|
||||||
if (info->data == nullptr)
|
if (info->get_data() == nullptr)
|
||||||
{
|
{
|
||||||
char result[ PATH_MAX ];
|
char result[ PATH_MAX ];
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
u32 bufsize = PATH_MAX;
|
u32 bufsize = PATH_MAX;
|
||||||
bool success = _NSGetExecutablePath( result, &bufsize ) == 0;
|
const bool success = _NSGetExecutablePath( result, &bufsize ) == 0;
|
||||||
#elif defined(KERN_PROC_PATHNAME)
|
#elif defined(KERN_PROC_PATHNAME)
|
||||||
usz bufsize = PATH_MAX;
|
usz bufsize = PATH_MAX;
|
||||||
int mib[] = {
|
int mib[] = {
|
||||||
@ -150,13 +171,13 @@ namespace rsx
|
|||||||
-1,
|
-1,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
bool success = sysctl(mib, sizeof(mib)/sizeof(mib[0]), result, &bufsize, NULL, 0) >= 0;
|
const bool success = sysctl(mib, sizeof(mib)/sizeof(mib[0]), result, &bufsize, NULL, 0) >= 0;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
bool success = readlink( "/proc/self/exe", result, PATH_MAX ) >= 0;
|
const bool success = readlink( "/proc/self/exe", result, PATH_MAX ) >= 0;
|
||||||
#elif defined(__sun)
|
#elif defined(__sun)
|
||||||
bool success = readlink( "/proc/self/path/a.out", result, PATH_MAX ) >= 0;
|
const bool success = readlink( "/proc/self/path/a.out", result, PATH_MAX ) >= 0;
|
||||||
#else
|
#else
|
||||||
bool success = readlink( "/proc/curproc/file", result, PATH_MAX ) >= 0;
|
const bool success = readlink( "/proc/curproc/file", result, PATH_MAX ) >= 0;
|
||||||
#endif
|
#endif
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
@ -168,7 +189,7 @@ namespace rsx
|
|||||||
#endif
|
#endif
|
||||||
info = std::make_unique<image_info>(src.c_str());
|
info = std::make_unique<image_info>(src.c_str());
|
||||||
// Check if the icons are in the same directory as the executable (local builds)
|
// Check if the icons are in the same directory as the executable (local builds)
|
||||||
if (info->data == nullptr)
|
if (info->get_data() == nullptr)
|
||||||
{
|
{
|
||||||
src = executablePath + "/Icons/ui/" + res;
|
src = executablePath + "/Icons/ui/" + res;
|
||||||
info = std::make_unique<image_info>(src.c_str());
|
info = std::make_unique<image_info>(src.c_str());
|
||||||
@ -176,7 +197,7 @@ namespace rsx
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (info->data != nullptr)
|
if (info->get_data())
|
||||||
{
|
{
|
||||||
// Install the image to config dir
|
// Install the image to config dir
|
||||||
fs::create_path(fs::get_parent_dir(image_path));
|
fs::create_path(fs::get_parent_dir(image_path));
|
||||||
|
@ -33,16 +33,21 @@ namespace rsx
|
|||||||
|
|
||||||
struct image_info
|
struct image_info
|
||||||
{
|
{
|
||||||
int w = 0, h = 0;
|
private:
|
||||||
int bpp = 0;
|
|
||||||
u8* data = nullptr;
|
u8* data = nullptr;
|
||||||
|
std::vector<u8> data_grey;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int w = 0, h = 0, channels = 0;
|
||||||
|
int bpp = 0;
|
||||||
|
|
||||||
image_info(image_info&) = delete;
|
image_info(image_info&) = delete;
|
||||||
image_info(const char* filename);
|
image_info(const char* filename, bool grayscaled = false);
|
||||||
image_info(const std::vector<u8>& bytes);
|
image_info(const std::vector<u8>& bytes, bool grayscaled = false);
|
||||||
~image_info();
|
~image_info();
|
||||||
|
|
||||||
void load_data(const std::vector<u8>& bytes);
|
void load_data(const std::vector<u8>& bytes, bool grayscaled = false);
|
||||||
|
const u8* get_data() const { return channels == 4 ? data : data_grey.empty() ? nullptr : data_grey.data(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct resource_config
|
struct resource_config
|
||||||
|
@ -92,7 +92,7 @@ namespace rsx
|
|||||||
|
|
||||||
update_custom_background();
|
update_custom_background();
|
||||||
|
|
||||||
if (background_image && background_image->data)
|
if (background_image && background_image->get_data())
|
||||||
{
|
{
|
||||||
result.add(background_poster.get_compiled());
|
result.add(background_poster.get_compiled());
|
||||||
}
|
}
|
||||||
@ -359,11 +359,11 @@ namespace rsx
|
|||||||
if (const auto picture_path = Emu.GetBackgroundPicturePath(); fs::exists(picture_path))
|
if (const auto picture_path = Emu.GetBackgroundPicturePath(); fs::exists(picture_path))
|
||||||
{
|
{
|
||||||
background_image = std::make_unique<image_info>(picture_path.c_str());
|
background_image = std::make_unique<image_info>(picture_path.c_str());
|
||||||
dirty |= !!background_image->data;
|
dirty |= !!background_image->get_data();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dirty && background_image && background_image->data)
|
if (dirty && background_image && background_image->get_data())
|
||||||
{
|
{
|
||||||
const f32 color = (100 - background_darkening_strength) / 100.f;
|
const f32 color = (100 - background_darkening_strength) / 100.f;
|
||||||
background_poster.fore_color = color4f(color, color, color, 1.);
|
background_poster.fore_color = color4f(color, color, color, 1.);
|
||||||
|
@ -435,7 +435,7 @@ namespace vk
|
|||||||
|
|
||||||
for (const auto &res : configuration.texture_raw_data)
|
for (const auto &res : configuration.texture_raw_data)
|
||||||
{
|
{
|
||||||
upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, 1, false, false, res->data, -1);
|
upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, 1, false, false, res->get_data(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration.free_resources();
|
configuration.free_resources();
|
||||||
@ -516,7 +516,7 @@ namespace vk
|
|||||||
return found->second.get();
|
return found->second.get();
|
||||||
|
|
||||||
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1,
|
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1,
|
||||||
false, true, desc->data, owner_uid);
|
false, true, desc->get_data(), owner_uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VkPushConstantRange> ui_overlay_renderer::get_push_constants()
|
std::vector<VkPushConstantRange> ui_overlay_renderer::get_push_constants()
|
||||||
|
@ -271,6 +271,16 @@ enum class localized_string_id
|
|||||||
HOME_MENU_SAVESTATE_AND_EXIT,
|
HOME_MENU_SAVESTATE_AND_EXIT,
|
||||||
HOME_MENU_RELOAD_SAVESTATE,
|
HOME_MENU_RELOAD_SAVESTATE,
|
||||||
HOME_MENU_RECORDING,
|
HOME_MENU_RECORDING,
|
||||||
|
HOME_MENU_TROPHIES,
|
||||||
|
HOME_MENU_TROPHY_LIST_TITLE,
|
||||||
|
HOME_MENU_TROPHY_LOCKED_TITLE,
|
||||||
|
HOME_MENU_TROPHY_HIDDEN_TITLE,
|
||||||
|
HOME_MENU_TROPHY_HIDDEN_DESCRIPTION,
|
||||||
|
HOME_MENU_TROPHY_PLATINUM_RELEVANT,
|
||||||
|
HOME_MENU_TROPHY_GRADE_BRONZE,
|
||||||
|
HOME_MENU_TROPHY_GRADE_SILVER,
|
||||||
|
HOME_MENU_TROPHY_GRADE_GOLD,
|
||||||
|
HOME_MENU_TROPHY_GRADE_PLATINUM,
|
||||||
|
|
||||||
PROGRESS_DIALOG_PROGRESS,
|
PROGRESS_DIALOG_PROGRESS,
|
||||||
PROGRESS_DIALOG_PROGRESS_ANALYZING,
|
PROGRESS_DIALOG_PROGRESS_ANALYZING,
|
||||||
|
@ -137,6 +137,7 @@
|
|||||||
<ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" />
|
<ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" />
|
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" />
|
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" />
|
||||||
|
<ClCompile Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Program\ProgramStateCache.cpp" />
|
<ClCompile Include="Emu\RSX\Program\ProgramStateCache.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Program\program_util.cpp" />
|
<ClCompile Include="Emu\RSX\Program\program_util.cpp" />
|
||||||
<ClCompile Include="Emu\RSX\Program\SPIRVCommon.cpp" />
|
<ClCompile Include="Emu\RSX\Program\SPIRVCommon.cpp" />
|
||||||
@ -664,6 +665,7 @@
|
|||||||
<ClInclude Include="Emu\RSX\Overlays\overlay_manager.h" />
|
<ClInclude Include="Emu\RSX\Overlays\overlay_manager.h" />
|
||||||
<ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" />
|
<ClInclude Include="Emu\RSX\Overlays\overlay_media_list_dialog.h" />
|
||||||
<ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp" />
|
<ClInclude Include="Emu\RSX\Overlays\overlay_progress_bar.hpp" />
|
||||||
|
<ClInclude Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.h" />
|
||||||
<ClInclude Include="Emu\RSX\Program\GLSLTypes.h" />
|
<ClInclude Include="Emu\RSX\Program\GLSLTypes.h" />
|
||||||
<ClInclude Include="Emu\RSX\Program\ProgramStateCache.h" />
|
<ClInclude Include="Emu\RSX\Program\ProgramStateCache.h" />
|
||||||
<ClInclude Include="Emu\RSX\Program\program_util.h" />
|
<ClInclude Include="Emu\RSX\Program\program_util.h" />
|
||||||
|
@ -127,6 +127,9 @@
|
|||||||
<Filter Include="Emu\GPU\RSX\Utils">
|
<Filter Include="Emu\GPU\RSX\Utils">
|
||||||
<UniqueIdentifier>{0e218fca-53a6-4066-a412-4e0659d6ff0b}</UniqueIdentifier>
|
<UniqueIdentifier>{0e218fca-53a6-4066-a412-4e0659d6ff0b}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Emu\GPU\RSX\Overlays\Trophies">
|
||||||
|
<UniqueIdentifier>{caf84300-5c45-4340-bd9a-8ac859409351}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Crypto\aes.cpp">
|
<ClCompile Include="Crypto\aes.cpp">
|
||||||
@ -1318,6 +1321,9 @@
|
|||||||
<ClCompile Include="Emu\RSX\Core\RSXDrawCommands.cpp">
|
<ClCompile Include="Emu\RSX\Core\RSXDrawCommands.cpp">
|
||||||
<Filter>Emu\GPU\RSX\Core</Filter>
|
<Filter>Emu\GPU\RSX\Core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.cpp">
|
||||||
|
<Filter>Emu\GPU\RSX\Overlays\Trophies</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Crypto\aes.h">
|
<ClInclude Include="Crypto\aes.h">
|
||||||
@ -2668,6 +2674,9 @@
|
|||||||
<ClInclude Include="Emu\RSX\Core\RSXDriverState.h">
|
<ClInclude Include="Emu\RSX\Core\RSXDriverState.h">
|
||||||
<Filter>Emu\GPU\RSX\Core</Filter>
|
<Filter>Emu\GPU\RSX\Core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Emu\RSX\Overlays\Trophies\overlay_trophy_list_dialog.h">
|
||||||
|
<Filter>Emu\GPU\RSX\Overlays\Trophies</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||||
|
@ -636,6 +636,7 @@ int main(int argc, char** argv)
|
|||||||
if (i > 0) utf8_args += " ";
|
if (i > 0) utf8_args += " ";
|
||||||
utf8_args += '\'' + wchar_to_utf8(arg_list[i]) + '\'';
|
utf8_args += '\'' + wchar_to_utf8(arg_list[i]) + '\'';
|
||||||
}
|
}
|
||||||
|
LocalFree(arg_list);
|
||||||
sys_log.notice("argv_utf8: %s", utf8_args);
|
sys_log.notice("argv_utf8: %s", utf8_args);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -292,6 +292,16 @@ private:
|
|||||||
case localized_string_id::HOME_MENU_SAVESTATE_AND_EXIT: return tr("Save Emulation State And Exit");
|
case localized_string_id::HOME_MENU_SAVESTATE_AND_EXIT: return tr("Save Emulation State And Exit");
|
||||||
case localized_string_id::HOME_MENU_RELOAD_SAVESTATE: return tr("Reload Last Emulation State");
|
case localized_string_id::HOME_MENU_RELOAD_SAVESTATE: return tr("Reload Last Emulation State");
|
||||||
case localized_string_id::HOME_MENU_RECORDING: return tr("Start/Stop Recording");
|
case localized_string_id::HOME_MENU_RECORDING: return tr("Start/Stop Recording");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHIES: return tr("Trophies");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_LIST_TITLE: return tr("Trophy Progress: %0").arg(std::forward<Args>(args)...);
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_LOCKED_TITLE: return tr("Locked trophy: %0").arg(std::forward<Args>(args)...);
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_HIDDEN_TITLE: return tr("Hidden trophy");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_HIDDEN_DESCRIPTION: return tr("This trophy is hidden");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_PLATINUM_RELEVANT: return tr("Platinum relevant");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_GRADE_BRONZE: return tr("Bronze", "Trophy type");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_GRADE_SILVER: return tr("Silver", "Trophy type");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_GRADE_GOLD: return tr("Gold", "Trophy type");
|
||||||
|
case localized_string_id::HOME_MENU_TROPHY_GRADE_PLATINUM: return tr("Platinum", "Trophy type");
|
||||||
case localized_string_id::PROGRESS_DIALOG_PROGRESS: return tr("Progress:");
|
case localized_string_id::PROGRESS_DIALOG_PROGRESS: return tr("Progress:");
|
||||||
case localized_string_id::PROGRESS_DIALOG_PROGRESS_ANALYZING: return tr("Progress: analyzing...");
|
case localized_string_id::PROGRESS_DIALOG_PROGRESS_ANALYZING: return tr("Progress: analyzing...");
|
||||||
case localized_string_id::PROGRESS_DIALOG_REMAINING: return tr("remaining");
|
case localized_string_id::PROGRESS_DIALOG_REMAINING: return tr("remaining");
|
||||||
|
@ -420,7 +420,7 @@ bool trophy_manager_dialog::LoadTrophyFolderToDB(const std::string& trop_name)
|
|||||||
std::unique_ptr<GameTrophiesData> game_trophy_data = std::make_unique<GameTrophiesData>();
|
std::unique_ptr<GameTrophiesData> game_trophy_data = std::make_unique<GameTrophiesData>();
|
||||||
|
|
||||||
game_trophy_data->path = vfs_path;
|
game_trophy_data->path = vfs_path;
|
||||||
game_trophy_data->trop_usr.reset(new TROPUSRLoader());
|
game_trophy_data->trop_usr = std::make_unique<TROPUSRLoader>();
|
||||||
const std::string tropusr_path = trophy_path + "/TROPUSR.DAT";
|
const std::string tropusr_path = trophy_path + "/TROPUSR.DAT";
|
||||||
const std::string tropconf_path = trophy_path + "/TROPCONF.SFM";
|
const std::string tropconf_path = trophy_path + "/TROPCONF.SFM";
|
||||||
const bool success = game_trophy_data->trop_usr->Load(tropusr_path, tropconf_path).success;
|
const bool success = game_trophy_data->trop_usr->Load(tropusr_path, tropconf_path).success;
|
||||||
@ -1114,7 +1114,7 @@ void trophy_manager_dialog::PopulateTrophyTable()
|
|||||||
|
|
||||||
const int all_trophies = data->trop_usr->GetTrophiesCount();
|
const int all_trophies = data->trop_usr->GetTrophiesCount();
|
||||||
const int unlocked_trophies = data->trop_usr->GetUnlockedTrophiesCount();
|
const int unlocked_trophies = data->trop_usr->GetUnlockedTrophiesCount();
|
||||||
const int percentage = 100 * unlocked_trophies / all_trophies;
|
const int percentage = (all_trophies > 0) ? (100 * unlocked_trophies / all_trophies) : 0;
|
||||||
|
|
||||||
m_game_progress->setText(tr("Progress: %1% (%2/%3)").arg(percentage).arg(unlocked_trophies).arg(all_trophies));
|
m_game_progress->setText(tr("Progress: %1% (%2/%3)").arg(percentage).arg(unlocked_trophies).arg(all_trophies));
|
||||||
|
|
||||||
@ -1172,11 +1172,12 @@ void trophy_manager_dialog::PopulateTrophyTable()
|
|||||||
// Get name and detail
|
// Get name and detail
|
||||||
for (std::shared_ptr<rXmlNode> n2 = n->GetChildren(); n2; n2 = n2->GetNext())
|
for (std::shared_ptr<rXmlNode> n2 = n->GetChildren(); n2; n2 = n2->GetNext())
|
||||||
{
|
{
|
||||||
if (n2->GetName() == "name")
|
const std::string name = n2->GetName();
|
||||||
|
if (name == "name")
|
||||||
{
|
{
|
||||||
strcpy_trunc(details.name, n2->GetNodeContent());
|
strcpy_trunc(details.name, n2->GetNodeContent());
|
||||||
}
|
}
|
||||||
if (n2->GetName() == "detail")
|
else if (name == "detail")
|
||||||
{
|
{
|
||||||
strcpy_trunc(details.description, n2->GetNodeContent());
|
strcpy_trunc(details.description, n2->GetNodeContent());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user