mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-27 00:14:40 -07:00
[Replay] Implement option to skip empty sections (#7069)
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
* add settings * [Replay] Implement option to skip empty sections * correct starting offset
This commit is contained in:
parent
46bdb6df32
commit
c08dc780a7
8 changed files with 95 additions and 0 deletions
|
|
@ -3,9 +3,11 @@
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <libcockatrice/protocol/get_pb_extension.h>
|
||||||
#include <libcockatrice/settings/interface_settings.h>
|
#include <libcockatrice/settings/interface_settings.h>
|
||||||
|
|
||||||
static constexpr int TIMER_INTERVAL_MS = 200;
|
static constexpr int TIMER_INTERVAL_MS = 200;
|
||||||
|
static constexpr int EMPTY_SECTION_MARGIN_MS = 500;
|
||||||
|
|
||||||
static QList<int> createReplayTimeline(const GameReplay *replay)
|
static QList<int> createReplayTimeline(const GameReplay *replay)
|
||||||
{
|
{
|
||||||
|
|
@ -119,6 +121,10 @@ void ReplayManager::replayTimerTimeout()
|
||||||
processNewEvents(NORMAL_PLAYBACK);
|
processNewEvents(NORMAL_PLAYBACK);
|
||||||
|
|
||||||
timeChanged(currentVisualTime);
|
timeChanged(currentVisualTime);
|
||||||
|
|
||||||
|
if (skipEmptySections) {
|
||||||
|
handleSkipEmptySection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Processes all unprocessed events up to the current time. */
|
/** @brief Processes all unprocessed events up to the current time. */
|
||||||
|
|
@ -149,6 +155,51 @@ void ReplayManager::processNewEvents(PlaybackMode playbackMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasMeaningfulEvent(const GameEventContainer &cont)
|
||||||
|
{
|
||||||
|
const int eventListSize = cont.event_list_size();
|
||||||
|
for (int i = 0; i < eventListSize; ++i) {
|
||||||
|
const GameEvent &event = cont.event_list(i);
|
||||||
|
const auto eventType = static_cast<GameEvent::GameEventType>(getPbExtension(event));
|
||||||
|
|
||||||
|
if (eventType != GameEvent::PLAYER_PROPERTIES_CHANGED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayManager::handleSkipEmptySection()
|
||||||
|
{
|
||||||
|
if (currentEvent == replayTimeline.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find most recent meaningful event
|
||||||
|
int prevEvent = std::max(0, currentEvent - 1);
|
||||||
|
for (; prevEvent > 0 && !hasMeaningfulEvent(replay->event_list(prevEvent)); --prevEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int prevEventTime = replayTimeline.value(prevEvent);
|
||||||
|
if (currentVisualTime - prevEventTime <= EMPTY_SECTION_MARGIN_MS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find next earliest meaningful event
|
||||||
|
int nextEvent = currentEvent;
|
||||||
|
for (; nextEvent < replayTimeline.size() - 1 && !hasMeaningfulEvent(replay->event_list(nextEvent)); ++nextEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextEventTime = replayTimeline.value(nextEvent);
|
||||||
|
if (nextEventTime - currentVisualTime <= EMPTY_SECTION_MARGIN_MS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip forward if we're not within margin of either event
|
||||||
|
skipToTime(nextEventTime - EMPTY_SECTION_MARGIN_MS, false);
|
||||||
|
}
|
||||||
|
|
||||||
void ReplayManager::setTimeScaleFactor(qreal _timeScaleFactor)
|
void ReplayManager::setTimeScaleFactor(qreal _timeScaleFactor)
|
||||||
{
|
{
|
||||||
timeScaleFactor = _timeScaleFactor;
|
timeScaleFactor = _timeScaleFactor;
|
||||||
|
|
@ -156,6 +207,11 @@ void ReplayManager::setTimeScaleFactor(qreal _timeScaleFactor)
|
||||||
replayTimer->setInterval(interval);
|
replayTimer->setInterval(interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReplayManager::setSkipEmptySections(bool value)
|
||||||
|
{
|
||||||
|
skipEmptySections = value;
|
||||||
|
}
|
||||||
|
|
||||||
void ReplayManager::startReplay()
|
void ReplayManager::startReplay()
|
||||||
{
|
{
|
||||||
replayTimer->start();
|
replayTimer->start();
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class ReplayManager : public QObject
|
||||||
QTimer *rewindBufferingTimer;
|
QTimer *rewindBufferingTimer;
|
||||||
|
|
||||||
qreal timeScaleFactor = 1.0;
|
qreal timeScaleFactor = 1.0;
|
||||||
|
bool skipEmptySections = false;
|
||||||
|
|
||||||
int currentVisualTime = 0; ///< time currently displayed by the timeline
|
int currentVisualTime = 0; ///< time currently displayed by the timeline
|
||||||
int currentProcessedTime = 0; ///< time that events are currently processed up to. Could differ from visual time due
|
int currentProcessedTime = 0; ///< time that events are currently processed up to. Could differ from visual time due
|
||||||
|
|
@ -41,6 +42,7 @@ class ReplayManager : public QObject
|
||||||
void handleBackwardsSkip(bool doRewindBuffering);
|
void handleBackwardsSkip(bool doRewindBuffering);
|
||||||
void processRewind();
|
void processRewind();
|
||||||
void processNewEvents(PlaybackMode playbackMode);
|
void processNewEvents(PlaybackMode playbackMode);
|
||||||
|
void handleSkipEmptySection();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void replayTimerTimeout();
|
void replayTimerTimeout();
|
||||||
|
|
@ -63,6 +65,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTimeScaleFactor(qreal _timeScaleFactor);
|
void setTimeScaleFactor(qreal _timeScaleFactor);
|
||||||
|
void setSkipEmptySections(bool value);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void startReplay();
|
void startReplay();
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,17 @@ ReplayQuickSettingsWidget::ReplayQuickSettingsWidget(QWidget *parent) : Settings
|
||||||
connect(&fastForwardSpeedBox, qOverload<double>(&QDoubleSpinBox::valueChanged), this,
|
connect(&fastForwardSpeedBox, qOverload<double>(&QDoubleSpinBox::valueChanged), this,
|
||||||
&ReplayQuickSettingsWidget::actUpdateFastForwardSpeed);
|
&ReplayQuickSettingsWidget::actUpdateFastForwardSpeed);
|
||||||
|
|
||||||
|
skipEmptyCheckBox.setChecked(SettingsCache::instance().userInterface().getSkipEmptySections());
|
||||||
|
connect(&skipEmptyCheckBox, &QCheckBox::QT_STATE_CHANGED, this,
|
||||||
|
&ReplayQuickSettingsWidget::actUpdateSkipEmptySections);
|
||||||
|
|
||||||
// putting it all together
|
// putting it all together
|
||||||
auto *widget = new QWidget;
|
auto *widget = new QWidget;
|
||||||
auto *grid = new QGridLayout(widget);
|
auto *grid = new QGridLayout(widget);
|
||||||
grid->setContentsMargins(0, 0, 0, 0);
|
grid->setContentsMargins(0, 0, 0, 0);
|
||||||
grid->addWidget(&fastForwardSpeedLabel, 0, 0, 1, 1);
|
grid->addWidget(&fastForwardSpeedLabel, 0, 0, 1, 1);
|
||||||
grid->addWidget(&fastForwardSpeedBox, 0, 1, 1, 1);
|
grid->addWidget(&fastForwardSpeedBox, 0, 1, 1, 1);
|
||||||
|
grid->addWidget(&skipEmptyCheckBox, 1, 0, 1, 2);
|
||||||
|
|
||||||
this->addSettingsWidget(widget);
|
this->addSettingsWidget(widget);
|
||||||
|
|
||||||
|
|
@ -36,6 +41,8 @@ void ReplayQuickSettingsWidget::retranslateUi()
|
||||||
{
|
{
|
||||||
fastForwardSpeedLabel.setText(tr("Fast forward speed:"));
|
fastForwardSpeedLabel.setText(tr("Fast forward speed:"));
|
||||||
fastForwardSpeedBox.setSuffix("x");
|
fastForwardSpeedBox.setSuffix("x");
|
||||||
|
|
||||||
|
skipEmptyCheckBox.setText(tr("Skip empty sections"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayQuickSettingsWidget::actUpdateFastForwardSpeed(qreal value)
|
void ReplayQuickSettingsWidget::actUpdateFastForwardSpeed(qreal value)
|
||||||
|
|
@ -43,3 +50,9 @@ void ReplayQuickSettingsWidget::actUpdateFastForwardSpeed(qreal value)
|
||||||
SettingsCache::instance().userInterface().setFastForwardSpeed(value);
|
SettingsCache::instance().userInterface().setFastForwardSpeed(value);
|
||||||
emit fastForwardSpeedChanged(value);
|
emit fastForwardSpeedChanged(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReplayQuickSettingsWidget::actUpdateSkipEmptySections(QT_STATE_CHANGED_T value)
|
||||||
|
{
|
||||||
|
SettingsCache::instance().userInterface().setSkipEmptySections(value);
|
||||||
|
emit skipEmptySectionsChanged(value);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@
|
||||||
|
|
||||||
#include "../../interface/widgets/quick_settings/settings_button_widget.h"
|
#include "../../interface/widgets/quick_settings/settings_button_widget.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QDoubleSpinBox>
|
#include <QDoubleSpinBox>
|
||||||
|
#include <libcockatrice/utility/macros.h>
|
||||||
|
|
||||||
class ReplayQuickSettingsWidget : public SettingsButtonWidget
|
class ReplayQuickSettingsWidget : public SettingsButtonWidget
|
||||||
{
|
{
|
||||||
|
|
@ -16,13 +18,17 @@ public:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void fastForwardSpeedChanged(qreal speed);
|
void fastForwardSpeedChanged(qreal speed);
|
||||||
|
void skipEmptySectionsChanged(bool skip);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel fastForwardSpeedLabel;
|
QLabel fastForwardSpeedLabel;
|
||||||
QDoubleSpinBox fastForwardSpeedBox;
|
QDoubleSpinBox fastForwardSpeedBox;
|
||||||
|
|
||||||
|
QCheckBox skipEmptyCheckBox;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void actUpdateFastForwardSpeed(qreal value);
|
void actUpdateFastForwardSpeed(qreal value);
|
||||||
|
void actUpdateSkipEmptySections(QT_STATE_CHANGED_T value);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_REPLAY_QUICK_SETTINGS_WIDGET_H
|
#endif // COCKATRICE_REPLAY_QUICK_SETTINGS_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,10 @@ ReplayWidget::ReplayWidget(QWidget *parent, GameReplay *replay)
|
||||||
settingsWidget->setFixedSize(QSize(32, 32));
|
settingsWidget->setFixedSize(QSize(32, 32));
|
||||||
connect(settingsWidget, &ReplayQuickSettingsWidget::fastForwardSpeedChanged, this,
|
connect(settingsWidget, &ReplayQuickSettingsWidget::fastForwardSpeedChanged, this,
|
||||||
[this] { updateTimeScaleFactor(replayFastForwardButton->isChecked()); });
|
[this] { updateTimeScaleFactor(replayFastForwardButton->isChecked()); });
|
||||||
|
connect(settingsWidget, &ReplayQuickSettingsWidget::skipEmptySectionsChanged, replayManager,
|
||||||
|
&ReplayManager::setSkipEmptySections);
|
||||||
|
|
||||||
|
replayManager->setSkipEmptySections(SettingsCache::instance().userInterface().getSkipEmptySections());
|
||||||
|
|
||||||
// putting everything together
|
// putting everything together
|
||||||
auto replayControlLayout = new QHBoxLayout;
|
auto replayControlLayout = new QHBoxLayout;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ public:
|
||||||
[[nodiscard]] virtual int getMinPlayersForMultiColumnLayout() const = 0;
|
[[nodiscard]] virtual int getMinPlayersForMultiColumnLayout() const = 0;
|
||||||
[[nodiscard]] virtual int getRewindBufferingMs() const = 0;
|
[[nodiscard]] virtual int getRewindBufferingMs() const = 0;
|
||||||
[[nodiscard]] virtual qreal getFastForwardSpeed() const = 0;
|
[[nodiscard]] virtual qreal getFastForwardSpeed() const = 0;
|
||||||
|
[[nodiscard]] virtual bool getSkipEmptySections() const = 0;
|
||||||
[[nodiscard]] virtual bool getLeftJustified() const = 0;
|
[[nodiscard]] virtual bool getLeftJustified() const = 0;
|
||||||
[[nodiscard]] virtual int getZoneViewGroupByIndex() const = 0;
|
[[nodiscard]] virtual int getZoneViewGroupByIndex() const = 0;
|
||||||
[[nodiscard]] virtual int getZoneViewSortByIndex() const = 0;
|
[[nodiscard]] virtual int getZoneViewSortByIndex() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,11 @@ qreal InterfaceSettings::getFastForwardSpeed() const
|
||||||
return getValue("fastForwardSpeed", "replay", QString(), 10).toReal();
|
return getValue("fastForwardSpeed", "replay", QString(), 10).toReal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InterfaceSettings::getSkipEmptySections() const
|
||||||
|
{
|
||||||
|
return getValue("skipEmptySections", "replay", QString(), false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
bool InterfaceSettings::getLeftJustified() const
|
bool InterfaceSettings::getLeftJustified() const
|
||||||
{
|
{
|
||||||
return getValue("leftJustified", QString(), QString(), false).toBool();
|
return getValue("leftJustified", QString(), QString(), false).toBool();
|
||||||
|
|
@ -279,6 +284,11 @@ void InterfaceSettings::setFastForwardSpeed(qreal _value)
|
||||||
setValue(_value, "fastForwardSpeed", "replay");
|
setValue(_value, "fastForwardSpeed", "replay");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InterfaceSettings::setSkipEmptySections(bool _value)
|
||||||
|
{
|
||||||
|
setValue(_value, "skipEmptySections", "replay");
|
||||||
|
}
|
||||||
|
|
||||||
void InterfaceSettings::setLeftJustified(bool _leftJustified)
|
void InterfaceSettings::setLeftJustified(bool _leftJustified)
|
||||||
{
|
{
|
||||||
setValue(_leftJustified, "leftJustified");
|
setValue(_leftJustified, "leftJustified");
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ public:
|
||||||
[[nodiscard]] int getMinPlayersForMultiColumnLayout() const override;
|
[[nodiscard]] int getMinPlayersForMultiColumnLayout() const override;
|
||||||
[[nodiscard]] int getRewindBufferingMs() const override;
|
[[nodiscard]] int getRewindBufferingMs() const override;
|
||||||
[[nodiscard]] qreal getFastForwardSpeed() const override;
|
[[nodiscard]] qreal getFastForwardSpeed() const override;
|
||||||
|
[[nodiscard]] bool getSkipEmptySections() const override;
|
||||||
[[nodiscard]] bool getLeftJustified() const override;
|
[[nodiscard]] bool getLeftJustified() const override;
|
||||||
[[nodiscard]] int getZoneViewGroupByIndex() const override;
|
[[nodiscard]] int getZoneViewGroupByIndex() const override;
|
||||||
[[nodiscard]] int getZoneViewSortByIndex() const override;
|
[[nodiscard]] int getZoneViewSortByIndex() const override;
|
||||||
|
|
@ -65,6 +66,7 @@ public:
|
||||||
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
|
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);
|
||||||
void setRewindBufferingMs(int _rewindBufferingMs);
|
void setRewindBufferingMs(int _rewindBufferingMs);
|
||||||
void setFastForwardSpeed(qreal _value);
|
void setFastForwardSpeed(qreal _value);
|
||||||
|
void setSkipEmptySections(bool _value);
|
||||||
void setLeftJustified(bool _leftJustified);
|
void setLeftJustified(bool _leftJustified);
|
||||||
void setZoneViewGroupByIndex(int _zoneViewGroupByIndex);
|
void setZoneViewGroupByIndex(int _zoneViewGroupByIndex);
|
||||||
void setZoneViewSortByIndex(int _zoneViewSortByIndex);
|
void setZoneViewSortByIndex(int _zoneViewSortByIndex);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue