diff --git a/docs/cvars.md b/docs/cvars.md index ba91db5a..ddb8bce6 100644 --- a/docs/cvars.md +++ b/docs/cvars.md @@ -692,6 +692,9 @@ |sar_trace_record|0|Record the trace to a slot. Set to 0 for not recording| |sar_trace_reveal|0|Only draw traces until the specified tick. Set to bbox to draw until the bbox tick.| |sar_trace_show|cmd|sar_trace_show [trace name] - show the trace with the given name| +|sar_trace_sync|cmd|sar_trace_sync - syncs all the hovered traces to the fastest trace.| +|sar_trace_sync_reset|cmd|sar_trace_sync_reset \ - resets the sync of the player trace by the given name.| +|sar_trace_sync_reset_all|cmd|sar_trace_sync_reset_all - resets the sync of all the player traces.| |sar_trace_teleport_at|cmd|sar_trace_teleport_at \ [player slot] [trace name] - teleports the player at the given trace tick on the given trace ID (defaults to hovered one or the first one ever made) in the given slot (defaults to 0).| |sar_trace_teleport_eye|cmd|sar_trace_teleport_eye \ [player slot] [trace name] - teleports the player to the eye position at the given trace tick on the given trace (defaults to hovered one or the first one ever made) in the given slot (defaults to 0).| |sar_trace_use_shot_eyeoffset|1|Uses eye offset and angles accurate for portal shooting.| diff --git a/src/Features/PlayerTrace.cpp b/src/Features/PlayerTrace.cpp index a1e10821..7deb1aa6 100644 --- a/src/Features/PlayerTrace.cpp +++ b/src/Features/PlayerTrace.cpp @@ -16,6 +16,7 @@ #include "Modules/Surface.hpp" #include +#include PlayerTrace *playerTrace; @@ -60,11 +61,11 @@ static int tickInternalToUser(int tick, const Trace &trace) { if (tick == -1) return -1; switch (sar_trace_draw_time.GetInt()) { case 2: - return tick + trace.startSessionTick; + return tick + trace.startSessionTick + trace.tasTickOffset; case 3: - if (trace.startTasTick > 0) return tick + trace.startTasTick; + if (trace.startTasTick > 0) return tick + trace.startTasTick + trace.tasTickOffset; default: // FALLTHROUGH - return tick; + return tick + trace.tasTickOffset; } } @@ -72,11 +73,11 @@ static int tickUserToInternal(int tick, const Trace &trace) { if (tick == -1) return -1; switch (sar_trace_draw_time.GetInt()) { case 2: - return tick - trace.startSessionTick; + return tick - trace.startSessionTick - trace.tasTickOffset; case 3: - if (trace.startTasTick > 0) return tick - trace.startTasTick; + if (trace.startTasTick > 0) return tick - trace.startTasTick - trace.tasTickOffset; default: // FALLTHROUGH - return tick; + return tick - trace.tasTickOffset; } } @@ -136,6 +137,12 @@ void PlayerTrace::AddPoint(std::string trace_name, void *player, int slot, bool if (traces.count(trace_name) == 0) { traces[trace_name] = Trace(); traces[trace_name].startSessionTick = session->GetTick(); + + auto it = playerTrace->tickOffsets.find(trace_name); + + if (it != playerTrace->tickOffsets.end()) { + traces[trace_name].tasTickOffset = it->second; + } } Trace &trace = traces[trace_name]; @@ -889,6 +896,20 @@ int PlayerTrace::GetTasTraceTick() { return max_tas_tick; } +void PlayerTrace::SetTickOffset(std::string &trace_name, int offset) { + playerTrace->tickOffsets[trace_name] = offset; +} + +void PlayerTrace::ResetAllTraceOffsets() { + for (auto it = playerTrace->traces.begin(); it != playerTrace->traces.end(); ++it) { + Trace &trace = it->second; + + trace.tasTickOffset = 0; + } + + playerTrace->tickOffsets.clear(); +} + HUD_ELEMENT2(trace, "0", "Draws info about current trace bbox tick.\n", HudType_InGame | HudType_Paused) { if (!sv_cheats.GetBool()) return; playerTrace->DrawTraceHud(ctx); @@ -1239,6 +1260,40 @@ CON_COMMAND(sar_trace_compare, "sar_trace_compare - compares } } +CON_COMMAND(sar_trace_sync, "sar_trace_sync - syncs all the hovered traces to the fastest trace.\n") { + size_t min_tick = SIZE_MAX; + + for (auto &h : hovers) { + min_tick = std::min(min_tick, h.tick); + } + + for (auto &h : hovers) { + auto trace = playerTrace->GetTrace(h.trace_name); + + auto offset = min_tick - h.tick; + + trace->tasTickOffset = offset; + + playerTrace->SetTickOffset(h.trace_name, offset); + } +} + +CON_COMMAND(sar_trace_sync_reset_all, "sar_trace_sync_reset_all - resets the sync of all the player traces.\n") { + playerTrace->ResetAllTraceOffsets(); +} + +CON_COMMAND(sar_trace_sync_reset, "sar_trace_sync_reset - resets the sync of the player trace by the given name.\n") { + if (args.ArgC() < 2) { + return console->Print(sar_trace_sync_reset.ThisPtr()->m_pszHelpString); + } + + std::string trace_name = args[1]; + + playerTrace->GetTrace(trace_name)->tasTickOffset = 0; + + playerTrace->SetTickOffset(trace_name, 0); +} + void PlayerTrace::EnterLogScope(const char *name) { if (!playerTrace->ShouldRecord()) return; auto trace = this->GetTrace(sar_trace_record.GetString()); diff --git a/src/Features/PlayerTrace.hpp b/src/Features/PlayerTrace.hpp index 71ab5e35..67cf21bc 100644 --- a/src/Features/PlayerTrace.hpp +++ b/src/Features/PlayerTrace.hpp @@ -48,6 +48,7 @@ struct PortalLocations { struct Trace { int startSessionTick; int startTasTick; + int tasTickOffset = 0; std::vector positions[2]; std::vector eyepos[2]; std::vector angles[2]; @@ -69,6 +70,8 @@ class PlayerTrace : public Feature { private: // In order to arbitrarily number traces std::map traces; + // Universal map for trace tick offsets to be able to preserve them between trace recordings + std::unordered_map tickOffsets; std::string lastRecordedTrace; public: PlayerTrace(); @@ -114,6 +117,10 @@ class PlayerTrace : public Feature { void CheckTraceChanged(); // Get the current trace bbox tick for TAS stuff, or -1 if there isn't one int GetTasTraceTick(); + // Set tick offset globally + void SetTickOffset(std::string &trace_name, int offset); + // Reset all offsets + void ResetAllTraceOffsets(); // Returns an identifier for the scope which should be passed to ExitLogScope void EnterLogScope(const char *name);