Skip to main content
The CSAFAP Config Package uses AveYo’s ticker system to execute alias chains every frame, enabling binds that require frame-perfect timing. This system is critical for jumpthrow binds, null movement, and rapid-fire mechanics.

What is the Ticker?

The ticker is a .vtest script file that runs every frame, calling specific aliases at precise intervals. It leverages CS2’s -testscript launch option to execute code outside the normal command queue.

Launch Option Requirement

From README.md installation (csafap/addons/.vtest:2):
This tells CS2 to execute .vtest file continuously during gameplay.

The .vtest File

From csafap/addons/.vtest:

How It Works

  1. Test_WaitForCheckPoint frame_end: Synchronizes to frame end
  2. Alias calls (e.g., W!, M1!, JT!): Execute in order
  3. Repeated calls: Chain multiple alias substitutions in single frame
  4. Test_Run: Loops back to beginning, running every frame
Key insight: Each alias (like W!) is called twice because a single alias substitution can only change one level deep per frame. Calling twice allows chained state transitions.

Jumpthrow Implementation

Basic Jumpthrow

From csafap/addons/AveYo.cfg:4-7:
State Machine Flow: On key press (+JumpThrow):
  1. Set JT! to JT+1
  2. Next frame: Ticker calls JT! → executes JT+1 → calls M1> (release attack1), sets JT! to JT+2
  3. Next frame: Ticker calls JT! → executes JT+2 → calls M2> (release attack2), sets JT! to JT+3
  4. Next frame: Ticker calls JT! → executes JT+3 → activates +jump, clears JT!
On key release (-JumpThrow):
  1. Set JT! to JT-1
  2. Next frame: Ticker calls JT! → executes JT-1 → deactivates jump with jump -9999 f u, clears JT!
Result: The grenade releases exactly when jump activates, replicating CS:GO’s jumpthrow timing.

W-Jumpthrow

From csafap/addons/AveYo.cfg:9-13:
Adds forward movement before jump:
  1. Frame 1: +forward
  2. Frame 2: Release M1>
  3. Frame 3: Release M2>
  4. Frame 4: +jump
On release:
  1. Frame 1: Cancel forward movement
  2. Frame 2: Cancel jump

Mouse Button Ticker Integration

Jumpthrow requires special mouse binds (csafap/addons/AveYo.cfg:15-20):
How M1> and M2> work:
  • When you click mouse1, +M1 sets M1> to -attack
  • When jumpthrow calls M1>, it executes -attack (releases grenade)
  • After release, M1> is cleared back to empty
Important: spec_next and spec_prev preserve spectator functionality when mouse buttons are released.

Null Movement Binds

From csafap/addons/AveYo.cfg:27-42:
State Machine Logic: When W is pressed:
  1. +nullW sets W! to W+1
  2. Next frame: W+1 calls W< (empty initially), sets W! to W+2
  3. Next frame: W+2 activates +forward, and sets S< and S> aliases:
    • S< = cancel forward movement
    • S> = activate forward movement
When S is pressed while W is held:
  1. +nullS triggers similar chain
  2. Calls W< which now equals forward -9999 f u (from S’s setup)
  3. Cancels forward movement instantly
  4. Activates backward movement instead
Result: Pressing opposite direction keys cancels the first key’s action, enabling “Snap-Tap” null movement.

Why Dual Aliases (< and >)

  • W</S</A</D<: Called by opposite key to cancel current movement
  • W>/S>/A>/D>: Called on key release to restore previous movement state
This creates proper priority: last pressed key wins.

Crouch Jump

From csafap/addons/AveYo.cfg:22-25:
On press:
  1. Frame 1: +duck
  2. Frame 2: +jump
On release:
  1. Frame 1: Cancel duck
  2. Frame 2: Cancel jump
Ensures crouch activates one frame before jump for maximum height.

Performance Impact

From csafap/addons/.vtest:28-29:
Options:
  • No Test_RunFrame: Runs every frame (highest responsiveness, small FPS cost)
  • One Test_RunFrame: Runs every 2nd frame (lower responsiveness, better FPS)
  • Multiple Test_RunFrame: Further reduces frequency
Default configuration omits Test_RunFrame for maximum responsiveness.

Ticker vs. Radio Wheel Binds

The CSAFAP package uses two different bind systems:

Common Issues

Console Spam: Unknown command: W!...

From README.md Q20: Cause: The ticker aliases (W!, M1!, etc.) aren’t initialized before the .vtest script starts. Solution:
  1. Ensure +exec csafap/main is in launch options
  2. Check for long alias commands that might break the exec queue
  3. Verify .vtest file has correct name (literally .vtest, not vtest.vtest)

Movement/Mouse Buttons Don’t Work

From README.md Q21: Cause: Same as console spam - ticker initialized before binds loaded. Solution:
  1. Remove -testscript from launch options temporarily
  2. Check console for errors after exec csafap/main
  3. Fix any alias that’s too long or malformed
  4. Add -testscript back once all aliases load successfully

Rapid Fire/Follow Recoil Not Working

From README.md Q18: Framerate dependency:
  • Default config requires 150+ FPS
  • For <150 FPS: rename rapid_followrecoil_lessthan150FPS.cfg to rapid_followrecoil.cfg
Ticker timing is frame-dependent, so low FPS breaks frame-perfect sequences.

Technical Deep Dive

Why -9999 f u?

Commands like jump -9999 f u instantly deactivate the command:
  • The -9999 is an extreme negative value
  • f u are flags (exact meaning undocumented by Valve)
  • Together they force immediate deactivation, overriding any queued actions

Alias Substitution Depth Limit

CS2 only allows one level of alias substitution per frame. Example:
This is why .vtest calls each alias twice - the first call changes the alias, the second call executes the new value.

Frame Timing

  • frame_end: Ticker runs after game logic but before rendering
  • Render time: ~6-16ms at 60-165 FPS
  • Ticker overhead: <0.1ms per frame
This ensures ticker actions take effect before the next frame’s input processing.

Advantages Over Multi-Input Binds

Valve patched multi-input binds (Oct 28, 2024) where bind key "+action1; +action2" would only execute first action. Ticker system bypasses this by:
  1. Storing state in aliases (e.g., JT!)
  2. Ticker executing state machine steps across multiple frames
  3. Each frame issues only one +action, legal per Valve’s rules
This is why jumpthrow still works post-patch while old methods don’t.