From d4eae28ce217f9ac19206bf91e8bd2bbb098036a Mon Sep 17 00:00:00 2001 From: DanielSvoboda Date: Wed, 9 Oct 2024 07:30:51 -0300 Subject: [PATCH] Play Time (#1305) * Play Time * SDL * QT * Sort / Formatting * Timer 1 minute * remove the seconds removes the seconds from the screen, but in the play_time.txt file it continues to record the seconds for better accuracy, and the screen is cleaner * fixes the invisible 0 * SDL . . . * Fix Timer --- src/emulator.cpp | 94 ++++++++++++++++++++++++++++++++ src/emulator.h | 2 + src/qt_gui/game_info.h | 3 + src/qt_gui/game_list_frame.cpp | 67 +++++++++++++++++++++-- src/qt_gui/game_list_frame.h | 7 ++- src/qt_gui/game_list_utils.h | 2 + src/qt_gui/main_window.cpp | 1 + src/qt_gui/settings_dialog.ui | 4 +- src/qt_gui/translations/ar.ts | 5 ++ src/qt_gui/translations/da_DK.ts | 5 ++ src/qt_gui/translations/de.ts | 5 ++ src/qt_gui/translations/el.ts | 5 ++ src/qt_gui/translations/en.ts | 5 ++ src/qt_gui/translations/es_ES.ts | 5 ++ src/qt_gui/translations/fa_IR.ts | 5 ++ src/qt_gui/translations/fi.ts | 5 ++ src/qt_gui/translations/fr.ts | 5 ++ src/qt_gui/translations/hu_HU.ts | 5 ++ src/qt_gui/translations/id.ts | 5 ++ src/qt_gui/translations/it.ts | 5 ++ src/qt_gui/translations/ja_JP.ts | 5 ++ src/qt_gui/translations/ko_KR.ts | 5 ++ src/qt_gui/translations/lt_LT.ts | 5 ++ src/qt_gui/translations/nb.ts | 5 ++ src/qt_gui/translations/nl.ts | 5 ++ src/qt_gui/translations/pl_PL.ts | 5 ++ src/qt_gui/translations/pt_BR.ts | 5 ++ src/qt_gui/translations/ro_RO.ts | 5 ++ src/qt_gui/translations/ru_RU.ts | 5 ++ src/qt_gui/translations/sq.ts | 5 ++ src/qt_gui/translations/tr_TR.ts | 5 ++ src/qt_gui/translations/vi_VN.ts | 5 ++ src/qt_gui/translations/zh_CN.ts | 5 ++ src/qt_gui/translations/zh_TW.ts | 5 ++ 34 files changed, 303 insertions(+), 7 deletions(-) diff --git a/src/emulator.cpp b/src/emulator.cpp index a9d0f6de2..9f801fb83 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -8,6 +8,7 @@ #include "common/logging/backend.h" #include "common/logging/log.h" #ifdef ENABLE_QT_GUI +#include #include "common/memory_patcher.h" #endif #include "common/assert.h" @@ -79,6 +80,17 @@ Emulator::Emulator() { // Load renderdoc module. VideoCore::LoadRenderDoc(); + + // Start the timer (Play Time) +#ifdef ENABLE_QT_GUI + start_time = std::chrono::steady_clock::now(); + const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); + QString filePath = QString::fromStdString((user_dir / "play_time.txt").string()); + QFile file(filePath); + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { + LOG_INFO(Loader, "Error opening or creating play_time.txt"); + } +#endif } Emulator::~Emulator() { @@ -122,6 +134,14 @@ void Emulator::Run(const std::filesystem::path& file) { } #ifdef ENABLE_QT_GUI MemoryPatcher::g_game_serial = id; + + // Timer for 'Play Time' + QTimer* timer = new QTimer(); + QObject::connect(timer, &QTimer::timeout, [this, id]() { + UpdatePlayTime(id); + start_time = std::chrono::steady_clock::now(); + }); + timer->start(60000); // 60000 ms = 1 minute #endif title = param_sfo->GetString("TITLE").value_or("Unknown title"); LOG_INFO(Loader, "Game id: {} Title: {}", id, title); @@ -228,6 +248,10 @@ void Emulator::Run(const std::filesystem::path& file) { window->waitEvent(); } +#ifdef ENABLE_QT_GUI + UpdatePlayTime(id); +#endif + std::exit(0); } @@ -269,4 +293,74 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) { } } +#ifdef ENABLE_QT_GUI +void Emulator::UpdatePlayTime(const std::string& serial) { + const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); + QString filePath = QString::fromStdString((user_dir / "play_time.txt").string()); + + QFile file(filePath); + if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { + LOG_INFO(Loader, "Error opening play_time.txt"); + return; + } + + auto end_time = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast(end_time - start_time); + int totalSeconds = duration.count(); + + QTextStream in(&file); + QStringList lines; + QString content; + while (!in.atEnd()) { + content += in.readLine() + "\n"; + } + file.close(); + + QStringList existingLines = content.split('\n', Qt::SkipEmptyParts); + int accumulatedSeconds = 0; + bool found = false; + + for (const QString& line : existingLines) { + QStringList parts = line.split(' '); + if (parts.size() == 2 && parts[0] == QString::fromStdString(serial)) { + QStringList timeParts = parts[1].split(':'); + if (timeParts.size() == 3) { + int hours = timeParts[0].toInt(); + int minutes = timeParts[1].toInt(); + int seconds = timeParts[2].toInt(); + accumulatedSeconds = hours * 3600 + minutes * 60 + seconds; + found = true; + break; + } + } + } + accumulatedSeconds += totalSeconds; + int hours = accumulatedSeconds / 3600; + int minutes = (accumulatedSeconds % 3600) / 60; + int seconds = accumulatedSeconds % 60; + QString playTimeSaved = QString::number(hours) + ":" + + QString::number(minutes).rightJustified(2, '0') + ":" + + QString::number(seconds).rightJustified(2, '0'); + + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&file); + bool lineUpdated = false; + + for (const QString& line : existingLines) { + if (line.startsWith(QString::fromStdString(serial))) { + out << QString::fromStdString(serial) + " " + playTimeSaved + "\n"; + lineUpdated = true; + } else { + out << line << "\n"; + } + } + + if (!lineUpdated) { + out << QString::fromStdString(serial) + " " + playTimeSaved + "\n"; + } + } + LOG_INFO(Loader, "Playing time for {}: {}", serial, playTimeSaved.toStdString()); +} +#endif + } // namespace Core diff --git a/src/emulator.h b/src/emulator.h index 01bce7e7c..dc2959af4 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -26,6 +26,7 @@ public: ~Emulator(); void Run(const std::filesystem::path& file); + void UpdatePlayTime(const std::string& serial); private: void LoadSystemModules(const std::filesystem::path& file); @@ -34,6 +35,7 @@ private: Input::GameController* controller; Core::Linker* linker; std::unique_ptr window; + std::chrono::steady_clock::time_point start_time; }; } // namespace Core diff --git a/src/qt_gui/game_info.h b/src/qt_gui/game_info.h index 9db25482a..8f65803bf 100644 --- a/src/qt_gui/game_info.h +++ b/src/qt_gui/game_info.h @@ -60,6 +60,9 @@ public: if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) { game.version = *app_ver; } + if (const auto play_time = psf.GetString("PLAY_TIME"); play_time.has_value()) { + game.play_time = *play_time; + } } return game; } diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index c2f6736b8..99628b083 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -24,16 +24,17 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, QWidg this->horizontalHeader()->setSortIndicatorShown(true); this->horizontalHeader()->setStretchLastSection(true); this->setContextMenuPolicy(Qt::CustomContextMenu); - this->setColumnCount(8); + this->setColumnCount(9); this->setColumnWidth(1, 300); // Name this->setColumnWidth(2, 120); // Serial this->setColumnWidth(3, 90); // Region this->setColumnWidth(4, 90); // Firmware this->setColumnWidth(5, 90); // Size this->setColumnWidth(6, 90); // Version + this->setColumnWidth(7, 100); // Play Time QStringList headers; headers << tr("Icon") << tr("Name") << tr("Serial") << tr("Region") << tr("Firmware") - << tr("Size") << tr("Version") << tr("Path"); + << tr("Size") << tr("Version") << tr("Play Time") << tr("Path"); this->setHorizontalHeaderLabels(headers); this->horizontalHeader()->setSortIndicatorShown(true); this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); @@ -100,9 +101,37 @@ void GameListFrame::PopulateGameList() { SetTableItem(i, 4, QString::fromStdString(m_game_info->m_games[i].fw)); SetTableItem(i, 5, QString::fromStdString(m_game_info->m_games[i].size)); SetTableItem(i, 6, QString::fromStdString(m_game_info->m_games[i].version)); + + QString playTime = GetPlayTime(m_game_info->m_games[i].serial); + if (playTime.isEmpty()) { + m_game_info->m_games[i].play_time = "0:00:00"; + SetTableItem(i, 7, "0"); + } else { + QStringList timeParts = playTime.split(':'); + int hours = timeParts[0].toInt(); + int minutes = timeParts[1].toInt(); + int seconds = timeParts[2].toInt(); + + QString formattedPlayTime; + if (hours > 0) { + formattedPlayTime += QString("%1h ").arg(hours); + } + if (minutes > 0) { + formattedPlayTime += QString("%1m ").arg(minutes); + } + + formattedPlayTime = formattedPlayTime.trimmed(); + m_game_info->m_games[i].play_time = playTime.toStdString(); + if (formattedPlayTime.isEmpty()) { + SetTableItem(i, 7, "0"); + } else { + SetTableItem(i, 7, formattedPlayTime); + } + } + QString path; Common::FS::PathToQString(path, m_game_info->m_games[i].path); - SetTableItem(i, 7, path); + SetTableItem(i, 8, path); } } @@ -171,7 +200,7 @@ void GameListFrame::ResizeIcons(int iconSize) { this->setItem(index, 0, iconItem); index++; } - this->horizontalHeader()->setSectionResizeMode(7, QHeaderView::ResizeToContents); + this->horizontalHeader()->setSectionResizeMode(8, QHeaderView::ResizeToContents); } void GameListFrame::SetTableItem(int row, int column, QString itemStr) { @@ -224,3 +253,33 @@ void GameListFrame::SetRegionFlag(int row, int column, QString itemStr) { this->setItem(row, column, item); this->setCellWidget(row, column, widget); } + +QString GameListFrame::GetPlayTime(const std::string& serial) { + QString playTime; + const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); + QString filePath = QString::fromStdString((user_dir / "play_time.txt").string()); + + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return playTime; + } + + while (!file.atEnd()) { + QByteArray line = file.readLine(); + QString lineStr = QString::fromUtf8(line).trimmed(); + + QStringList parts = lineStr.split(' '); + if (parts.size() >= 2) { + QString fileSerial = parts[0]; + QString time = parts[1]; + + if (fileSerial == QString::fromStdString(serial)) { + playTime = time; + break; + } + } + } + + file.close(); + return playTime; +} diff --git a/src/qt_gui/game_list_frame.h b/src/qt_gui/game_list_frame.h index 957ac7318..6da2734a8 100644 --- a/src/qt_gui/game_list_frame.h +++ b/src/qt_gui/game_list_frame.h @@ -29,6 +29,7 @@ public Q_SLOTS: private: void SetTableItem(int row, int column, QString itemStr); void SetRegionFlag(int row, int column, QString itemStr); + QString GetPlayTime(const std::string& serial); QList m_columnActs; GameInfoClass* game_inf_get = nullptr; bool ListSortedAsc = true; @@ -68,6 +69,8 @@ public: case 6: return a.version < b.version; case 7: + return a.play_time < b.play_time; + case 8: return a.path < b.path; default: return false; @@ -89,9 +92,11 @@ public: case 6: return a.version > b.version; case 7: + return a.play_time > b.play_time; + case 8: return a.path > b.path; default: return false; } } -}; \ No newline at end of file +}; diff --git a/src/qt_gui/game_list_utils.h b/src/qt_gui/game_list_utils.h index f62275eff..3d710c5b7 100644 --- a/src/qt_gui/game_list_utils.h +++ b/src/qt_gui/game_list_utils.h @@ -19,6 +19,8 @@ struct GameInfo { std::string version = "Unknown"; std::string region = "Unknown"; std::string fw = "Unknown"; + + std::string play_time = "Unknown"; }; class GameListUtils { diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index f93bdb069..2323214e6 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -58,6 +58,7 @@ bool MainWindow::Init() { this->show(); // load game list LoadGameLists(); + // Check for update CheckUpdateMain(true); auto end = std::chrono::steady_clock::now(); diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index ad9cf5cef..9637c5fec 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -12,7 +12,7 @@ 0 0 854 - 570 + 605 @@ -71,7 +71,7 @@ - 1 + 0 diff --git a/src/qt_gui/translations/ar.ts b/src/qt_gui/translations/ar.ts index ca23620bb..ec03c04b5 100644 --- a/src/qt_gui/translations/ar.ts +++ b/src/qt_gui/translations/ar.ts @@ -1111,6 +1111,11 @@ Path مسار + + + Play Time + وقت اللعب + CheckUpdate diff --git a/src/qt_gui/translations/da_DK.ts b/src/qt_gui/translations/da_DK.ts index 0d81e2357..c7edfb102 100644 --- a/src/qt_gui/translations/da_DK.ts +++ b/src/qt_gui/translations/da_DK.ts @@ -1111,6 +1111,11 @@ Path Sti + + + Play Time + Spilletid + CheckUpdate diff --git a/src/qt_gui/translations/de.ts b/src/qt_gui/translations/de.ts index 9e31afd6e..43e19a37f 100644 --- a/src/qt_gui/translations/de.ts +++ b/src/qt_gui/translations/de.ts @@ -1111,6 +1111,11 @@ Path Pfad + + + Play Time + Spielzeit + CheckUpdate diff --git a/src/qt_gui/translations/el.ts b/src/qt_gui/translations/el.ts index de10fc3a8..8009dfd88 100644 --- a/src/qt_gui/translations/el.ts +++ b/src/qt_gui/translations/el.ts @@ -1111,6 +1111,11 @@ Path Διαδρομή + + + Play Time + Χρόνος παιχνιδιού + CheckUpdate diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 18c54428f..8ac683804 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -1146,6 +1146,11 @@ Path Path + + + Play Time + Play Time + CheckUpdate diff --git a/src/qt_gui/translations/es_ES.ts b/src/qt_gui/translations/es_ES.ts index 86a3e1adc..0c6591a5f 100644 --- a/src/qt_gui/translations/es_ES.ts +++ b/src/qt_gui/translations/es_ES.ts @@ -1111,6 +1111,11 @@ Path Ruta + + + Play Time + Tiempo de Juego + CheckUpdate diff --git a/src/qt_gui/translations/fa_IR.ts b/src/qt_gui/translations/fa_IR.ts index a613af70b..60d8be89e 100644 --- a/src/qt_gui/translations/fa_IR.ts +++ b/src/qt_gui/translations/fa_IR.ts @@ -1111,6 +1111,11 @@ Path مسیر + + + Play Time + زمان بازی + CheckUpdate diff --git a/src/qt_gui/translations/fi.ts b/src/qt_gui/translations/fi.ts index e4010b872..30c60af81 100644 --- a/src/qt_gui/translations/fi.ts +++ b/src/qt_gui/translations/fi.ts @@ -1111,6 +1111,11 @@ Path Polku + + + Play Time + Peliaika + CheckUpdate diff --git a/src/qt_gui/translations/fr.ts b/src/qt_gui/translations/fr.ts index b11b585c9..54e4b0e82 100644 --- a/src/qt_gui/translations/fr.ts +++ b/src/qt_gui/translations/fr.ts @@ -1111,6 +1111,11 @@ Path Répertoire + + + Play Time + Temps de jeu + CheckUpdate diff --git a/src/qt_gui/translations/hu_HU.ts b/src/qt_gui/translations/hu_HU.ts index 5986193c4..a6481d5a2 100644 --- a/src/qt_gui/translations/hu_HU.ts +++ b/src/qt_gui/translations/hu_HU.ts @@ -1111,6 +1111,11 @@ Path Útvonal + + + Play Time + Játékidő + CheckUpdate diff --git a/src/qt_gui/translations/id.ts b/src/qt_gui/translations/id.ts index 274029bd0..2fdc9b68c 100644 --- a/src/qt_gui/translations/id.ts +++ b/src/qt_gui/translations/id.ts @@ -1111,6 +1111,11 @@ Path Jalur + + + Play Time + Waktu Bermain + CheckUpdate diff --git a/src/qt_gui/translations/it.ts b/src/qt_gui/translations/it.ts index 07976865c..aba38a290 100644 --- a/src/qt_gui/translations/it.ts +++ b/src/qt_gui/translations/it.ts @@ -1111,6 +1111,11 @@ Path Percorso + + + Play Time + Tempo di Gioco + CheckUpdate diff --git a/src/qt_gui/translations/ja_JP.ts b/src/qt_gui/translations/ja_JP.ts index c3444906b..7524250f5 100644 --- a/src/qt_gui/translations/ja_JP.ts +++ b/src/qt_gui/translations/ja_JP.ts @@ -1111,6 +1111,11 @@ Path パス + + + Play Time + プレイ時間 + CheckUpdate diff --git a/src/qt_gui/translations/ko_KR.ts b/src/qt_gui/translations/ko_KR.ts index e816e2f4b..4805a4d0e 100644 --- a/src/qt_gui/translations/ko_KR.ts +++ b/src/qt_gui/translations/ko_KR.ts @@ -1111,6 +1111,11 @@ Path Path + + + Play Time + Play Time + CheckUpdate diff --git a/src/qt_gui/translations/lt_LT.ts b/src/qt_gui/translations/lt_LT.ts index d5b4ff3ad..beaaa116a 100644 --- a/src/qt_gui/translations/lt_LT.ts +++ b/src/qt_gui/translations/lt_LT.ts @@ -1111,6 +1111,11 @@ Path Kelias + + + Play Time + Žaidimo laikas + CheckUpdate diff --git a/src/qt_gui/translations/nb.ts b/src/qt_gui/translations/nb.ts index 334600950..c193e83dd 100644 --- a/src/qt_gui/translations/nb.ts +++ b/src/qt_gui/translations/nb.ts @@ -1111,6 +1111,11 @@ Path Sti + + + Play Time + Spilletid + CheckUpdate diff --git a/src/qt_gui/translations/nl.ts b/src/qt_gui/translations/nl.ts index 6e49d4640..6b0befa92 100644 --- a/src/qt_gui/translations/nl.ts +++ b/src/qt_gui/translations/nl.ts @@ -1111,6 +1111,11 @@ Path Pad + + + Play Time + Speeltijd + CheckUpdate diff --git a/src/qt_gui/translations/pl_PL.ts b/src/qt_gui/translations/pl_PL.ts index e95b8ba0c..ba8b4f9e4 100644 --- a/src/qt_gui/translations/pl_PL.ts +++ b/src/qt_gui/translations/pl_PL.ts @@ -1111,6 +1111,11 @@ Path Ścieżka + + + Play Time + Czas gry + CheckUpdate diff --git a/src/qt_gui/translations/pt_BR.ts b/src/qt_gui/translations/pt_BR.ts index e1570b2cd..2e859f12b 100644 --- a/src/qt_gui/translations/pt_BR.ts +++ b/src/qt_gui/translations/pt_BR.ts @@ -1111,6 +1111,11 @@ Path Diretório + + + Play Time + Horas Jogadas + CheckUpdate diff --git a/src/qt_gui/translations/ro_RO.ts b/src/qt_gui/translations/ro_RO.ts index e98b7e5c9..b36647c1c 100644 --- a/src/qt_gui/translations/ro_RO.ts +++ b/src/qt_gui/translations/ro_RO.ts @@ -1111,6 +1111,11 @@ Path Drum + + + Play Time + Timp de Joacă + CheckUpdate diff --git a/src/qt_gui/translations/ru_RU.ts b/src/qt_gui/translations/ru_RU.ts index aaff66ef9..224342f34 100644 --- a/src/qt_gui/translations/ru_RU.ts +++ b/src/qt_gui/translations/ru_RU.ts @@ -1111,6 +1111,11 @@ Path Путь + + + Play Time + Время Игры + CheckUpdate diff --git a/src/qt_gui/translations/sq.ts b/src/qt_gui/translations/sq.ts index dddc694a4..062226369 100644 --- a/src/qt_gui/translations/sq.ts +++ b/src/qt_gui/translations/sq.ts @@ -1111,6 +1111,11 @@ Path Shtegu + + + Play Time + Kohë Lojë + CheckUpdate diff --git a/src/qt_gui/translations/tr_TR.ts b/src/qt_gui/translations/tr_TR.ts index 5cd71af34..3e9173c7c 100644 --- a/src/qt_gui/translations/tr_TR.ts +++ b/src/qt_gui/translations/tr_TR.ts @@ -1111,6 +1111,11 @@ Path Yol + + + Play Time + Oynama Süresi + CheckUpdate diff --git a/src/qt_gui/translations/vi_VN.ts b/src/qt_gui/translations/vi_VN.ts index 523683621..af8d218a6 100644 --- a/src/qt_gui/translations/vi_VN.ts +++ b/src/qt_gui/translations/vi_VN.ts @@ -1111,6 +1111,11 @@ Path Đường dẫn + + + Play Time + Thời gian chơi + CheckUpdate diff --git a/src/qt_gui/translations/zh_CN.ts b/src/qt_gui/translations/zh_CN.ts index f2abc4f4b..5eef55641 100644 --- a/src/qt_gui/translations/zh_CN.ts +++ b/src/qt_gui/translations/zh_CN.ts @@ -1111,6 +1111,11 @@ Path 路径 + + + Play Time + 游戏时间 + CheckUpdate diff --git a/src/qt_gui/translations/zh_TW.ts b/src/qt_gui/translations/zh_TW.ts index 2d34f8d12..7e3585a07 100644 --- a/src/qt_gui/translations/zh_TW.ts +++ b/src/qt_gui/translations/zh_TW.ts @@ -1111,6 +1111,11 @@ Path 路徑 + + + Play Time + 遊玩時間 + CheckUpdate