# cs2surf/timer architecture

> Architecture diagram of the GitHub repository cs2surf/timer, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/cs2surf/timer
- Repository: https://github.com/cs2surf/timer

## Overview

CS2 SurfTimer is a CounterStrikeSharp server plugin that turns player movement through map zones into timed map, stage, and bonus runs. Game events and commands initialize player/map state, drive timing and replay capture, and expose results through HUD and chat. Run/profile records use a shared data-access abstraction backed by MySQL or the optional REST API. The index confirms several calls; unsampled modules and portions of excerpts limit finer control-flow claims, so uncertain links are omitted.

Main entry points: [`src/ST-Player/Player.cs`](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Player.cs) (Player), [`src/ST-Commands/PlayerCommands.cs`](https://github.com/cs2surf/timer/blob/main/src/ST-Commands/PlayerCommands.cs) (Player commands), [`src/ST-Events/ZoneEventHandlers.cs`](https://github.com/cs2surf/timer/blob/main/src/ST-Events/ZoneEventHandlers.cs) (Zone events), [`src/ST-UTILS/Data/IDataAccessService.cs`](https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/IDataAccessService.cs) (Data access contract)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime["Plugin runtime"]
  node_entry["Plugin lifecycle<br/>[SurfTimer.cs]"]
  node_tick["Tick updates<br/>[Tick.cs]"]
  node_config["Configuration<br/>[Config.cs]"]
end

subgraph group_gameplay["Surf gameplay"]
  node_map["Map and zones<br/>[Map.cs]"]
  node_events["Zone events"]
  node_touch["Trigger touch hooks"]
  node_endtouch["Trigger exit hooks<br/>[TriggerEndTouch.cs]"]
  node_commands["Player commands<br/>[PlayerCommands.cs]"]
  node_mapcommands["Map commands<br/>[MapCommands.cs]"]
  node_hud["HUD and results<br/>[PlayerHUD.cs]"]
  node_saveloc["Practice locations<br/>[SavelocFrame.cs]"]
end

subgraph group_records["Player records"]
  node_player["Player<br/>[Player.cs]"]
  node_timer["Run timer<br/>[PlayerTimer.cs]"]
  node_currentrun["Current run<br/>[CurrentRun.cs]"]
  node_pb["Personal bests<br/>[PersonalBest.cs]"]
  node_stats["Player stats<br/>[PlayerStats.cs]"]
  node_profile["Player profile<br/>[PlayerProfile.cs]"]
  node_recorder["Replay recorder<br/>[ReplayRecorder.cs]"]
  node_frames["Replay frames<br/>[ReplayFrame.cs]"]
  node_replaymanager["Replay manager<br/>[ReplayManager.cs]"]
  node_replayplayer["Replay playback<br/>[ReplayPlayer.cs]"]
end

subgraph group_persistence["Persistence and API"]
  node_dataiface["Data access contract"]
  node_mysql["MySQL access"]
  node_apiaccess["REST API access"]
end

node_actor(("Surf player"))
node_game["CounterStrikeSharp"]
node_database[("MySQL database")]
node_restapi["SurfTimer REST API"]

node_game -->|"starts plugin"| node_entry
node_entry -->|"initializes map"| node_map
node_actor -->|"issues commands"| node_commands
node_commands -->|"starts replay"| node_recorder
node_commands -->|"selects replay"| node_replayplayer
node_commands -->|"uses saved locations"| node_saveloc
node_touch -.->|"dispatches zone touch"| node_events
node_endtouch -.->|"dispatches zone exit"| node_events
node_events -->|"updates player"| node_player
node_events -->|"uses map zones"| node_map
node_events -->|"records run"| node_currentrun
node_tick -->|"captures frames"| node_recorder
node_tick -.->|"advances playback"| node_replayplayer
node_player -->|"owns timer"| node_timer
node_player -->|"owns stats"| node_stats
node_player -->|"owns profile"| node_profile
node_player -->|"owns recorder"| node_recorder
node_player -->|"stores locations"| node_saveloc
node_player -->|"owns HUD"| node_hud
node_currentrun -->|"saves run"| node_dataiface
node_profile -->|"loads profile"| node_dataiface
node_map -->|"loads map records"| node_dataiface
node_stats -->|"manages bests"| node_pb
node_stats -->|"manages current run"| node_currentrun
node_recorder -->|"creates frames"| node_frames
node_replaymanager -->|"holds replays"| node_replayplayer
node_map -->|"initializes manager"| node_replaymanager
node_commands -.->|"displays results"| node_hud
node_dataiface -->|"implemented by"| node_mysql
node_dataiface -->|"implemented by"| node_apiaccess
node_mysql -.->|"queries"| node_database
node_apiaccess -.->|"requests"| node_restapi
node_config -->|"configures API"| node_apiaccess
node_entry -.->|"loads settings"| node_config

click node_player "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Player.cs"
click node_entry "https://github.com/cs2surf/timer/blob/main/src/SurfTimer.cs"
click node_map "https://github.com/cs2surf/timer/blob/main/src/ST-Map/Map.cs"
click node_events "https://github.com/cs2surf/timer/blob/main/src/ST-Events/ZoneEventHandlers.cs"
click node_touch "https://github.com/cs2surf/timer/blob/main/src/ST-Events/TriggerStartTouch.cs"
click node_endtouch "https://github.com/cs2surf/timer/blob/main/src/ST-Events/TriggerEndTouch.cs"
click node_tick "https://github.com/cs2surf/timer/blob/main/src/ST-Events/Tick.cs"
click node_commands "https://github.com/cs2surf/timer/blob/main/src/ST-Commands/PlayerCommands.cs"
click node_mapcommands "https://github.com/cs2surf/timer/blob/main/src/ST-Commands/MapCommands.cs"
click node_timer "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerTimer.cs"
click node_currentrun "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/CurrentRun.cs"
click node_pb "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/PersonalBest.cs"
click node_stats "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/PlayerStats.cs"
click node_profile "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerProfile.cs"
click node_hud "https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerHUD.cs"
click node_recorder "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayRecorder.cs"
click node_frames "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayFrame.cs"
click node_replaymanager "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayManager.cs"
click node_replayplayer "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayPlayer.cs"
click node_saveloc "https://github.com/cs2surf/timer/blob/main/src/ST-Player/Saveloc/SavelocFrame.cs"
click node_dataiface "https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/IDataAccessService.cs"
click node_mysql "https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/MySqlDataAccessService.cs"
click node_apiaccess "https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/ApiDataAccessService.cs"
click node_config "https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Config.cs"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_entry,node_tick,node_config toneBlue
class node_map,node_events,node_touch,node_endtouch,node_commands,node_mapcommands,node_hud,node_saveloc,node_database toneAmber
class node_player,node_timer,node_currentrun,node_pb,node_stats,node_profile,node_recorder,node_frames,node_replaymanager,node_replayplayer,node_restapi toneMint
class node_dataiface,node_mysql,node_apiaccess toneRose
class node_actor,node_game toneIndigo
```

## Components

### Plugin runtime

- [Plugin lifecycle](https://github.com/cs2surf/timer/blob/main/src/SurfTimer.cs): `src/SurfTimer.cs`
- [Tick updates](https://github.com/cs2surf/timer/blob/main/src/ST-Events/Tick.cs): `src/ST-Events/Tick.cs`
- [Configuration](https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Config.cs): `src/ST-UTILS/Config.cs`

### Surf gameplay

- [Map and zones](https://github.com/cs2surf/timer/blob/main/src/ST-Map/Map.cs): `src/ST-Map/Map.cs`
- [Zone events](https://github.com/cs2surf/timer/blob/main/src/ST-Events/ZoneEventHandlers.cs): `src/ST-Events/ZoneEventHandlers.cs`
- [Trigger touch hooks](https://github.com/cs2surf/timer/blob/main/src/ST-Events/TriggerStartTouch.cs): `src/ST-Events/TriggerStartTouch.cs`
- [Trigger exit hooks](https://github.com/cs2surf/timer/blob/main/src/ST-Events/TriggerEndTouch.cs): `src/ST-Events/TriggerEndTouch.cs`
- [Player commands](https://github.com/cs2surf/timer/blob/main/src/ST-Commands/PlayerCommands.cs): `src/ST-Commands/PlayerCommands.cs`
- [Map commands](https://github.com/cs2surf/timer/blob/main/src/ST-Commands/MapCommands.cs): `src/ST-Commands/MapCommands.cs`
- [HUD and results](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerHUD.cs): `src/ST-Player/PlayerHUD.cs`
- [Practice locations](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Saveloc/SavelocFrame.cs): `src/ST-Player/Saveloc/SavelocFrame.cs`

### Player records

- [Player](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Player.cs): `src/ST-Player/Player.cs`
- [Run timer](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerTimer.cs): `src/ST-Player/PlayerTimer.cs`
- [Current run](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/CurrentRun.cs): `src/ST-Player/PlayerStats/CurrentRun.cs`
- [Personal bests](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/PersonalBest.cs): `src/ST-Player/PlayerStats/PersonalBest.cs`
- [Player stats](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerStats/PlayerStats.cs): `src/ST-Player/PlayerStats/PlayerStats.cs`
- [Player profile](https://github.com/cs2surf/timer/blob/main/src/ST-Player/PlayerProfile.cs): `src/ST-Player/PlayerProfile.cs`
- [Replay recorder](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayRecorder.cs): `src/ST-Player/Replay/ReplayRecorder.cs`
- [Replay frames](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayFrame.cs): `src/ST-Player/Replay/ReplayFrame.cs`
- [Replay manager](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayManager.cs): `src/ST-Player/Replay/ReplayManager.cs`
- [Replay playback](https://github.com/cs2surf/timer/blob/main/src/ST-Player/Replay/ReplayPlayer.cs): `src/ST-Player/Replay/ReplayPlayer.cs`

### Persistence and API

- [Data access contract](https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/IDataAccessService.cs): `src/ST-UTILS/Data/IDataAccessService.cs`
- [MySQL access](https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/MySqlDataAccessService.cs): `src/ST-UTILS/Data/MySqlDataAccessService.cs`
- [REST API access](https://github.com/cs2surf/timer/blob/main/src/ST-UTILS/Data/ApiDataAccessService.cs): `src/ST-UTILS/Data/ApiDataAccessService.cs`

### Other components

- **Surf player**
- **CounterStrikeSharp**
- **MySQL database**
- **SurfTimer REST API**

## Connections

- CounterStrikeSharp → Plugin lifecycle: starts plugin (evidence: `src/SurfTimer.cs`)
- Plugin lifecycle → Map and zones: initializes map (evidence: `src/SurfTimer.cs`)
- Surf player → Player commands: issues commands (evidence: `README.md`)
- Player commands → Replay recorder: starts replay (evidence: `src/ST-Commands/PlayerCommands.cs`)
- Player commands → Replay playback: selects replay (evidence: `src/ST-Commands/PlayerCommands.cs`)
- Player commands → Practice locations: uses saved locations (evidence: `src/ST-Commands/PlayerCommands.cs`)
- Trigger touch hooks → Zone events: dispatches zone touch
- Trigger exit hooks → Zone events: dispatches zone exit
- Zone events → Player: updates player (evidence: `src/ST-Events/ZoneEventHandlers.cs`)
- Zone events → Map and zones: uses map zones (evidence: `src/ST-Events/ZoneEventHandlers.cs`)
- Zone events → Current run: records run (evidence: `src/ST-Events/ZoneEventHandlers.cs`)
- Tick updates → Replay recorder: captures frames (evidence: `src/ST-Events/Tick.cs`)
- Tick updates → Replay playback: advances playback (evidence: `src/ST-Player/Replay/ReplayPlayer.cs`)
- Player → Run timer: owns timer (evidence: `src/ST-Player/Player.cs`)
- Player → Player stats: owns stats (evidence: `src/ST-Player/Player.cs`)
- Player → Player profile: owns profile (evidence: `src/ST-Player/Player.cs`)
- Player → Replay recorder: owns recorder (evidence: `src/ST-Player/Player.cs`)
- Player → Practice locations: stores locations (evidence: `src/ST-Player/Player.cs`)
- Player → HUD and results: owns HUD (evidence: `src/ST-Player/Player.cs`)
- Current run → Data access contract: saves run (evidence: `src/ST-Player/PlayerStats/CurrentRun.cs`)
- Player profile → Data access contract: loads profile (evidence: `src/ST-Player/PlayerProfile.cs`)
- Map and zones → Data access contract: loads map records (evidence: `src/ST-Map/Map.cs`)
- Player stats → Personal bests: manages bests (evidence: `src/ST-UTILS/Injection.cs`)
- Player stats → Current run: manages current run (evidence: `src/ST-UTILS/Injection.cs`)
- Replay recorder → Replay frames: creates frames (evidence: `src/ST-Player/Replay/ReplayRecorder.cs`)
- Replay manager → Replay playback: holds replays (evidence: `src/ST-Player/Replay/ReplayManager.cs`)
- Map and zones → Replay manager: initializes manager (evidence: `src/ST-Map/Map.cs`)
- Player commands → HUD and results: displays results
- Data access contract → MySQL access: implemented by (evidence: `src/ST-UTILS/Data/MySqlDataAccessService.cs`)
- Data access contract → REST API access: implemented by (evidence: `src/ST-UTILS/Data/ApiDataAccessService.cs`)
- MySQL access → MySQL database: queries
- REST API access → SurfTimer REST API: requests
- Configuration → REST API access: configures API (evidence: `src/ST-UTILS/Config.cs`)
- Plugin lifecycle → Configuration: loads settings (evidence: `src/SurfTimer.cs`)
