mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-08 17:13:57 -07:00
Buffer rewinds from backward skips in replays (#5141)
* split event processing to own method * implement rewind throttling * don't throttle backward skips from clicks * use the term 'buffering' instead * remove initial backup logic; just always buffer shortcut backward skips * prevent segfault * turns out you can just reuse the same one-shot timer * try scaling timeout based on event count * rewrite timeout calculation code * fix linker error
This commit is contained in:
parent
6652012f4c
commit
e43a21866c
2 changed files with 69 additions and 13 deletions
|
|
@ -10,6 +10,10 @@ ReplayTimelineWidget::ReplayTimelineWidget(QWidget *parent)
|
||||||
{
|
{
|
||||||
replayTimer = new QTimer(this);
|
replayTimer = new QTimer(this);
|
||||||
connect(replayTimer, SIGNAL(timeout()), this, SLOT(replayTimerTimeout()));
|
connect(replayTimer, SIGNAL(timeout()), this, SLOT(replayTimerTimeout()));
|
||||||
|
|
||||||
|
rewindBufferingTimer = new QTimer(this);
|
||||||
|
rewindBufferingTimer->setSingleShot(true);
|
||||||
|
connect(rewindBufferingTimer, &QTimer::timeout, this, &ReplayTimelineWidget::processRewind);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int ReplayTimelineWidget::binLength = 5000;
|
const int ReplayTimelineWidget::binLength = 5000;
|
||||||
|
|
@ -67,10 +71,11 @@ void ReplayTimelineWidget::mousePressEvent(QMouseEvent *event)
|
||||||
#else
|
#else
|
||||||
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->x() / width());
|
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->x() / width());
|
||||||
#endif
|
#endif
|
||||||
skipToTime(newTime);
|
// don't buffer rewinds from clicks, since clicks usually don't happen fast enough to require buffering
|
||||||
|
skipToTime(newTime, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayTimelineWidget::skipToTime(int newTime)
|
void ReplayTimelineWidget::skipToTime(int newTime, bool doRewindBuffering)
|
||||||
{
|
{
|
||||||
// check boundary conditions
|
// check boundary conditions
|
||||||
if (newTime < 0) {
|
if (newTime < 0) {
|
||||||
|
|
@ -81,16 +86,53 @@ void ReplayTimelineWidget::skipToTime(int newTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
newTime -= newTime % 200; // Time should always be a multiple of 200
|
newTime -= newTime % 200; // Time should always be a multiple of 200
|
||||||
if (newTime < currentTime) {
|
|
||||||
currentTime = 0;
|
const bool isBackwardsSkip = newTime < currentTime;
|
||||||
currentEvent = 0;
|
currentTime = newTime;
|
||||||
emit rewound();
|
|
||||||
|
if (isBackwardsSkip) {
|
||||||
|
handleBackwardsSkip(doRewindBuffering);
|
||||||
|
} else {
|
||||||
|
processNewEvents();
|
||||||
}
|
}
|
||||||
currentTime = newTime - 200; // 200 is added back in replayTimerTimeout
|
|
||||||
replayTimerTimeout();
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param doRewindBuffering When true, if multiple backward skips are made in quick succession, only a single rewind
|
||||||
|
/// is processed at the end. When false, the backwards skip will always cause an immediate rewind
|
||||||
|
void ReplayTimelineWidget::handleBackwardsSkip(bool doRewindBuffering)
|
||||||
|
{
|
||||||
|
if (doRewindBuffering) {
|
||||||
|
// We use a one-shot timer to implement the rewind buffering.
|
||||||
|
// The rewind only happens once the timer runs out.
|
||||||
|
// If another backwards skip happens, the timer will just get reset instead of rewinding.
|
||||||
|
rewindBufferingTimer->stop();
|
||||||
|
rewindBufferingTimer->start(calcRewindBufferingTimeout());
|
||||||
|
} else {
|
||||||
|
// otherwise, process the rewind immediately
|
||||||
|
processRewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The timeout scales based on the current event number, up to a limit
|
||||||
|
int ReplayTimelineWidget::calcRewindBufferingTimeout() const
|
||||||
|
{
|
||||||
|
int extraTime = currentEvent / 100;
|
||||||
|
return std::min(BASE_REWIND_BUFFERING_TIMEOUT_MS + extraTime, MAX_REWIND_BUFFERING_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplayTimelineWidget::processRewind()
|
||||||
|
{
|
||||||
|
// stop any queued-up rewinds
|
||||||
|
rewindBufferingTimer->stop();
|
||||||
|
|
||||||
|
// process the rewind
|
||||||
|
currentEvent = 0;
|
||||||
|
emit rewound();
|
||||||
|
processNewEvents();
|
||||||
|
}
|
||||||
|
|
||||||
QSize ReplayTimelineWidget::sizeHint() const
|
QSize ReplayTimelineWidget::sizeHint() const
|
||||||
{
|
{
|
||||||
return {-1, 50};
|
return {-1, 50};
|
||||||
|
|
@ -104,6 +146,16 @@ QSize ReplayTimelineWidget::minimumSizeHint() const
|
||||||
void ReplayTimelineWidget::replayTimerTimeout()
|
void ReplayTimelineWidget::replayTimerTimeout()
|
||||||
{
|
{
|
||||||
currentTime += 200;
|
currentTime += 200;
|
||||||
|
|
||||||
|
processNewEvents();
|
||||||
|
|
||||||
|
if (!(currentTime % 1000))
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Processes all unprocessed events up to the current time.
|
||||||
|
void ReplayTimelineWidget::processNewEvents()
|
||||||
|
{
|
||||||
while ((currentEvent < replayTimeline.size()) && (replayTimeline[currentEvent] < currentTime)) {
|
while ((currentEvent < replayTimeline.size()) && (replayTimeline[currentEvent] < currentTime)) {
|
||||||
emit processNextEvent();
|
emit processNextEvent();
|
||||||
++currentEvent;
|
++currentEvent;
|
||||||
|
|
@ -112,9 +164,6 @@ void ReplayTimelineWidget::replayTimerTimeout()
|
||||||
emit replayFinished();
|
emit replayFinished();
|
||||||
replayTimer->stop();
|
replayTimer->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(currentTime % 1000))
|
|
||||||
update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplayTimelineWidget::setTimeScaleFactor(qreal _timeScaleFactor)
|
void ReplayTimelineWidget::setTimeScaleFactor(qreal _timeScaleFactor)
|
||||||
|
|
@ -135,5 +184,5 @@ void ReplayTimelineWidget::stopReplay()
|
||||||
|
|
||||||
void ReplayTimelineWidget::skipByAmount(int amount)
|
void ReplayTimelineWidget::skipByAmount(int amount)
|
||||||
{
|
{
|
||||||
skipToTime(currentTime + amount);
|
skipToTime(currentTime + amount, true);
|
||||||
}
|
}
|
||||||
|
|
@ -18,6 +18,9 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTimer *replayTimer;
|
QTimer *replayTimer;
|
||||||
|
static constexpr int BASE_REWIND_BUFFERING_TIMEOUT_MS = 180;
|
||||||
|
static constexpr int MAX_REWIND_BUFFERING_TIMEOUT_MS = 280;
|
||||||
|
QTimer *rewindBufferingTimer;
|
||||||
QList<int> replayTimeline;
|
QList<int> replayTimeline;
|
||||||
QList<int> histogram;
|
QList<int> histogram;
|
||||||
static const int binLength;
|
static const int binLength;
|
||||||
|
|
@ -26,7 +29,11 @@ private:
|
||||||
int currentTime;
|
int currentTime;
|
||||||
int currentEvent;
|
int currentEvent;
|
||||||
|
|
||||||
void skipToTime(int newTime);
|
void skipToTime(int newTime, bool doRewindBuffering);
|
||||||
|
void handleBackwardsSkip(bool doRewindBuffering);
|
||||||
|
int calcRewindBufferingTimeout() const;
|
||||||
|
void processRewind();
|
||||||
|
void processNewEvents();
|
||||||
private slots:
|
private slots:
|
||||||
void replayTimerTimeout();
|
void replayTimerTimeout();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue