SkillAgentSearch skills...

Demoparser

Counter-Strike 2 replay parser for Python and JavaScript

Install / Use

/learn @LaihoE/Demoparser

README

Demo parser for Counter-Strike 2

We now have a discord channel: Discord

Demoparser is a tool for analysing CS2 replay files "demos". All the heavy lifting is done in Rust, but you use it from the comfort of Python/JavaScript. The parser takes a slightly different approach to exposing the information in the demo. Rather than letting you hook onto events in a streaming fashion, it lets you "query" the demo similarly to how you would interact with a database.

Install

Python: pip install demoparser2 (python >= 3.8)

NodeJS: npm i @laihoe/demoparser2

WASM: npm i demoparser2

Getting started

Python

from demoparser2 import DemoParser

parser = DemoParser("path_to_demo.dem")
event_df = parser.parse_event("player_death", player=["X", "Y"], other=["total_rounds_played"])
ticks_df = parser.parse_ticks(["X", "Y"])

NodeJS

var {parseEvent, parseTicks} = require('@laihoe/demoparser2');

let event_json = parseEvent("path_to_demo.dem", "player_death", ["X", "Y"], ["total_rounds_played"])
let ticks_json = parseTicks("path_to_demo.dem", ["X", "Y"])

Examples in Python and JavaScript

Scuffed Documentaion

Performance

The benchmark finds the coordinates of all player deaths. Code: Benchmark

Benchmarked 50 demos containing a mix of (MM, Faceit, HLTV) demos. Total size: 4.6GB |device|CPU cores|total time|MB/s| | :-------------------:| :----------------------------------- | :----------------------------------- |:----------------------------------- | gaming PC|12|6.14s|749| ThinkPad T14 gen 2|4|14.00s|328|

Gaming pc specs: CPU: Ryzen 5900x, SSD: Samsung 980 pro NVME
Thinkpad specs: CPU: i5-1335g7, SSD: Toshiba XG6 NVME
Both devices run Ubuntu 20.04
Python/JS are rougly as fast.

List of fields the parser supports:

Player data

| Name | "Real" name | | :-------------------: | :----------------------------------- | | X | m_vec + m_cell | | Y | m_vec + m_cell | | Z | m_vec + m_cell | | health | m_iHealth | | score | m_iScore | | mvps| m_iMVPs | | is_alive | m_bPawnIsAlive | | balance | m_iAccount | | inventory| _ | | inventory_as_ids | - | | life_state | m_lifeState | | pitch | m_angEyeAngles[0] | | yaw | m_angEyeAngles[1] | | is_auto_muted | m_bHasCommunicationAbuseMute | | crosshair_code | m_szCrosshairCodes | | pending_team_num | m_iPendingTeamNum | | player_color | m_iCompTeammateColor | | ever_played_on_team | m_bEverPlayedOnTeam | | is_coach_team | m_iCoachingTeam | | rank | m_iCompetitiveRanking | | rank_if_win| m_iCompetitiveRankingPredicted_Win | | rank_if_loss| m_iCompetitiveRankingPredicted_Loss | | rank_if_tie| m_iCompetitiveRankingPredicted_Tie | | comp_wins | m_iCompetitiveWins | | comp_rank_type | m_iCompetitiveRankType | | is_controlling_bot | m_bControllingBot | | has_controlled_bot_this_round | m_bHasControlledBotThisRound | | can_control_bot | m_bCanControlObservedBot | | has_defuser | m_bPawnHasDefuser | | has_helmet | m_bPawnHasHelmet | | spawn_time | m_iPawnLifetimeStart | | death_time | m_iPawnLifetimeEnd | | game_time | net_tick | | is_connected | m_iConnected | | player_name | m_iszPlayerName | | player_steamid | m_steamID | | fov | m_iDesiredFOV | | start_balance | m_iStartAccount | | total_cash_spent | m_iTotalCashSpent | | cash_spent_this_round | m_iCashSpentThisRound | | music_kit_id | m_unMusicID | | leader_honors | m_nPersonaDataPublicCommendsLeader | | teacher_honors | m_nPersonaDataPublicCommendsTeacher | | friendly_honors | m_nPersonaDataPublicCommendsFriendly | | ping | m_iPing | | move_collide | m_MoveCollide | | move_type | m_MoveType | | team_num | m_iTeamNum | | active_weapon | m_hActiveWeapon | | looking_at_weapon | m_bIsLookingAtWeapon | | holding_look_at_weapon | m_bIsHoldingLookAtWeapon | | next_attack_time | m_flNextAttack | | duck_time_ms | m_nDuckTimeMsecs | | max_speed | m_flMaxspeed | | max_fall_velo | m_flMaxFallVelocity | | duck_amount | m_flDuckAmount | | duck_speed | m_flDuckSpeed | | duck_overrdie | m_bDuckOverride | | old_jump_pressed | m_bOldJumpPressed | | jump_until | m_flJumpUntil | | jump_velo | m_flJumpVel | | fall_velo | m_flFallVelocity | | in_crouch | m_bInCrouch | | crouch_state | m_nCrouchState | | ducked | m_bDucked | | ducking | m_bDucking | | in_duck_jump | m_bInDuckJump | | allow_auto_movement | m_bAllowAutoMovement | | jump_time_ms | m_nJumpTimeMsecs | | last_duck_time | m_flLastDuckTime | | is_rescuing | m_bIsRescuing | | weapon_purchases_this_match | m_iWeaponPurchasesThisMatch | | weapon_purchases_this_round | m_iWeaponPurchasesThisRound | | spotted | m_bSpotted | | approximate_spotted_by | m_bSpottedByMask | | time_last_injury | m_flTimeOfLastInjury | | direction_last_injury | m_nRelativeDirectionOfLastInjury | | player_state | m_iPlayerState | | passive_items | m_passiveItems | | is_scoped | m_bIsScoped | | is_walking | m_bIsWalking | | resume_zoom | m_bResumeZoom | | is_defusing | m_bIsDefusing | | is_grabbing_hostage | m_bIsGrabbingHostage | | blocking_use_in_progess | m_iBlockingUseActionInProgress | | molotov_damage_time | m_fMolotovDamageTime | | moved_since_spawn | m_bHasMovedSinceSpawn | | in_bomb_zone | m_bInBombZone | | in_buy_zone | m_bInBuyZone | | in_no_defuse_area | m_bInNoDefuseArea | | killed_by_taser | m_bKilledByTaser | | move_state | m_iMoveState | | which_bomb_zone | m_nWhichBombZone | | in_hostage_rescue_zone | m_bInHostageRescueZone | | stamina | m_flStamina | | direction | m_iDirection | | shots_fired | m_iShotsFired | | armor_value | m_ArmorValue | | velo_modifier | m_flVelocityModifier | | ground_accel_linear_frac_last_time | m_flGroundAccelLinearFracLastTime | | flash_duration | m_flFlashDuration | | flash_max_alpha | m_flFlashMaxAlpha | | wait_for_no_attack | m_bWaitForNoAttack | | last_place_name | m_szLastPlaceName | | is_strafing | m_bStrafing | | round_start_equip_value | m_unRoundStartEquipmentValue | | current_equip_value | m_unCurrentEquipmentValue | | velocity | - | | velocity_X | - | | velocity_Y | - | | velocity_Z | - | | agent_skin | - | | user_id | - | | entity_id | - | | is_airborne | m_hGroundEntity | | aim_punch_angle | CCSPlayerPawn.m_aimPunchAngle | | aim_punch_angle_vel | CCSPlayerPawn.m_aimPunchAngleVel | | glove_paint_id | - | | glove_paint_seed | - | | glove_paint_float | - | | glove_item_idx | - |

Buttons

True/Flase if player is pressing button. | Name | Real name | | :-------------------: | :----------------------------------- | |FORWARD|m_nButtonDownMaskPrev| |LEFT|m_nButtonDownMaskPrev| |RIGHT |m_nButtonDownMaskPrev| |BACK|m_nButtonDownMaskPrev| |FIRE|m_nButtonDownMaskPrev| |RIGHTCLICK |m_nButtonDownMaskPrev| |RELOAD |m_nButtonDownMaskPrev| |INSPECT|m_nButtonDownMaskPrev| |USE|m_nButtonDownMaskPrev| |ZOOM |m_nButtonDownMaskPrev| |SCOREBOARD|m_nButtonDownMaskPrev| |WALK|m_nButtonDownMaskPrev| |buttons|m_nButtonDownMaskPrev|

(buttons is the real value of m_nButtonDownMaskPrev and the others are derived from it)

Game State

| Name | Real name | | :-------------------: | :----------------------------------- | |team_rounds_total|m_iScore| |team_surrendered|m_bSurrendered| |team_name|m_szTeamname| |team_score_overtime|m_scoreOvertime| |team_match_stat|m_szTeamMatchStat| |team_num_map_victories|m_numMapVictories| |team_score_first_half| m_scoreFirstHalf | | team_score_second_half | m_scoreSecondHalf | | team_clan_name | m_szClanTeamname | | is_freeze_period | m_bFreezePeriod | | is_warmup_period | m_bWarmupPeriod | | warmup_period_end | m_fWarmupPeriodEnd | | warmup_period_start | m_fWarmupPeriodStart | | is_terrorist_timeout | m_bTerroristTimeOutActive | | is_ct_timeout | m_bCTTimeOutActive | | terrorist_timeout_remaining | m_flTerroristTimeOutRemaining | | ct_timeout_remaining | m_flCTTimeOutRemaining | | num_terrorist_timeouts | m_nTerroristTimeOuts | | num_ct_timeouts | m_nCTTimeOuts | | is_technical_timeout | m_bTechnicalTimeOut | | is_waiting_for_resume | m_bMatchWaitingForResume | | match_start_time | m_fMatchStartTime | | round_start_time | m_fRoundStartTime | | restart_round_time | m_flRestartRoundTime | | is_game_restart | m_bGameRestart | | game_start_time | m_flGameStartTime | | time_until_next_phase_start | m_timeUntilNextPhaseStarts | | game_phase | m_gamePhase | | total_rounds_played | m_totalRoundsPlayed | | rounds_played_this_phase | m_nRoundsPlayedThisPhase | | hostages_remaining | m_iHostagesRemaining | | any_hostages_reached | m_bAnyHostageReached | | has_bombites | m_bMapHasBombTarget | | has_rescue_zone | m_bMapHasRescueZone | | has_buy_zone | m_bMapHasBuyZone | | is_matchmaking | m_bIsQueuedMatchmaking | | match_making_mode | m_nQueuedMatchmakingMode | | is_valve_dedicated_server | m_bIsValveDS | | gungame_prog_weap_ct | m_iNumGunGameProgressiveWeaponsCT | | gungame_prog_weap_t | m_iNumGunGameProgressiveWeaponsT | | spectator_slot_count | m_iSpectatorSlotCount | | is_match_started | m_bHasMatchStarted | | n_best_of_maps | m_numBestOfMaps | | is_bomb_dropped | m_bBombDropped | | is_bomb_planted | m_bBombPlanted | | round_win_status | m_iRoundWinStatus | | round_win_reason | m_eRoundWinReason | | terrorist_cant_buy | m_bTCantBuy | | ct_cant_buy | m_bCTCantBuy | | ct_losing_streak | m_iNumConsecutiveCTLoses | | t_losing_streak | m_iNumConsecutiveTerroristLoses | | survival_start_time | m_flSurvivalStartTime | | round_in_progres

View on GitHub
GitHub Stars615
CategoryDevelopment
Updated9h ago
Forks73

Languages

Rust

Security Score

100/100

Audited on Mar 27, 2026

No findings