diff --git a/docs/cvars.md b/docs/cvars.md index 29afa209..ec455955 100644 --- a/docs/cvars.md +++ b/docs/cvars.md @@ -640,7 +640,7 @@ |sar_time_demo|cmd|sar_time_demo \ - parses a demo and prints some information about it| |sar_time_demo_dev|0|Printing mode when using sar_time_demo.
0 = Default,
1 = Console commands,
2 = Console commands & packets.| |sar_time_demos|cmd|sar_time_demos \ [demo_name2]... - parses multiple demos and prints the total sum of them| -|sar_timeline_show_completed|0|Only show speedrun starts and splits with matching finishes.| +|sar_timeline_show_completed|0|Only show speedrun starts and splits with matching finishes. Set to 2 to only show Personal Bests.| |sar_timeline_splits|1|Add split markers to the Steam Timeline.| |sar_timer_always_running|1|Timer will save current value when disconnecting.| |sar_timer_result|cmd|sar_timer_result - prints result of timer| diff --git a/src/Features/SteamTimeline.cpp b/src/Features/SteamTimeline.cpp index f5356f84..8be7fbcb 100644 --- a/src/Features/SteamTimeline.cpp +++ b/src/Features/SteamTimeline.cpp @@ -7,7 +7,7 @@ /* Timeline can get cluttered up (especially at long recording lengths), nice to have an option to disable adding splits. */ Variable sar_timeline_splits("sar_timeline_splits", "1", "Add split markers to the Steam Timeline.\n"); -Variable sar_timeline_show_completed("sar_timeline_show_completed", "0", "Only show speedrun starts and splits with matching finishes.\n"); +Variable sar_timeline_show_completed("sar_timeline_show_completed", "0", "Only show speedrun starts and splits with matching finishes. Set to 2 to only show Personal Bests.\n"); Timeline *timeline; @@ -17,6 +17,11 @@ Timeline::Timeline() { static std::chrono::time_point g_speedrunStart; static std::vector> g_pendingSplits; +static float g_pendingPbFinishOffset; +static std::string g_pendingPbFinishTime; +static std::chrono::time_point g_pendingPbSpeedrunStart; +static std::vector> g_pendingPbSplits; +static bool g_hasPendingPbRun = false; void Timeline::StartSpeedrun() { if (!steam->hasLoaded) return; @@ -57,6 +62,16 @@ ON_EVENT(SPEEDRUN_FINISH) { auto fl_time = SpeedrunTimer::GetTotalTicks() * engine->GetIPT(); auto time = SpeedrunTimer::Format(fl_time); + if (sar_timeline_show_completed.GetInt() >= 2) { + g_pendingPbFinishOffset = offset.count(); + g_pendingPbFinishTime = time; + g_pendingPbSpeedrunStart = g_speedrunStart; + g_pendingPbSplits = g_pendingSplits; + g_hasPendingPbRun = true; + g_pendingSplits.clear(); + return; + } + if (sar_timeline_show_completed.GetBool()) { steam->g_timeline->AddTimelineEvent("steam_timer", "Speedrun Start", "", 1, -offset.count(), 0.0f, k_ETimelineEventClipPriority_Standard); @@ -80,8 +95,38 @@ ON_EVENT(SPEEDRUN_FINISH) { ON_EVENT(MAYBE_AUTOSUBMIT) { if (!steam->hasLoaded) return; - if (!event.pb) + if (!event.pb) { + g_pendingPbSplits.clear(); + g_hasPendingPbRun = false; return; + } + + if (sar_timeline_show_completed.GetInt() >= 2 && g_hasPendingPbRun) { + std::chrono::duration offset = std::chrono::system_clock::now() - g_pendingPbSpeedrunStart; + float finishOffset = g_pendingPbFinishOffset - offset.count(); + + steam->g_timeline->AddTimelineEvent("steam_timer", "Speedrun Start", "", 1, -offset.count(), 0.0f, k_ETimelineEventClipPriority_Standard); + + for (const auto &[splitName, splitTime, splitOffset] : g_pendingPbSplits) { + steam->g_timeline->AddTimelineEvent( + "steam_bolt", + splitName.c_str(), + splitTime.c_str(), + 0, + splitOffset - offset.count(), + 0.0f, + k_ETimelineEventClipPriority_None); + } + g_pendingPbSplits.clear(); + + steam->g_timeline->SetTimelineStateDescription(("Speedrun " + g_pendingPbFinishTime).c_str(), -offset.count()); + steam->g_timeline->ClearTimelineStateDescription(finishOffset); + steam->g_timeline->AddTimelineEvent("steam_crown", "Personal Best", SpeedrunTimer::Format(event.score / 100.0f).c_str(), 2, finishOffset, 0.0f, k_ETimelineEventClipPriority_Featured); + g_hasPendingPbRun = false; + return; + } + g_pendingPbSplits.clear(); + g_hasPendingPbRun = false; steam->g_timeline->AddTimelineEvent("steam_crown", "Personal Best", SpeedrunTimer::Format(event.score / 100.0f).c_str(), 2, 0.0f, 0.0f, k_ETimelineEventClipPriority_Featured); }