diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index b3242bcef..d9612fce8 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1055,7 +1055,7 @@ void GMainWindow::BootGame(const QString& filename) { game_list->hide(); game_list_placeholder->hide(); } - status_bar_update_timer.start(2000); + status_bar_update_timer.start(1000); if (UISettings::values.hide_mouse) { mouse_hide_timer.start(); @@ -1165,6 +1165,7 @@ void GMainWindow::ShutdownGame() { // Disable status bar updates status_bar_update_timer.stop(); message_label->setVisible(false); + message_label_used_for_movie = false; emu_speed_label->setVisible(false); game_fps_label->setVisible(false); emu_frametime_label->setVisible(false); @@ -1982,6 +1983,23 @@ void GMainWindow::UpdateStatusBar() { return; } + // Update movie status + const u64 current = Core::Movie::GetInstance().GetCurrentInputIndex(); + const u64 total = Core::Movie::GetInstance().GetTotalInputCount(); + if (Core::Movie::GetInstance().IsRecordingInput()) { + message_label->setText(tr("Recording %1").arg(current)); + message_label->setVisible(true); + message_label_used_for_movie = true; + } else if (Core::Movie::GetInstance().IsPlayingInput()) { + message_label->setText(tr("Playing %1 / %2").arg(current).arg(total)); + message_label->setVisible(true); + message_label_used_for_movie = true; + } else if (message_label_used_for_movie) { // Clear the label if movie was just closed + message_label->setText(QString{}); + message_label->setVisible(false); + message_label_used_for_movie = false; + } + auto results = Core::System::GetInstance().GetAndResetPerfStats(); if (Settings::values.use_frame_limit_alternate) { @@ -2093,6 +2111,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det emu_thread->SetRunning(true); message_label->setText(status_message); message_label->setVisible(true); + message_label_used_for_movie = false; } } } diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index eff5ea7b5..99451d308 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -248,6 +248,7 @@ private: QLabel* game_fps_label = nullptr; QLabel* emu_frametime_label = nullptr; QTimer status_bar_update_timer; + bool message_label_used_for_movie = false; MultiplayerState* multiplayer_state = nullptr; std::unique_ptr config; diff --git a/src/core/movie.cpp b/src/core/movie.cpp index 51746e744..1e27b45f2 100644 --- a/src/core/movie.cpp +++ b/src/core/movie.cpp @@ -129,6 +129,22 @@ struct CTMHeader { static_assert(sizeof(CTMHeader) == 256, "CTMHeader should be 256 bytes"); #pragma pack(pop) +static u64 GetInputCount(const std::vector& input) { + u64 input_count = 0; + for (std::size_t pos = 0; pos < input.size(); pos += sizeof(ControllerState)) { + if (input.size() < pos + sizeof(ControllerState)) { + break; + } + + ControllerState state; + std::memcpy(&state, input.data() + pos, sizeof(ControllerState)); + if (state.type == ControllerStateType::PadAndCircle) { + input_count++; + } + } + return input_count; +} + template void Movie::serialize(Archive& ar, const unsigned int file_version) { // Only serialize what's needed to make savestates useful for TAS: @@ -136,6 +152,10 @@ void Movie::serialize(Archive& ar, const unsigned int file_version) { ar& _current_byte; current_byte = static_cast(_current_byte); + if (file_version > 0) { + ar& current_input; + } + std::vector recorded_input_ = recorded_input; ar& recorded_input_; @@ -167,6 +187,7 @@ void Movie::serialize(Archive& ar, const unsigned int file_version) { "This savestate was created at a later point and must be loaded in R+W mode"); } play_mode = PlayMode::Playing; + total_input = GetInputCount(recorded_input); } else { recorded_input = std::move(recorded_input_); play_mode = PlayMode::Recording; @@ -184,6 +205,13 @@ bool Movie::IsRecordingInput() const { return play_mode == PlayMode::Recording; } +u64 Movie::GetCurrentInputIndex() const { + return current_input; +} +u64 Movie::GetTotalInputCount() const { + return total_input; +} + void Movie::CheckInputEnd() { if (current_byte + sizeof(ControllerState) > recorded_input.size()) { LOG_INFO(Movie, "Playback finished"); @@ -198,6 +226,7 @@ void Movie::Play(Service::HID::PadState& pad_state, s16& circle_pad_x, s16& circ ControllerState s; std::memcpy(&s, &recorded_input[current_byte], sizeof(ControllerState)); current_byte += sizeof(ControllerState); + current_input++; if (s.type != ControllerStateType::PadAndCircle) { LOG_ERROR(Movie, @@ -325,6 +354,8 @@ void Movie::Record(const ControllerState& controller_state) { void Movie::Record(const Service::HID::PadState& pad_state, const s16& circle_pad_x, const s16& circle_pad_y) { + current_input++; + ControllerState s; s.type = ControllerStateType::PadAndCircle; @@ -429,22 +460,6 @@ Movie::ValidationResult Movie::ValidateHeader(const CTMHeader& header) const { return ValidationResult::OK; } -static u64 GetInputCount(const std::vector& input) { - u64 input_count = 0; - for (std::size_t pos = 0; pos < input.size(); pos += sizeof(ControllerState)) { - if (input.size() < pos + sizeof(ControllerState)) { - break; - } - - ControllerState state; - std::memcpy(&state, input.data() + pos, sizeof(ControllerState)); - if (state.type == ControllerStateType::PadAndCircle) { - input_count++; - } - } - return input_count; -} - Movie::ValidationResult Movie::ValidateInput(const std::vector& input, u64 expected_count) const { return GetInputCount(input) == expected_count ? ValidationResult::OK @@ -507,11 +522,13 @@ void Movie::StartPlayback(const std::string& movie_file) { record_movie_author = author.data(); rerecord_count = header.rerecord_count; + total_input = header.input_count; recorded_input.resize(size - sizeof(CTMHeader)); save_record.ReadArray(recorded_input.data(), recorded_input.size()); current_byte = 0; + current_input = 0; id = header.id; LOG_INFO(Movie, "Loaded Movie, ID: {:016X}", id); @@ -622,6 +639,7 @@ void Movie::Shutdown() { recorded_input.resize(0); record_movie_file.clear(); current_byte = 0; + current_input = 0; init_time = 0; id = 0; } diff --git a/src/core/movie.h b/src/core/movie.h index dcbe8129b..e62dfe5c2 100644 --- a/src/core/movie.h +++ b/src/core/movie.h @@ -123,6 +123,9 @@ public: bool IsPlayingInput() const; bool IsRecordingInput() const; + u64 GetCurrentInputIndex() const; + u64 GetTotalInputCount() const; + private: static Movie s_instance; @@ -159,6 +162,9 @@ private: std::vector recorded_input; std::size_t current_byte = 0; + u64 current_input = 0; + // Total input count of the current movie being played. Not used for recording. + u64 total_input = 0; u64 id = 0; // ID of the current movie loaded u64 init_time;