CSGO demo parser for Python

Overview

CSGO demo parser for Python

Demo parser for Counter-Strike: Global Offensive. Parser is used to collect data from replay files (".dem" files).
The goal of the parser fast and simple. Performance is solved by having Rust do the heavy lifting and to keep it simple we completely avoid "hooks" and rather just let users "query" the demo.

Installing

Python >= 3.7 (but not 3.11 it came out like a few days ago, will add when available)

pip install demoparser

Game events

from demoparser import DemoParser

parser = DemoParser("path_to_demo.dem")
events = parser.parse_events("player_death")

List of possible events: GameEvents
WARNING all demos do not contain every possible event.

Events can easily be transformed into a df:

df = pd.DataFrame(events)

You can also add "tick data" into game events like so:

events = parser.parse_events("player_death", props=["X", "Y", "health"])

Tick data

from demoparser import DemoParser

wanted_props = ["X", "Y", "Z", "health"]

parser = DemoParser("path_to_demo.dem")
df = parser.parse_ticks(wanted_props)

List of possible props:props
parse_ticks also accepts optional arguments for filtering players and ticks:

df = parser.parse_ticks(wanted_props, players=[76561197991348083], ticks=[489, 5884])

Utility functions

There are also these 2 functions for header and player info. Takes no arguments and returns some data.

parser.parse_header()
parser.parse_players()

Example game event

{
'player_name': 'flusha',
'event_name': 'weapon_fire',
'round': 0,
'silenced': 'false',
'weapon': 'weapon_ak47',
'tick': 18,
'player_id': 76561197991348083
}

Example tick data (output is a df)

           health         X              Y        tick        steamid       name
0            100     148.867508    -413.923218   10000  76561197991348083  flusha
1            100     149.625168    -412.063995   10001  76561197991348083  flusha
2            100     150.342468    -410.183685   10002  76561197991348083  flusha
3            100     151.025726    -408.286407   10003  76561197991348083  flusha
4            100     151.677643    -406.374207   10004  76561197991348083  flusha
...          ...            ...            ...     ...                ...     ...
90911         86   -1684.031250    2547.948975  100995  76561197991348083  flusha
90912         86   -1684.031250    2547.948975  100996  76561197991348083  flusha
90913         86   -1684.031250    2547.948975  100997  76561197991348083  flusha
90914         86   -1684.031250    2547.948975  100998  76561197991348083  flusha
90915         86   -1684.031250    2547.948975  100999  76561197991348083  flusha

[90916 rows x 6 columns]

Getting started

Examples are probably the best way to get started with parsing.

Performance

Your performance will mostly depend on how fast your HDD/SSD is. You can roughly calculate this part by demo size / reading speed of your drive.

Below are some rough estimates for parsing speeds excluding I/O.

Action Time
Game events with no "tick data" 30ms
Game events with "tick data" 310ms
Tick data: 1 value (no early exit) 300ms
Tick data: 5 million values 800ms
Rust only 150-200ms

Time taken for the parsing (with ryzen 5900x and no I/O):

If you have a fast SSD then i strongly recommend multiprocessing your parsing. Examples show how to multiprocess across demos. Multiprocessing will most likely max out your drive's reading speed. With multiprocessing ive been able to parse > 5GB/s (of game events) and >3GB/s (tick data). An average MM demo is around 90MB.

Performance will definetly still continue to improve, especially tick data with big number of values. "Rust only" means one full parse of the demo, compareable to what other parsers are doing. This part is probably quite close to the limit on how fast we can go, but we might be able to partially skip data, leading to even bigger improvements, but parsing every tick is not likely to improve by much.

Current flamegraph of performance: flamegraph. Save the image and open it in a browser to zoom.

Other notes

  • Demo tickrate is not the same as server tickrate. Often demo tickrate is half of server tickrate. For example faceit demos are 64 tick and MM demos are 32 tick. This means that every other tick is "missing". Pro games are often recorded at native tickrate.
  • First and last ticks often have many NaN values. For example if player isn't connected this happens.
  • Game events have lots of information. Look there first.
  • Exact granade trajectories are currently not supported. What you can find is where the granade was thrown from ("weapon_fire" event) and where it detonated (for example "hegrenade_detonate" event). Detonate event also includes coordinates but the weapon fire does not.
  • Parser early exits when biggest wanted tick is reached
  • If using WSL make sure the demos are also on WSL (or it will be slower)

Why yet another parser?

Currently you have to take such a big performance hit if you want to use Python, that most people just go elsewhere like Markus-wa's GO parser (great alternative if you want something mature). Unfortunately GO is just not such a popular language and most data analysis is done in Python/R. I also expect that most people interested in parsing demos are not experienced programmers and these people are very unlikely to learn a new language just for demo parsing. Demo parsing is something I think should be doable for very unexperienced programmers.

The parser is completely written in Rust (same speed as C/C++), (memory safe btw). This leaves the door open for the parser to become more or less as fast as we can go.

Also this type of setup makes it easy to create bindings for other languages (mainly R). Maybe in the future?

Special thank you to

Valve for "official" implementation https://github.com/ValveSoftware/csgo-demoinfo
Markuswa: Go parser: https://github.com/markus-wa/demoinfocs-golang
Saul: JS parser: https://github.com/saul/demofile
Akiver: Demos-Manager (really handy for quickly looking at demos) https://github.com/akiver/CSGO-Demos-Manager

You might also like...
Utilities for converting Vega-Lite specs from the command line and Python

VlConvert VlConvert provides a Rust library, CLI utility, and Python library for converting Vega-Lite chart specifications into static images (SVG or

Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

KVM memory R/W cheat for CSGO

CSGO KVM DMA Main Feature Triggerbot with random press/release time *TODO list: add method to detect key event in VM. add No recoil. add wallhack(

Demo app duplicated in 5 languages (Go/JavaScript/Python/Ruby/Rust) showing how to go from source code to container image using melange+apko

hello-melange-apko 💫 This repo contains an example app duplicated across 5 languages showing how to: Package source code into APKs using melange Buil

Yet Another Parser library for Rust. A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing strings and slices.

Yap: Yet another (rust) parsing library A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing input.

Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

A language parser tool to build recursive descent top down parser.

lang-pt A language parser tool to generate recursive descent top down parser. Overview Parsers written for the languages like Javascript are often cus

Python wrapper for Rust's httparse HTTP parser

httparse Python wrapper for Rust's httparse. See this project on GitHub. Example from httparse import RequestParser parser = RequestParser() buff =

Msgpack serialization/deserialization library for Python, written in Rust using PyO3, and rust-msgpack. Reboot of orjson. msgpack.org[Python]

ormsgpack ormsgpack is a fast msgpack library for Python. It is a fork/reboot of orjson It serializes faster than msgpack-python and deserializes a bi

Create a Python project automatically with rust (like create-react-app but for python)

create-python-project Create a Python project automatically with rust (like create-react-app but for python) Installation cargo install create-python-

Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better
Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

Create, open, manage your Python projects with ease, a project aimed to make python development experience a little better

Rust Imaging Library's Python binding: A performant and high-level image processing library for Python written in Rust

ril-py Rust Imaging Library for Python: Python bindings for ril, a performant and high-level image processing library written in Rust. What's this? Th

A Python CLI tool that finds all third-party packages imported into your Python project

python-third-party-imports This is a Python CLI tool built with Rust that finds all third-party packages imported into your Python project. Install Yo

Natural language detection library for Rust. Try demo online: https://www.greyblake.com/whatlang/
Natural language detection library for Rust. Try demo online: https://www.greyblake.com/whatlang/

Whatlang Natural language detection for Rust with focus on simplicity and performance. Content Features Get started Documentation Supported languages

A working demo of RustDesk server implementation

A working demo of RustDesk server implementation This is a super simple working demo implementation with only one relay connection allowed, without NA

Demo for the swash font library

Demo for the swash crate See the swash repo or crate for the actual project. This is a chunk of very rough code.

Basic Rust I2C demo on the TI Launchpad

msp430-i2c-oled-example An example project to talk to an SSD1306 OLED (Adafruit PiOLED) with an MSP430G2553 Launchpad via I2C.

Source code from Atlas, our 64k demo presented at Revision 2019 with Macau Exports

Atlas source code dump This is a dump of the source code for the engine, graphics tool and player for Atlas, our 64k demo released with Macau Exports

Demo Terraform Provider in Rust

terraform-provider-helloworld Welcome to a large pile of hacks masquerading as a PoC. This repository proves that it's possible to write a Terraform P

Comments
  • No attribute 'parse_ticks', possible Issues installing latest version

    No attribute 'parse_ticks', possible Issues installing latest version

    I was running into some issues running some of the examples. I was getting errors like.

    AttributeError: 'builtins.DemoParser' object has no attribute 'parse_ticks'

    But I then noticed the version of the package I was on was 0.1.0 when the latest appears to be 0.3.2. So I uninstalled an reinstalled demoparser.

    pip install demoparser
    Collecting demoparser
      Downloading demoparser-0.1.0.tar.gz (336 kB)
    

    But it just re-downloads the 0.10 version. So I tried to specify the latest version.

    pip install demoparser==0.3.2
    ERROR: Could not find a version that satisfies the requirement demoparser==0.3.2 (from versions: 0.1.0)
    ERROR: No matching distribution found for demoparser==0.3.2
    

    This appears to be mac specific. I am able to install the newest version just fine on a windows machine. I also see .whl files available for windows and linux. But none for macos.

    opened by DandrewsDev 2
  • Is it possible to get stats like ADR, MVPs, and other scoreboard items?

    Is it possible to get stats like ADR, MVPs, and other scoreboard items?

    I've looked through the examples and readme, didn't see any mention for querying those sort of built stats. My guess is that these are not available directly, but could be aggregated through a series of events. Like ADR, listening to an event for a player being damaged, getting the attacker info, getting the dmg delt, adding up total dmg for each player, and then at the end / by total rounds. But I wanted to see if there was some pre-built method for extracting data like that.

    opened by DandrewsDev 2
  • use the rust parser without python bindings?

    use the rust parser without python bindings?

    is there any way to utilize the rust parser natively within rust? i’m looking to learn rust and this seems like the only other rust demo parser i’ve found that’s not 5 years out of date. i realize it would be more difficult than just using the python bindings however im doing it specifically to try and teach myself some more rust

    opened by willjsaint 3
Owner
CS student @ University of Helsinki
null
Source code from Atlas, our 64k demo presented at Revision 2019 with Macau Exports

Atlas source code dump This is a dump of the source code for the engine, graphics tool and player for Atlas, our 64k demo released with Macau Exports

Monad 65 Jan 2, 2023
Small ray tracer demo of the F# to Rust language transpiler in Fable 4.x

Small ray tracer demo of the F# to Rust language transpiler in Fable 4.x

null 45 Nov 16, 2022
A parser for the perf.data format

linux-perf-data This repo contains a parser for the perf.data format which is output by the Linux perf tool. It also contains a main.rs which acts sim

Markus Stange 8 Dec 29, 2022
Texting Robots: A Rust native `robots.txt` parser with thorough unit testing

Texting Robots Crate texting_robots is a library for parsing robots.txt files. A key design goal of this crate is to have a thorough test suite tested

Stephen Merity 20 Aug 17, 2022
Extensible BBCode parser with scoping rules, auto close tags

More BBCode parsers? Yeah! I needed something highly extensible, flexible, and specifically WITH scoping rules so it always produces correct HTML. For

Carlos Sanchez 2 Dec 18, 2022
A minimal and fast zero-copy parser for the PE32+ file format.

peview A minimal and fast zero-copy parser for the PE32+ file format. Goal This project aims to offer a more light weight and easier to use alternativ

null 5 Dec 20, 2022
A parser for the .map file included in the aimware leak

a utility I wrote to parse the map file included with the recent aimware self-leak. there is also an IDAPython script to import the symbol information into IDA.

unknowntrojan 9 Feb 28, 2023
A fast uuid generator in Python using Rust

ruuid A fast UUID generator for Python built using Rust. Its a simple wrapper on top of Rust's UUID crate. How to use? Installation: pip3 install ruui

Rahul Nair 19 Jul 13, 2022
Write Anchor-compatible Solana programs in Python

seahorse: Write Solana programs in Python The ease of Python with the safety of Rust. Seahorse lets you write Solana programs in Python. It is a commu

✨ amelia chen ✨ 214 Dec 28, 2022
A Rust-powered linear programming library for Python.

Dantzig: A Rust-powered LP library for Python Dantzig is a lightweight and concise linear programming solver suitable for small and large-scale proble

Matteo Santamaria 4 Jan 10, 2023