npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

demofile

v2.10.0

Published

A node.js library for parsing Counter-Strike Global Offensive (CSGO) demo files. The library is also Browserify-able, and a standalone bundle that you can `<script src="...">` is available in [browser/bundle.js](browser/bundle.js).

Downloads

8,257

Readme

demofile npm CI

A node.js library for parsing Counter-Strike Global Offensive (CSGO) demo files. The library is also Browserify-able, and a standalone bundle that you can <script src="..."> is available in browser/bundle.js.

This library also supports streaming from GOTV broadcasts over HTTP, with DemoFile#parseBroadcast.

⚠️ This library requires Node v14 or later.

❓ Need help

Supported demo features

  • GOTV and POV perspective fully supported
  • Game events (e.g. player_death)
  • User messages (e.g. chat messages, HUD text)
  • Console variables (cvar/convars)
  • Entity updates, server classes, data tables
  • String tables
  • Reading encrypted messages (e.g. chat in public matchmaking demos)
  • Streaming from GOTV broadcasts over HTTP

Running the examples

Getting started is simple:

.../demofile$ npm ci
.../demofile$ cd examples
.../demofile/examples$ npm ci

You can now run the example scripts. Take a look in the examples folder for some scripts to try out. Detailed descriptions of these scripts can be found below in the Examples section below.

If you don't have any demo files to hand, use the demos/download.sh Bash script to download the ones used for testing.

.../demofile/examples$ npx ts-node dumpfile.ts ../demos/pc419-vs-chiefs-mirage.dem
npx: installed 14 in 1.883s
Demo header: {
  magic: 'HL2DEMO',
  protocol: 4,
  networkProtocol: 13753,
  serverName: 'Counter-Strike: Global Offensive',
  clientName: 'GOTV Demo',
  mapName: 'de_mirage',
  gameDirectory: 'csgo',
  playbackTime: 2569.375,
  playbackTicks: 328880,
  playbackFrames: 164271,
  signonLength: 433479
}
...

Installation

Node

npm install --save demofile

Browser

<script src="browser/bundle.js"></script>

The DemoFile module will be available as window.demofile.

Screenshot

Using the dumpfile example:

Example output

Documentation

Auto-generated API documentation is available at saul.github.io/demofile.

| Class | Description | | ----------------------------------------------------------------- | ----------------------------------- | | DemoFile | Represents a demo file for parsing. |

The DemoFile object has properties which point to instances of several other classes that can be used to inspect and listen to changes in the game world:

| Class | Property | Description | | ------------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------- | | ConVars | demoFile.conVars | Manages console variables. (Only FCVAR_NOTIFY and FCVAR_REPLICATED are available.) | | Entities | demoFile.entities | Represents entities and networked properties within a demo. | | GameEvents | demoFile.gameEvents | Manages game events for a demo file. (e.g. player_death, bomb_defused) | | StringTables | demoFile.stringTables | Handles string tables for a demo file. (e.g. userinfo) | | UserMessages | demoFile.userMessages | Handles user messages for a demo file. (e.g. SayText for in-game chat messages) |

There are several classes which allow access to different types of entities (e.g. players, items, props). These are summarised below:

| Entity | Usage | Description | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | Networkable | demoFile.entities.getByHandledemoFile.entities.entities.get(entIndex) | Base class of all in-game entities, even non-renderable entities (e.g. CCSTeam). | | BaseEntity | | Base class of the vast majority of in-game entities (e.g. players, weapons, all other renderable entities). | | Player | demoFile.entities.playersdemoFile.entities.getByUserId | Represents an in-game player. | | Team | demoFile.entities.teamsplayer.team | Represents a team (terrorists, counter-terrorists, spectators). | | Weapon | demoFile.entities.weaponsplayer.weaponplayer.weapons | Represents an in-game weapon (guns, grenades, knifes). | | Projectile | | Represents a thrown grenade projectile (e.g. a flying smoke grenade). | | GameRules | demoFile.gameRules | Represents the game rules and parts of the match state (e.g. round number, is warmup) |

API

This library provides full access to all data available in CSGO demo files. Unlike some other libraries, demofile is feature complete and supports the latest demos. As well as providing high-level APIs to access the state of the game, low-level access is available and is not discouraged.

Note that events are fired at the end of a tick, after all entity props and string tables have been updated.

Examples

Various examples are available in the examples folder:

| Example | Description | | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | join-leave.ts | Print all players that join and leave the game during the course of the demo. | | molotov.ts | Prints the location of molotov/incendiary grenade explosions. | | paintkits.ts | Collects paint kits of each weapon that is used in a kill. | | plant-site.ts | Prints which player planted the bomb and at which site. | | purchases.ts | Prints which items are purchased by each player. | | rank.ts | At the end of the game, prints all player ranks. | | scores.ts | Prints team scores after each round. | | tickrate.ts | Prints demo tick rate and duration in seconds. | | trajectory.ts | Prints grenade trajectories and who threw them. | | ⚠ Advanced: dumpfile.ts | Advanced example of recreating coloured chat messages, round scores and the kill feed. |

Print kills

const fs = require("fs");
const demofile = require("demofile");

const demoFile = new demofile.DemoFile();

demoFile.gameEvents.on("player_death", e => {
  const victim = demoFile.entities.getByUserId(e.userid);
  const victimName = victim ? victim.name : "unnamed";

  // Attacker may have disconnected so be aware.
  // e.g. attacker could have thrown a grenade, disconnected, then that grenade
  // killed another player.
  const attacker = demoFile.entities.getByUserId(e.attacker);
  const attackerName = attacker ? attacker.name : "unnamed";

  const headshotText = e.headshot ? " HS" : "";

  console.log(`${attackerName} [${e.weapon}${headshotText}] ${victimName}`);
});

demoFile.parseStream(fs.createReadStream("test.dem"));

/* Outputs:

HS [cz75a HS] flusha
Lekr0 [ak47 HS] friberg
KRIMZ [ak47] HS
JW [mac10 HS] Mixwell
JW [hegrenade] HS
JW [mac10 HS] Magisk

*/

Print player information when it changes

const fs = require("fs");
const demofile = require("demofile");

const demoFile = new demofile.DemoFile();

demoFile.stringTables.on("update", e => {
  if (e.table.name === "userinfo" && e.userData != null) {
    console.log("\nPlayer info updated:");
    console.log(e.entryIndex, e.userData);
  }
});

demoFile.parseStream(fs.createReadStream("test.dem"));

/* Outputs:

Player info updated:
0 {
  xuid: Long { low: 0, high: 0, unsigned: false },
  name: 'ESEA SourceTV',
  userId: 2,
  guid: 'BOT',
  friendsId: 0,
  friendsName: '',
  fakePlayer: true,
  isHltv: false
}

Player info updated:
1 {
  xuid: Long { low: 32578248, high: 17825793, unsigned: false },
  name: 'PC419 m0nt-S-',
  userId: 3,
  guid: 'STEAM_1:0:16289124',
  friendsId: 32578248,
  friendsName: '',
  fakePlayer: false,
  isHltv: false
}

[repeated for other players]
*/

Useful links

Contributing

Please read the Contributing Guidelines to learn how you can help out on the project.