From 1ae3b37fbebb0ff04faee541c418088f614fd20a Mon Sep 17 00:00:00 2001 From: Megamouse Date: Mon, 15 May 2023 23:22:13 +0200 Subject: [PATCH] sceNpTrophy: set timestamps --- rpcs3/Emu/Cell/Modules/cellRtc.cpp | 58 ++++++++++++++----------- rpcs3/Emu/Cell/Modules/cellRtc.h | 3 ++ rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp | 10 ++++- rpcs3/rpcs3qt/gui_settings.cpp | 2 + rpcs3/rpcs3qt/gui_settings.h | 1 + rpcs3/rpcs3qt/trophy_manager_dialog.cpp | 20 +++++++++ rpcs3/rpcs3qt/trophy_manager_dialog.h | 2 + 7 files changed, 69 insertions(+), 27 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/rpcs3/Emu/Cell/Modules/cellRtc.cpp index b2f0edd2ce..40c781665d 100644 --- a/rpcs3/Emu/Cell/Modules/cellRtc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRtc.cpp @@ -786,20 +786,8 @@ error_code cellRtcGetTick(vm::cptr pTime, vm::ptr return CELL_OK; } -error_code cellRtcSetTick(vm::ptr pTime, vm::cptr pTick) +CellRtcDateTime tick_to_date_time(u64 tick) { - cellRtc.todo("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); - - if (!vm::check_addr(pTime.addr())) - { - return CELL_RTC_ERROR_INVALID_POINTER; - } - - if (!vm::check_addr(pTick.addr())) - { - return CELL_RTC_ERROR_INVALID_POINTER; - } - /* u32 microseconds = round((pTick->tick % 1000000ULL)); u16 seconds = round((pTick->tick / (1000000ULL)) % 60); @@ -807,11 +795,11 @@ error_code cellRtcSetTick(vm::ptr pTime, vm::cptr u16 hours = round((pTick->tick / (60ULL * 60ULL * 1000000ULL)) % 24); u64 days_tmp = round((pTick->tick / (24ULL * 60ULL * 60ULL * 1000000ULL)));*/ - u32 microseconds = (pTick->tick % 1000000ULL); - u16 seconds = (pTick->tick / (1000000ULL)) % 60; - u16 minutes = (pTick->tick / (60ULL * 1000000ULL)) % 60; - u16 hours = (pTick->tick / (60ULL * 60ULL * 1000000ULL)) % 24; - u64 days_tmp = (pTick->tick / (24ULL * 60ULL * 60ULL * 1000000ULL)); + const u32 microseconds = (tick % 1000000ULL); + const u16 seconds = (tick / (1000000ULL)) % 60; + const u16 minutes = (tick / (60ULL * 1000000ULL)) % 60; + const u16 hours = (tick / (60ULL * 60ULL * 1000000ULL)) % 24; + u64 days_tmp = (tick / (24ULL * 60ULL * 60ULL * 1000000ULL)); u16 months = 1; u16 years = 1; @@ -842,13 +830,33 @@ error_code cellRtcSetTick(vm::ptr pTime, vm::cptr } while (!exit_while); - pTime->microsecond = microseconds; - pTime->second = seconds; - pTime->minute = minutes; - pTime->hour = hours; - pTime->day = ::narrow(days_tmp + 1); - pTime->month = months; - pTime->year = years; + CellRtcDateTime date_time{ + .year = years, + .month = months, + .day = ::narrow(days_tmp + 1), + .hour = hours, + .minute = minutes, + .second = seconds, + .microsecond = microseconds + }; + return date_time; +} + +error_code cellRtcSetTick(vm::ptr pTime, vm::cptr pTick) +{ + cellRtc.todo("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + + if (!vm::check_addr(pTime.addr())) + { + return CELL_RTC_ERROR_INVALID_POINTER; + } + + if (!vm::check_addr(pTick.addr())) + { + return CELL_RTC_ERROR_INVALID_POINTER; + } + + *pTime = tick_to_date_time(pTick->tick); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.h b/rpcs3/Emu/Cell/Modules/cellRtc.h index 13e60e888a..7a8bad18e3 100644 --- a/rpcs3/Emu/Cell/Modules/cellRtc.h +++ b/rpcs3/Emu/Cell/Modules/cellRtc.h @@ -50,3 +50,6 @@ u32 cellRtcGetTickResolution(); error_code cellRtcCheckValid(vm::cptr pTime); error_code cellRtcGetDayOfWeek(s32 year, s32 month, s32 day); error_code cellRtcGetTick(vm::cptr pTime, vm::ptr pTick); +error_code cellRtcGetCurrentTick(vm::ptr pTick); + +CellRtcDateTime tick_to_date_time(u64 tick); diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 3e29fdf427..c24e0d43db 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -991,7 +991,13 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt return SCE_NP_TROPHY_ERROR_ALREADY_UNLOCKED; } - ctxt->tropusr->UnlockTrophy(trophyId, 0, 0); // TODO: add timestamps + vm::var tick; + if (error_code error = cellRtcGetCurrentTick(tick)) + { + sceNpTrophy.error("sceNpTrophyUnlockTrophy: Failed to get timestamp: 0x%x", +error); + } + + ctxt->tropusr->UnlockTrophy(trophyId, tick->tick, tick->tick); // TODO: Make sure that unlocking platinum trophies is properly implemented and improve upon it const std::string& config_path = vfs::get("/dev_hdd0/home/" + Emu.GetUsr() + "/trophy/" + ctxt->trp_name + "/TROPCONF.SFM"); @@ -1001,7 +1007,7 @@ error_code sceNpTrophyUnlockTrophy(u32 context, u32 handle, s32 trophyId, vm::pt { sceNpTrophy.warning("sceNpTrophyUnlockTrophy: All requirements for unlocking the platinum trophy (ID = %d) were met.)", unlocked_platinum_id); - if (ctxt->tropusr->UnlockTrophy(unlocked_platinum_id, 0, 0)) // TODO: add timestamps + if (ctxt->tropusr->UnlockTrophy(unlocked_platinum_id, tick->tick, tick->tick)) { sceNpTrophy.success("You unlocked a platinum trophy! Hooray!!!"); } diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index 4099bca134..0447c5ab05 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -72,6 +72,8 @@ namespace gui return "trophy_column_id"; case trophy_list_columns::platinum_link: return "trophy_column_platinum_link"; + case trophy_list_columns::time_unlocked: + return "trophy_column_time_unlocked"; case trophy_list_columns::count: return ""; } diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index c6c284d7bb..dd8f44ae8b 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -47,6 +47,7 @@ namespace gui is_unlocked = 4, id = 5, platinum_link = 6, + time_unlocked = 7, count }; diff --git a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp index de187de6d6..2d68fbd73e 100644 --- a/rpcs3/rpcs3qt/trophy_manager_dialog.cpp +++ b/rpcs3/rpcs3qt/trophy_manager_dialog.cpp @@ -6,6 +6,7 @@ #include "game_list.h" #include "gui_settings.h" #include "progress_dialog.h" +#include "persistent_settings.h" #include "util/logs.hpp" #include "Utilities/StrUtil.h" @@ -14,6 +15,7 @@ #include "Emu/System.h" #include "Emu/system_utils.hpp" #include "Emu/Cell/Modules/sceNpTrophy.h" +#include "Emu/Cell/Modules/cellRtc.h" #include #include @@ -148,6 +150,7 @@ trophy_manager_dialog::trophy_manager_dialog(std::shared_ptr gui_s add_trophy_column(gui::trophy_list_columns::is_unlocked, tr("Status"), tr("Show Status")); add_trophy_column(gui::trophy_list_columns::id, tr("ID"), tr("Show IDs")); add_trophy_column(gui::trophy_list_columns::platinum_link, tr("Platinum Relevant"), tr("Show Platinum Relevant")); + add_trophy_column(gui::trophy_list_columns::time_unlocked, tr("Time Unlocked"), tr("Show Time Unlocked")); m_splitter = new QSplitter(); m_splitter->addWidget(m_game_table); @@ -1028,6 +1031,8 @@ void trophy_manager_dialog::PopulateTrophyTable() QPixmap placeholder(m_icon_height, m_icon_height); placeholder.fill(Qt::transparent); + const QLocale locale{}; + int i = 0; for (std::shared_ptr n = trophy_base->GetChildren(); n; n = n->GetNext()) { @@ -1079,6 +1084,10 @@ void trophy_manager_dialog::PopulateTrophyTable() } } + // Get timestamp + const u64 tick = data->trop_usr->GetTrophyTimestamp(trophy_id); + const QString datetime = tick ? locale.toString(TickToDateTime(tick), gui::persistent::last_played_date_with_time_of_day_format) : tr("Unknown"); + const QString unlockstate = data->trop_usr->GetTrophyUnlockState(trophy_id) ? tr("Earned") : tr("Not Earned"); custom_table_widget_item* icon_item = new custom_table_widget_item(); @@ -1095,6 +1104,7 @@ void trophy_manager_dialog::PopulateTrophyTable() m_trophy_table->setItem(i, static_cast(gui::trophy_list_columns::is_unlocked), new custom_table_widget_item(unlockstate)); m_trophy_table->setItem(i, static_cast(gui::trophy_list_columns::id), new custom_table_widget_item(QString::number(trophy_id), Qt::UserRole, trophy_id)); m_trophy_table->setItem(i, static_cast(gui::trophy_list_columns::platinum_link), new custom_table_widget_item(platinum_relevant, Qt::UserRole, platinum_link_id)); + m_trophy_table->setItem(i, static_cast(gui::trophy_list_columns::time_unlocked), new custom_table_widget_item(datetime, Qt::UserRole, QVariant::fromValue(tick))); ++i; } @@ -1225,3 +1235,13 @@ void trophy_manager_dialog::WaitAndAbortTrophyRepaintThreads() } } } + +QDateTime trophy_manager_dialog::TickToDateTime(u64 tick) +{ + const CellRtcDateTime rtc_date = tick_to_date_time(tick); + const QDateTime datetime( + QDate(rtc_date.year, rtc_date.month, rtc_date.day), + QTime(rtc_date.hour, rtc_date.minute, rtc_date.second, rtc_date.microsecond / 1000), + Qt::TimeSpec::UTC); + return datetime.toLocalTime(); +} diff --git a/rpcs3/rpcs3qt/trophy_manager_dialog.h b/rpcs3/rpcs3qt/trophy_manager_dialog.h index c6d70fa970..1f15f3a24b 100644 --- a/rpcs3/rpcs3qt/trophy_manager_dialog.h +++ b/rpcs3/rpcs3qt/trophy_manager_dialog.h @@ -80,6 +80,8 @@ private: void closeEvent(QCloseEvent *event) override; bool eventFilter(QObject *object, QEvent *event) override; + static QDateTime TickToDateTime(u64 tick); + std::shared_ptr m_gui_settings; std::vector> m_trophies_db; //! Holds all the trophy information.