]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - demoseeking.cfg
add options for seek speed factor and fast threshold
[xonotic/xonotic-data.pk3dir.git] / demoseeking.cfg
1 // Provides a seekdemo alias that allows fast-forwarding demo playback by a
2 // given time.
3 //
4 // Setup:
5 //
6 // Add "exec input-demoseeking.cfg" and the following cl_hook_gamestart_all
7 // hook to autoexec.cfg. If you already have a cl_hook_gamestart_all hook, add
8 // the quoted command to your hook, separated with a semicolon:
9 //
10 //     exec demoseeking.cfg
11 //     alias cl_hook_gamestart_all "demoseeking_game_started"
12 //
13 // Usage:
14 //     1. start a demo (ply/playdemo command or menu), and
15 //     2. while in a demo, use the "seekdemo <seconds>" command
16 //
17 // Alternatively, use input-demoseeking.cfg instead to restore the default
18 // bindings:
19 //
20 //     * use ,. (comma and dot) keys to seek -5/+5 seconds
21 //     * use m/ (m and slash) keys to seek -30/+30 seconds
22 //     * - (minus) also works instead of slash
23 //
24 // Options (persisted):
25 //
26 // _demoseeking_min_speed
27 //     Minimum seek speed. Default 1.5.
28 // _demoseeking_max_speed
29 //     Maximum seek speed. Default 200. Reduce this if the client freezes too
30 //     much while seeking. If the framerate is still high while seeking, you
31 //     may increase this, but increasing this with low framerate is unlikely to
32 //     improve seek performance.
33 // _demoseeking_speed_factor
34 //     Factor of remaining time to seek speed. Default 10.
35 //     The seek speed is defined by the formula
36 //
37 //       1.0 + [remaining seek seconds] * _demoseeking_speed_factor
38 //
39 //     bound by _demoseeking_min_speed and _demoseeking_max_speed.
40 // _demoseeking_fast_speed
41 //     Seek speed above which rendering is disabled. Default 80.
42 //
43 // Type demoseeking_reset_options in the console to reset all options.
44 //
45 // Variables:
46 //
47 // _demo_is_playing
48 //     Indicates whether a demo is currently playing. Set to 1 when playdemo
49 //     starts a demo.
50 //     Note: the setup above is needed to reset this reliably.
51 // _current_demo_name
52 //     The name of the latest played demo. Same as the argument passed to the
53 //     last playdemo command. If playdemo fails to start the demo (e.g. when
54 //     the file does not exist) this variable is not updated.
55 //     Note: the setup above is needed to reset this reliably.
56 // _demoseeking_is_seeking
57 //     1 while a seek is in progress, 0 otherwise.
58 //
59 // Extras:
60 //
61 // - The alias playdemo_hook is run when demo playback is started.
62 // - The alias seekdemo_hook_seek_end is run after a seek completed successfully.
63 // - The alias seekdemo_getseektime can be used by scripts to get the current
64 //   playback time or seek target time. See its usage below.
65
66 // state initialization
67 alias _demoseeking_init_vars "set _demoseeking_vars_loaded 1; set _demo_is_playing 0; set _current_demo_name \"\"; set _demoseeking_is_seeking 0; set _seekdemo_state idle; set _seekdemo_target 0; alias playdemo_hook \"\"; alias seekdemo_hook_seek_end"
68 alias _demoseeking_init_vars1 ""
69 _demoseeking_init_vars${_demoseeking_vars_loaded ?}
70
71 // option initialization (persistent)
72 alias demoseeking_reset_options "seta _demoseeking_options_loaded 1; seta _demoseeking_min_speed 1.5; seta _demoseeking_max_speed 200; seta _demoseeking_fast_speed 80; seta _demoseeking_speed_factor 10"
73 alias _demoseeking_init_options demoseeking_reset_options
74 alias _demoseeking_init_options1 ""
75 _demoseeking_init_options${_demoseeking_options_loaded ?}
76
77 // Hook into game start to reset seekdemo state. This prevents reloading the
78 // last demo when seekdemo is accidentally called during an actual game.
79 alias demoseeking_game_started "set _demo_is_playing 0; set _current_demo_name \"\""
80
81 // usage: seekdemo_getseektime <varname>
82 // Populates <varname> with the current seek target time, if seeking. If not
83 // seeking, populate it with the current playback time.
84 alias seekdemo_getseektime "_seekdemo_getseektime_get \"$1\" _seekdemo_getseektime_rpn_$_seekdemo_state"
85 alias _seekdemo_getseektime_get "cl_cmd rpn \"/$1\" ${$2} def"
86 set _seekdemo_getseektime_rpn_idle time
87 set _seekdemo_getseektime_rpn_starting _seekdemo_target
88 set _seekdemo_getseektime_rpn_seeking _seekdemo_target
89
90 // Hook into "playdemo" command. This alias runs immediately after the actual
91 // "playdemo" command runs. Needed for seekdemo to restart the demo when
92 // seeking backwards. Runs the playdemo_hook alias when a demo file is being
93 // loaded.
94 // ---
95 // "cl_cmd rpn" fails while a map is loading, leaving the value of
96 // _demoseeking_playdemo_success untouched, which means the playdemo command
97 // succeeded.
98 alias playdemo "set _demoseeking_playdemo_success 1; cl_cmd rpn /_demoseeking_playdemo_success 0 def; _demoseeking_playdemo_check \"$1\""
99 alias _demoseeking_playdemo_check "_demoseeking_playdemo_check_$_demoseeking_playdemo_success \"$1\""
100 alias _demoseeking_playdemo_check_0 "echo \"playdemo failed\""
101 alias _demoseeking_playdemo_check_1 "set _demo_is_playing 1; set _current_demo_name \"$1\"; playdemo_hook"
102
103 // Hook into the "defer" command to restore state when "defer clear" is run
104 // while seeking. "defer clear" seems to be run by some csprogs.
105 // ---
106 // compare the first argument. when it's "clear", run _demoseeking_restore
107 alias defer "alias _demoseeking_deftmp_$1 \"\"; alias _demoseeking_deftmp_clear _demoseeking_restore; _demoseeking_deftmp_$1; unalias _demoseeking_deftmp_$1"
108 alias _demoseeking_restore "_demoseeking_restore_$_seekdemo_state"
109 // idle - no seek, no state to restore
110 alias _demoseeking_restore_idle ""
111 // startseek - special state where this script calls defer clear before
112 // starting the seek loop
113 alias _demoseeking_restore_startseek ""
114 // starting - unexpected defer clear before seek started. Restore state by
115 // running check for forward/backward seek.
116 alias _demoseeking_restore_starting "_seekdemo_start_seek"
117 // seeking - unexpected defer clear while seeking. Restart the loop.
118 alias _demoseeking_restore_seeking "_seekdemo_check_time"
119
120 // usage: seekdemo <seconds>
121 // Seek the playing demo by the number of seconds. May be a floating point
122 // number. The seek is asynchronous. When a seek is already in action, the
123 // target time is adjusted by the specified amount.
124 // When starting a seek backwards, the demo is restarted before forwarding to
125 // the earlier time. Does nothing when no demo is playing (_demo_is_playing).
126 // ---
127 // check if seek should start or if target time should be adjusted instead
128 alias seekdemo "_seekdemo_checkstate_$_seekdemo_state ${* q}"
129 // before starting seek, verify demo is playing first
130 alias _seekdemo_checkstate_idle "set _seekdemo_demo_is_playing 0; cl_cmd rpn /_seekdemo_demo_is_playing _demo_is_playing 0 != def; _seekdemo_checkstart ${* q}"
131 // when already seeking, only update the variable holding the target time
132 alias _seekdemo_checkstate_starting "_seekdemo_checkstate_seeking ${* q}"
133 alias _seekdemo_checkstate_seeking "rpn /_seekdemo_target _seekdemo_target \"$1\" add def"
134
135 alias _seekdemo_checkstart "_seekdemo_checkstart_$_seekdemo_demo_is_playing ${* q}"
136 alias _seekdemo_checkstart_0 "echo \"no demo currently playing\""
137 // start new seek
138 alias _seekdemo_checkstart_1 "cl_cmd rpn /_seekdemo_target time \"$1\" add def; set _demoseeking_is_seeking 1; set _seekdemo_state starting; _seekdemo_save_options; _seekdemo_start_seek"
139
140 // check if seeking forwards or backwards
141 alias _seekdemo_start_seek "set _seekdemo_time_increasing err; cl_cmd rpn /_seekdemo_time_increasing _seekdemo_target time ge def; _seekdemo_check_increasing"
142 alias _seekdemo_check_increasing "_seekdemo_check_increasing_$_seekdemo_time_increasing"
143 // when seeking backwards, restart the demo and start the reload wait loop
144 alias _seekdemo_check_increasing_0 "playdemo \"$_current_demo_name\"; set _seekdemo_reload_success 1; cl_cmd rpn _seekdemo_reload_success 0 def; _seekdemo_check_reloading"
145 alias _seekdemo_check_increasing_1 "_seekdemo_check_time"
146 alias _seekdemo_check_increasing_err "_seekdemo_failed \"(demo not loaded?)\""
147 alias _seekdemo_check_reloading "_seekdemo_check_reloading_$_seekdemo_reload_success"
148 alias _seekdemo_check_reloading_0 "_seekdemo_failed (playdemo)"
149 // launch the "defer 10" command as a fallback to stop waiting in case demo reload fails
150 alias _seekdemo_check_reloading_1 "defer 10 \"_seekdemo_failed (reload)\"; _seekdemo_wait_reload"
151
152 // demo reload wait loop. "cl_cmd rpn" fails to execute until demo finished loading, leaving _demo_loaded 0
153 alias _seekdemo_wait_reload "set _demo_loaded 0; cl_cmd rpn /_demo_loaded 1 def; _seekdemo_check_loaded"
154 alias _seekdemo_check_loaded "_seekdemo_check_loaded_$_demo_loaded"
155 alias _seekdemo_check_loaded_0 "defer 0.02 _seekdemo_wait_reload"
156 // defer clear kills the fallback "defer 10" above
157 alias _seekdemo_check_loaded_1 "set _seekdemo_state startseek; defer clear; set _seekdemo_state seeking; _seekdemo_check_time"
158
159 // start of main seek loop, check if target time is reached
160 alias _seekdemo_check_time "set _seekdemo_seek_state failed; cl_cmd rpn _seekdemo_target time dup /_seekdemo_current_time exch def gt /_seekdemo_seek_state exch def; _seekdemo_check_continue"
161 alias _seekdemo_check_continue "_seekdemo_check_continue_$_seekdemo_seek_state"
162 alias _seekdemo_check_continue_0 "_seekdemo_leave_seek; seekdemo_hook_seek_end"
163 // Update options while seeking.
164 // - Adjust the playback speed by setting the slowmo cvar. The further the seek, the faster the playback speed.
165 // - Compare the speed to different speed levels to maximize performance for long seeks while reducing screen flashes for short ones.
166 // Then continue the loop with "defer 0", so the check is run on every rendered frame.
167 alias _seekdemo_check_continue_1 "set _seekdemo_speed_level failed; cl_cmd rpn _seekdemo_target time sub _demoseeking_speed_factor 0.01 max mul 1 add _demoseeking_min_speed max _demoseeking_max_speed min dup /slowmo exch def dup _demoseeking_fast_speed gt exch 2 gt add /_seekdemo_speed_level exch def; _seekdemo_set_options; defer 0 _seekdemo_check_time"
168 alias _seekdemo_check_continue_failed "_seekdemo_failed \"(demo ended?)\""
169
170 alias _seekdemo_failed "_seekdemo_leave_seek; echo SEEK FAILED ${1 ?}"
171
172 // Update options while and after seeking and for different levels of seek speed.
173 // - Disable r_render only at high seek speed to maximize performance, but keep
174 //   it enabled otherwise to avoid jarring black screens for short seeks.
175 // - snd_startnonloopingsounds disables all sounds that can safely be disabled,
176 //   avoiding lots of sounds playing at the same time.
177 // - Other disabled options prevent side effects from fast seeking at low
178 //   framerate, where particles and other effects accumulate and appear at the
179 //   same time when the target has been reached.
180 alias _seekdemo_leave_seek "_seekdemo_restore_options; set _demoseeking_is_seeking 0; set _seekdemo_state idle; r_render 1; snd_startnonloopingsounds 1; slowmo \"$_seekdemo_sav_slowmo\""
181 alias _seekdemo_set_options "_seekdemo_set_options_$_seekdemo_speed_level"
182 // speed level 0: below 2x playback speed, target almost reached, all options restored
183 alias _seekdemo_set_options_0 "r_render 1; snd_startnonloopingsounds 1; _seekdemo_restore_options"
184 // speed level 1: between 2x and 80x playback speed, sounds disabled, game rendered with reduced graphics
185 alias _seekdemo_set_options_1 "r_render 1; snd_startnonloopingsounds 0; _seekdemo_settemp_options"
186 // speed level 2: above 80x playback speed, sounds disabled, game not rendered to maximize performance
187 alias _seekdemo_set_options_2 "r_render 0; snd_startnonloopingsounds 0; _seekdemo_settemp_options"
188 // save/restore options for reduced settings
189 alias _seekdemo_save_options "set _seekdemo_sav_cl_decals \"$cl_decals\"; set _seekdemo_sav_cl_damagetext \"$cl_damagetext\"; set _seekdemo_sav_cl_particles \"$cl_particles\"; set _seekdemo_sav_cl_casings \"$cl_casings\"; set _seekdemo_sav_slowmo \"$slowmo\""
190 alias _seekdemo_settemp_options "settemp cl_decals 0; settemp cl_damagetext 0; settemp cl_particles 0; settemp cl_casings 0"
191 alias _seekdemo_restore_options "settemp cl_decals \"$_seekdemo_sav_cl_decals\"; settemp cl_damagetext \"$_seekdemo_sav_cl_damagetext\"; settemp cl_particles \"$_seekdemo_sav_cl_particles\"; settemp cl_casings \"$_seekdemo_sav_cl_casings\""