Segmented speedruns in source utilize SPT.
While creating a segmented run does not require it, it is very highly reccomended, and this guide will assume you are using SPT.
It will make the whole process significantly easier.
Follow the installation instructions in the readme, and load SPT into the game by using plugin_load spt
(or plugin_load spt-2013
, plugin_load spt-oe
, plugin_load spt-bms
).
Each runner in a segmented run has their own "segmenting cfg".
This is a config file which contains segmenting binds, aliases, scripts, and the run configuration.
Go into Game/game/cfg
(ex. Half-Life 2/hl2/cfg), and create seg.cfg. Open it in a text editor.
CFG files store commands which will be executed line by line when the config is executed in-game.
Let's start with the basics. These should be in every segmenting config, always:
spt_pause 1 // SPT command to Auto-Pause as early as possible when loading, should ALWAYS be used unless it's necessary to turn it off. Makes segments have less broken frames when rendering (we'll get to this)
spt_autojump 1 // SPT command for perfect autojumping. 100% accurate, unlike external scripts.
spt_disable_fade 1 // Disables fullscreen fades that make the player blind
// Do note that some SPT commands (autojump, disable fade) are not supported in every game.
cl_showpos 1 // Shows player coordinates
cl_showfps 1 // Shows player FPS
save_screenshot 0 // Disables saving screenshots when saving. Saves your SSD from dying, and eliminates possible stutter. Doesn't work in Old Engine.
snd_musicvolume 0 // Disables music
m_rawinput 1 // Enables Raw Input for higher mouse precision. Only Source 2013 games support this.
r_portalsopenall 1 // Improves visibility
sv_autosave 0 // Disables autosaving to prevent accidental invalid segments
spt_afterframes_reset_on_server_activate 1 // Resets spt_afterframes when loading a save. Prevents illegitimate segments when using spt_afterframes.
Demo playback is incredibly buggy by default in most games, but it can be fixed depending on the game.
demo_interplimit 999999999999999
demo_legacy_rollback 0
demo_interpolateview 1
cl_interp 0.015
demo_interplimit 999999999999999
demo_legacy_rollback 1
demo_interpolateview 1
cl_interp 0.015
cl_interp -1
cl_interp_npcs 0.1
// Sometimes the commands above do not work.
// If that's the case, use demo_interpolateview 0.
// It will cause frameskips, but the view will be non-jittery.
The runners should use some consistent game settings in a run and always have these in their CFG, to make sure no issues occur:
fov_desired 90 // Run FOV. It's possible to override when playing back a demo, but it causes some annoying issues. Doesn't work in Old Engine.
skill 1 // Run difficulty. Should stay constant. (2 - Normal, 3 - Hard)
closecaption 0;cc_subtitles 0 // Subtitles. Playing a demo with subitles when they're disabled crashes a game and vice versa. Needs to be constant.
There are some aliases which we will be using later on in this guide, these will aid you in your segmenting:
alias nade "attack1;_y_spt_afterticks 266 s4v3" // Voidclip granade redirect
alias attack2 "+attack2;wait 10; -attack2" // Doesn't work in Old Engine
alias attack1 "+attack;wait 10; -attack" // Doesn't work in Old Engine
alias pressuse "us3;echo use;wait 10;-use" // Doesn't work in Old Engine
alias re "-attack;-attack2;-attack3;-back;-duck;-forward;-jump;-left;-moveleft;-moveright;-moveup;-movedown;-reload;-right;-use;-speed" // Resetting inputs
alias jump "+jump" // Trust me this makes sense
// Jump scripts, ONLY FOR HL2 New Engine
alias +fronthop "-forward; +back; -speed; +walk; +jump; wait 5; -back";
alias -fronthop "-jump; -walk";
alias +backhop "-back;-speed;+walk;+jump";
alias -backhop "-jump;-walk";
alias +jumpy "+walk;+jump";
alias +strafehop "-forward; -speed; +walk; +strafe; +jump; wait 5; -strafe";
alias -strafehop "-jump; -walk";
alias -jumpy "-jump;-walk";
After all of that we can finally get to the Segmenting Aliases
These will let you start and finish segments.
alias l04d "wait 10;exec seg;stop;re;wait 10;load PREVIOUS_SEGMENT.sav;sensitivity 0;wait 10;record CURRENT_SEGMENT";
alias s4v3 "save CURRENT_SEGMENT;echo #SAVE#;sensitivity 0;wait 100;stop"
bind mouse3 l04d // Reset a segment, start recording
bind mouse4 "sensitivity 2;unpause" // Unpause after loading a segment
bind mouse5 s4v3 // Save a segment
It is best to not touch the parts of these aliases that you do not understand.
Let's break down l04d first. It is the alias that loads the save from the previous segment, and starts recording the next one.
the initial wait 10;exec seg;stop
simply makes sure that everything executes correctly, and then executes the segmenting config to update all settings, in case they were changed. Then it stops recording a demo if it was already being recorded, to make sure that the one you're about to start recording starts correctly.
re;wait 10
is an alias from earlier. It ensures that none of your inputs get stuck.
load 000-YOURNAME-000.sav;sensitivity 0;wait 10;record 001-YOURNAME
Loads the save from the previous segment, sets the sensitivity to 0 to make sure that you don't move your mouse during the loading screen (which would lead to jitter in the final result), then after roughly 10 frames it starts recording the next segment.
recording a demo HAS to be done this way to ensure that the demo recording start while the game is still loading.
Starting the demo recording after it had already finished loading will result in the demo being 2 ticks shorter than it is in reality, and any method that starts demos like this should not be used.
s4v3 Saves the demo which is currently being recorded.
It does so in a special way which makes rendering the speedrun into a video easier.
save 001-YOURNAME;echo #SAVE#;
will create a save, and then echo a flag which will let us know how long into the demo the save was made.
after around 100 frames, the alias will stop the demo.
This enlenghtening of the demo will give us more frames, and more audio to work with when rendering.
The unpause bind simply sets your sensitivity to a value that isn't 0, and unpauses.
alias l04d "exec seg;stop;spt_afterticks_reset;re;w10;load PREVIOUS_SEGMENT.sav;sensitivity 0;w5;spt_afterticks 1 rec"
alias rec "record CURRENT_SEGMENT"
alias s4v3 "save CURRENT_SEGMENT;echo #SAVE#;sensitivity 0;spt_afterticks 66 stop"
bind mouse3 l04d // Reset a segment, start recording
bind mouse4 "sensitivity 2;unpause" // Unpause after loading a segment
bind mouse5 s4v3 // Save a segment
Do note that this requires the wait table to be executed.
TODO: EXPLANATION FOR OLD ENGINE
Your Segmenting CFG Should now be complete.
For the purposes of learning, let's assume that you've recieved a save from another member of a segmented speedrun, and you want to record the next segment.
Let's say that the save you recieved is named 123-Jeff-789, and your name is Gordon.
The Syntax of the demo name works like this: SEGMENT_NUMBER-SEGMENTER-LENGHT
, so the demo you've recieved is the 123rd demo of the run, created by Jeff, and is 789 ticks long.
Place the save in your SAVE folder, open your segmenting CFG, and edit l04d and s4v3. Replace PREVIOUS_SEGMENT
with 123-Jeff-789
,
and both instances of CURRENT_SEGMENT
with 124-Gordon
. We will add the tick count later, as we can't know how long the demo will be.
Execute your segmenting config, and then press your l04d bind (mouse3 by default).
You will be loaded into the save you've recieved, and demo recording will start.
Press your unpause bind (mouse4 by default) to unpause and begin the segment.
After you're done, press your s4v3 bind and wait a second to let the demo recording finish.
Alternatively, if you're not happy with the segment simply execute l04d again to retry.
Keep in mind that starting a new demo will Overwrite the previous one unless it's renamed, making it unusable.
After you're satisfied with your segment, you will need to time it. For this, Listdemo- is used.
Simply drag and drop your demo onto the Listdemo exe.
On Linux, use wine with the demo as an argument or create a .desktop file with Exec=/bin/bash -c 'wine PATH_TO_LISTDEMO "%F"'
You will get an output similar to this:
We can see that the tick index at the time of the #SAVE#
flag is 52 ticks. This means that the actual time that has passed is 53 ticks, as the tick index starts at 0.
Always remember to add the 1 to the tick count.
Now you can rename both your demo and save to the proper format, which in this case will be 124-Gordon-53
.
As an alternative to manual renaming, there are scripts which do it automatically.
TODO: LINK TO AN ACTUAL PROPER SCRIPT. IF YOU'RE ON LINUX YOU MAY USE RENAMEDEMO BUT IT'S NOT RECOMMENDED. IT ASSUMES THAT LISTDEMO IS IN YOUR HOME DIRECTORY.
Once your segment is properly named, you may send it to the rest of the team.
In order to stop a segment on a map transition, Enter the transition, wait until it finishes, and save while paused.
This will create an additional _2 demo, which will be 2 ticks long.
Rename this demo to 124-Gordon-72_2, and make sure to send it together with the real part of the demo.
Since the #SAVE# flag does not exist in this instance, use the lenght of the entire demo to time it instead. Here this would be 72.
There are 2 ways to start a run.
The first, is to simply run stop;wait 5;map MAPNAME;wait 10;record 000-YOURNAME
, and then stop the segment with your s4v3 bind.
This is most often used if the run starts with a cutscene, and the player can't move instantly after loading.
If you need a segment where the player starts moving right after the map loads recording, use the following alias:
alias runstart "spt_afterframes_reset_on_server_activate 0;stop;map MAPNAME;spt_afterframes 7 s4v3;wait 5;record 000-YOURNAME"
Then execute it by typing runstart
in the console.
This shloud result in a 7 or 8 tick long segment, which is the shortest possible segment that will still give you starting items.
If the segment is longer, or shorter, you can adjust spt_afterframes 7
. Putting a higher amount of frames will result in a longer demo, while lowering it in shorter.
If it's too low, the save will not be made.
There are 2 ways to handle saveloading when segmenting.
the spt_saveloads
command is the most user-friendly way to create saveload segments, however, it is not supported in every game and mod.
We will create 10 saveload segments starting from segment 123-Alyx-45.
This can be done by executing spt_saveloads segment 124-Alyx 1 10
in the console, and then simply loading the 123-Alyx-45
save, where:
segment
is the saveload mode, the other 2 being execute
and render
124-Alyx
is the prefix of the segments which will be created (124-Alyx-001, 124-Alyx-002 and so on.)1
is the index of the first segment, this should be 1
99% of the time.10
is the index of the last segment.Due to a bug with SPT, spt_pause needs to be set to 0 for spt_saveloads to create demos for saveload segments. The segments will also display the #SAVE# flag at a tick differen't from 0, but rest assured, that is also a bug and the saveloads are 0-ticks.
More detailed documentation of spt_saveloads can be achieved by simply executing spt_saveloads
in game.
This method is not reccomended if spt_saveloads works.
We will use a CFG file to automatically create the segments for us.
However, that CFG file needs to be generated by a generator first.
The primary generators used are Rama's New Engine saveload CFG generator and 2838's New Engine GUI saveload CFG generator.
The usage of all of these generators is in practice identical.
1
99% of the time.All of these generators also have a "load time" variable. It is the reason why this method is not recommended.
If the load time is either too low or too high, the saveload chain will break.
If it's too low, segments will not be created.
If it's too high, segments will not be 0 ticks. You can tell this is happening if you see the "SAVED" popup in game. It should not appear.
The "Load Time" varies from map to map, and can even vary based on the direction the player is looking.
This means that a saveload chain can simply break for no reason in the middle of it.
If this happens, stop the saveloads by pressing p, then find the final working segment, change the index of the first saveload to the saveload after the final working one, regenerate the script and continue from there.
The GUI Script generator will auto-create a cfg file, while the Scripts will print it to the terminal.
You can easily get the output into a file by opening the script in the terminal and piping the output to a file with > (ex. python3 slscript_program > myslscript.cfg
)
Simply run the Save Deletion cfg, replacing both instances of SEGNAME with the name of the save deletion segment.
In case the demo is too long, lower the value of spt_afterframes. do the opposite if it's too long.
Jumpscripts are aliases meant to make movement easier to segment.
They automatically enable +walk for jumping and perfectly drop keys for circlestrafes.
bind your jump key to +fronthop
for forwards circlestrafes, +backhop
for backwards circlestrafes, and +jumpy
for general movement.
You may also use +strafehop as an alternative to +fronthop
. It's slightly faster, but requires you to move your mouse down in the moment of the jump.