demoinfocs

package module
v1.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 26, 2020 License: MIT Imports: 18 Imported by: 29

README

demoinfocs-golang - A CS:GO Demo Parser

Is a Go library for super fast parsing and analysing of Counter Strike: Global Offensive (CS:GO) demos (aka replays). It is based on Valve's demoinfogo and SatsHelix's demoinfo.

GoDoc Build Status codecov Go Report License FOSSA Status

Discussions / Chat

You can use gitter to ask questions and discuss ideas about this project.

Gitter chat

Requirements

This library is intended to be used with go 1.11 or higher as it is built using Go modules.

It's recommended to use modules for consumers as well if possible. If you are unfamiliar with Go modules there's a list of recommended resources in the wiki.

Go Get

go get -u github.com/markus-wa/demoinfocs-golang

Example

This is a simple example on how to handle game events using this library. It prints all kills in a given demo (killer, weapon, victim, was it a wallbang/headshot?) by registering a handler for events.Kill.

Check out the godoc of the events package for some information about the other available events and their purpose.

package main

import (
	"fmt"
	"os"

	dem "github.com/markus-wa/demoinfocs-golang"
	events "github.com/markus-wa/demoinfocs-golang/events"
)

func main() {
	f, err := os.Open("/path/to/demo.dem")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	p := dem.NewParser(f)

	// Register handler on kill events
	p.RegisterEventHandler(func(e events.Kill) {
		var hs string
		if e.IsHeadshot {
			hs = " (HS)"
		}
		var wallBang string
		if e.PenetratedObjects > 0 {
			wallBang = " (WB)"
		}
		fmt.Printf("%s <%v%s%s> %s\n", e.Killer, e.Weapon, hs, wallBang, e.Victim)
	})

	// Parse to end
	err = p.ParseToEnd()
	if err != nil {
		panic(err)
	}
}
Sample output

Running the code above will print something like this:

xms <AK-47 (HS)> crisby
tiziaN <USP-S (HS)> Ex6TenZ
tiziaN <USP-S> mistou
tiziaN <USP-S (HS)> ALEX
xms <Glock-18 (HS)> tiziaN
...
keev <AWP (HS) (WB)> to1nou
...
More examples

Check out the examples folder for more examples, like how to generate heatmaps like this one:

sample heatmap

Features

  • Game events (kills, shots, round starts/ends, footsteps etc.) - docs / example
  • Tracking of game-state (players, teams, grenades, ConVars etc.) - docs
  • Grenade projectiles / trajectories - docs / example
  • Access to entities, server-classes & data-tables - docs / example
  • Access to all net-messages - docs / example
  • Chat & console messages 1 - docs / example
  • POV demo support 2
  • Easy debugging via build-flags
  • Built with performance & concurrency in mind
  1. Only for some demos; in MM demos the chat is encrypted for example.
  2. Only partially supported (as good as other parsers), some POV demos seem to be inherently broken

Performance / Benchmarks

Two of the top priorities of this parser are performance and concurrency.

Here are some benchmark results from a system with an Intel i7 6700k CPU and a SSD disk running Windows 10 and a demo with 85'000 frames.

Overview
Benchmark Description Average Duration Speed
BenchmarkConcurrent Read and parse 8 demos concurrently 2.06 s (per 8 demos) ~330'000 ticks / s
BenchmarkDemoInfoCs Read demo from drive and parse 0.89 s ~95'000 ticks / s
BenchmarkInMemory Read demo from memory and parse 0.88 s ~96'000 ticks / s

That's almost 1.5 hours of gameplay per second when parsing in parallel (recorded at 64 ticks per second) - or 25 minues per second when only parsing a single demo at a time.

Raw output
$ go test -run _NONE_ -bench . -benchtime 30s -benchmem -concurrentdemos 8
goos: windows
goarch: amd64
pkg: github.com/markus-wa/demoinfocs-golang
BenchmarkDemoInfoCs-8             50     894500010 ns/op    257610127 B/op    914355 allocs/op
BenchmarkInMemory-8               50     876279984 ns/op    257457271 B/op    914143 allocs/op
BenchmarkConcurrent-8             20    2058303680 ns/op    2059386582 B/op  7313145 allocs/op
--- BENCH: BenchmarkConcurrent-8
    demoinfocs_test.go:315: Running concurrency benchmark with 8 demos
    demoinfocs_test.go:315: Running concurrency benchmark with 8 demos
PASS
ok      github.com/markus-wa/demoinfocs-golang  134.244s

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository. There is one caveat however: Beta features - which are marked as such via comments and in release notes - may change in minor releases.

Projects using demoinfocs-golang

If your project is using this library feel free to submit a PR or send a message in Gitter to be included in the list.

Development

Git hooks

To install some (optional, but quite handy) pre-commit and pre-push hooks, you can run the following script.

bin/git-hooks/link-git-hooks.sh
pre-commit:
pre-push:
  • run regression tests
Testing
Unit tests

For any new features, Test Driven Development should be practiced where possible. However, due to some design flaws in some parts of the code it's currently not always practical to do so.

Running unit tests:

bin/unit-tests.sh
# or (identical)
go test -short ./...
Regression tests

For the full regression suite you will need to download the test demo-set.

Prerequisites:

  • Git LFS must be installed
  • 7z must be in your PATH environment variable (p7zip or p7zip-full package on most Linux distros)

Downloading demos + running regression tests:

bin/regression-tests.sh
Updating the default.golden file

The file test/default.golden file contains a serialized output of all expected game events in test/cs-demos/default.dem.

If there is a change to game events (new fields etc.) it is necessary to update this file so the regression tests pass. To update it you can run the following command:

go test -run TestDemoInfoCs -update

Please don't update the .golden file if you are not sure it's required. Maybe the failing CI is just pointing out a regression.

Debugging

You can use the build tag debugdemoinfocs (i.e. go test -tags debugdemoinfocs -v) to print out debugging information - such as game events or unhandled demo-messages - during the parsing process.
Side-note: The tag isn't called debug to avoid naming conflicts with other libs (and underscores in tags don't work, apparently).

To change the default debugging behavior, Go's ldflags parameter can be used. Example for additionally printing out all server-classes with their properties: -ldflags '-X github.com/markus-wa/demoinfocs-golang.debugServerClasses=YES'

Check out debug_on.go for any other settings that can be changed.

Generating interfaces

We generate interfaces such as IGameState from structs to make it easier to keep docs in synch over structs and interfaces. For this we use @vburenin's ifacemaker tool.

You can download the latest version here. After adding it to your PATH you can use bin/generate-interfaces.sh to update interfaces.

Generating protobuf code

Should you need to re-generate the protobuf generated code in the msg package, you will need the following tools:

Make sure both are inside your PATH variable.

After installing these use go generate ./msg to generate the protobuf code. If you're on Windows you'll need to run go generate from CMD, not Bash.

Acknowledgements

Thanks to @JetBrains for sponsoring a license of their awesome GoLand IDE for this project - go check it out!

And a very special thanks goes out to all the ⭐️contributors⭐️, be it in the form of PRs, issues or anything else.

License

This project is licensed under the MIT license.

FOSSA Status

Documentation

Overview

Package demoinfocs provides a demo parser for the game Counter-Strike: Global Offensive. It is based on the official demoinfogo tool by Valve as well as Stats Helix's demoinfo.

A good entry point to using the library is the Parser type.

Demo events are documented in the events package.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrCancelled signals that parsing was cancelled via Parser.Cancel()
	ErrCancelled = errors.New("parsing was cancelled before it finished (ErrCancelled)")

	// ErrUnexpectedEndOfDemo signals that the demo is incomplete / corrupt -
	// these demos may still be useful, check how far the parser got.
	ErrUnexpectedEndOfDemo = errors.New("demo stream ended unexpectedly (ErrUnexpectedEndOfDemo)")

	// ErrInvalidFileType signals that the input isn't a valid CS:GO demo.
	ErrInvalidFileType = errors.New("invalid File-Type; expecting HL2DEMO in the first 8 bytes (ErrInvalidFileType)")
)

Parsing errors

View Source
var DefaultParserConfig = ParserConfig{
	MsgQueueBufferSize: -1,
}

DefaultParserConfig is the default Parser configuration used by NewParser().

Functions

This section is empty.

Types

type GameState added in v0.4.0

type GameState struct {
	// contains filtered or unexported fields
}

GameState contains all game-state relevant information.

func (GameState) Bomb added in v1.0.0

func (gs GameState) Bomb() *common.Bomb

Bomb returns the current bomb state.

func (*GameState) ConVars added in v1.3.0

func (gs *GameState) ConVars() map[string]string

ConVars returns a map of CVar keys and values. Not all values might be set. See also: https://developer.valvesoftware.com/wiki/List_of_CS:GO_Cvars.

func (GameState) Entities added in v1.0.0

func (gs GameState) Entities() map[int]*st.Entity

Entities returns all currently existing entities. (Almost?) everything in the game is an entity, such as weapons, players, fire etc.

func (GameState) GamePhase added in v1.3.0

func (gs GameState) GamePhase() common.GamePhase

GamePhase returns the game phase of the current game state. See common/gamerules.go for more.

func (GameState) GrenadeProjectiles added in v0.5.4

func (gs GameState) GrenadeProjectiles() map[int]*common.GrenadeProjectile

GrenadeProjectiles returns a map from entity-IDs to all live grenade projectiles.

Only constains projectiles currently in-flight or still active (smokes etc.), i.e. have been thrown but have yet to detonate.

func (GameState) Infernos added in v1.0.0

func (gs GameState) Infernos() map[int]*common.Inferno

Infernos returns a map from entity-IDs to all currently burning infernos (fires from incendiaries and Molotovs).

func (GameState) IngameTick added in v0.4.0

func (gs GameState) IngameTick() int

IngameTick returns the latest actual tick number of the server during the game.

Watch out, I've seen this return wonky negative numbers at the start of demos.

func (GameState) IsMatchStarted added in v1.0.0

func (gs GameState) IsMatchStarted() bool

IsMatchStarted returns whether the match has started according to CCSGameRulesProxy.

func (GameState) IsWarmupPeriod added in v1.0.0

func (gs GameState) IsWarmupPeriod() bool

IsWarmupPeriod returns whether the game is currently in warmup period according to CCSGameRulesProxy.

func (GameState) Participants added in v0.4.0

func (gs GameState) Participants() IParticipants

Participants returns a struct with all currently connected players & spectators and utility functions. The struct contains references to the original maps so it's always up-to-date.

func (*GameState) Team added in v1.0.0

func (gs *GameState) Team(team common.Team) *common.TeamState

Team returns the TeamState corresponding to team. Returns nil if team != TeamTerrorists && team != TeamCounterTerrorists.

Make sure to handle swapping sides properly if you keep the reference.

func (*GameState) TeamCounterTerrorists added in v1.0.0

func (gs *GameState) TeamCounterTerrorists() *common.TeamState

TeamCounterTerrorists returns the TeamState of the CT team.

Make sure to handle swapping sides properly if you keep the reference.

func (*GameState) TeamTerrorists added in v1.0.0

func (gs *GameState) TeamTerrorists() *common.TeamState

TeamTerrorists returns the TeamState of the T team.

Make sure to handle swapping sides properly if you keep the reference.

func (GameState) TotalRoundsPlayed added in v1.0.0

func (gs GameState) TotalRoundsPlayed() int

TotalRoundsPlayed returns the amount of total rounds played according to CCSGameRulesProxy.

func (GameState) Weapons added in v1.9.0

func (gs GameState) Weapons() map[int]*common.Equipment

Weapons returns a map from entity-IDs to all weapons currently in the game.

type IGameState added in v1.0.0

type IGameState interface {
	// IngameTick returns the latest actual tick number of the server during the game.
	//
	// Watch out, I've seen this return wonky negative numbers at the start of demos.
	IngameTick() int
	// Team returns the TeamState corresponding to team.
	// Returns nil if team != TeamTerrorists && team != TeamCounterTerrorists.
	//
	// Make sure to handle swapping sides properly if you keep the reference.
	Team(team common.Team) *common.TeamState
	// TeamCounterTerrorists returns the TeamState of the CT team.
	//
	// Make sure to handle swapping sides properly if you keep the reference.
	TeamCounterTerrorists() *common.TeamState
	// TeamTerrorists returns the TeamState of the T team.
	//
	// Make sure to handle swapping sides properly if you keep the reference.
	TeamTerrorists() *common.TeamState
	// Participants returns a struct with all currently connected players & spectators and utility functions.
	// The struct contains references to the original maps so it's always up-to-date.
	Participants() IParticipants
	// GrenadeProjectiles returns a map from entity-IDs to all live grenade projectiles.
	//
	// Only constains projectiles currently in-flight or still active (smokes etc.),
	// i.e. have been thrown but have yet to detonate.
	GrenadeProjectiles() map[int]*common.GrenadeProjectile
	// Infernos returns a map from entity-IDs to all currently burning infernos (fires from incendiaries and Molotovs).
	Infernos() map[int]*common.Inferno
	// Weapons returns a map from entity-IDs to all weapons currently in the game.
	Weapons() map[int]*common.Equipment
	// Entities returns all currently existing entities.
	// (Almost?) everything in the game is an entity, such as weapons, players, fire etc.
	Entities() map[int]*st.Entity
	// Bomb returns the current bomb state.
	Bomb() *common.Bomb
	// TotalRoundsPlayed returns the amount of total rounds played according to CCSGameRulesProxy.
	TotalRoundsPlayed() int
	// GamePhase returns the game phase of the current game state. See common/gamerules.go for more.
	GamePhase() common.GamePhase
	// IsWarmupPeriod returns whether the game is currently in warmup period according to CCSGameRulesProxy.
	IsWarmupPeriod() bool
	// IsMatchStarted returns whether the match has started according to CCSGameRulesProxy.
	IsMatchStarted() bool
	// ConVars returns a map of CVar keys and values.
	// Not all values might be set.
	// See also: https://developer.valvesoftware.com/wiki/List_of_CS:GO_Cvars.
	ConVars() map[string]string
}

IGameState is an auto-generated interface for GameState. GameState contains all game-state relevant information.

type IParser added in v1.0.0

type IParser interface {
	// ServerClasses returns the server-classes of this demo.
	// These are available after events.DataTablesParsed has been fired.
	ServerClasses() st.ServerClasses
	// Header returns the DemoHeader which contains the demo's metadata.
	// Only possible after ParserHeader() has been called.
	Header() common.DemoHeader
	// GameState returns the current game-state.
	// It contains most of the relevant information about the game such as players, teams, scores, grenades etc.
	GameState() IGameState
	// CurrentFrame return the number of the current frame, aka. 'demo-tick' (Since demos often have a different tick-rate than the game).
	// Starts with frame 0, should go up to DemoHeader.PlaybackFrames but might not be the case (usually it's just close to it).
	CurrentFrame() int
	// CurrentTime returns the time elapsed since the start of the demo
	CurrentTime() time.Duration
	// TickRate returns the tick-rate the server ran on during the game.
	TickRate() float64
	// TickTime returns the time a single tick takes in seconds.
	TickTime() time.Duration
	// Progress returns the parsing progress from 0 to 1.
	// Where 0 means nothing has been parsed yet and 1 means the demo has been parsed to the end.
	//
	// Might not be 100% correct since it's just based on the reported tick count of the header.
	// May always return 0 if the demo header is corrupt.
	Progress() float32
	/*
	   RegisterEventHandler registers a handler for game events.

	   The handler must be of type func(<EventType>) where EventType is the kind of event to be handled.
	   To catch all events func(interface{}) can be used.

	   Example:

	   	parser.RegisterEventHandler(func(e events.WeaponFired) {
	   		fmt.Printf("%s fired his %s\n", e.Shooter.Name, e.Weapon.Weapon)
	   	})

	   Parameter handler has to be of type interface{} because lolnogenerics.

	   Returns a identifier with which the handler can be removed via UnregisterEventHandler().
	*/
	RegisterEventHandler(handler interface{}) dp.HandlerIdentifier
	// UnregisterEventHandler removes a game event handler via identifier.
	//
	// The identifier is returned at registration by RegisterEventHandler().
	UnregisterEventHandler(identifier dp.HandlerIdentifier)
	/*
	   RegisterNetMessageHandler registers a handler for net-messages.

	   The handler must be of type func(*<MessageType>) where MessageType is the kind of net-message to be handled.

	   Returns a identifier with which the handler can be removed via UnregisterNetMessageHandler().

	   See also: RegisterEventHandler()
	*/
	RegisterNetMessageHandler(handler interface{}) dp.HandlerIdentifier
	// UnregisterNetMessageHandler removes a net-message handler via identifier.
	//
	// The identifier is returned at registration by RegisterNetMessageHandler().
	UnregisterNetMessageHandler(identifier dp.HandlerIdentifier)
	// ParseHeader attempts to parse the header of the demo and returns it.
	// If not done manually this will be called by Parser.ParseNextFrame() or Parser.ParseToEnd().
	//
	// Returns ErrInvalidFileType if the filestamp (first 8 bytes) doesn't match HL2DEMO.
	ParseHeader() (common.DemoHeader, error)
	// ParseToEnd attempts to parse the demo until the end.
	// Aborts and returns ErrCancelled if Cancel() is called before the end.
	//
	// See also: ParseNextFrame() for other possible errors.
	ParseToEnd() (err error)
	// Cancel aborts ParseToEnd().
	// All information that was already read up to this point may still be used (and new events may still be sent out).
	Cancel()
	/*
	   ParseNextFrame attempts to parse the next frame / demo-tick (not ingame tick).

	   Returns true unless the demo command 'stop' or an error was encountered.

	   May return ErrUnexpectedEndOfDemo for incomplete / corrupt demos.
	   May panic if the demo is corrupt in some way.

	   See also: ParseToEnd() for parsing the complete demo in one go (faster).
	*/
	ParseNextFrame() (moreFrames bool, err error)
}

IParser is an auto-generated interface for Parser, intended to be used when mockability is needed. Parser can parse a CS:GO demo. Creating a new instance is done via NewParser().

To start off you may use Parser.ParseHeader() to parse the demo header (this can be skipped and will be done automatically if necessary). Further, Parser.ParseNextFrame() and Parser.ParseToEnd() can be used to parse the demo.

Use Parser.RegisterEventHandler() to receive notifications about events.

Example (without error handling):

f, _ := os.Open("/path/to/demo.dem")
p := dem.NewParser(f)
header := p.ParseHeader()
fmt.Println("Map:", header.MapName)
p.RegisterEventHandler(func(e events.BombExplode) {
	fmt.Printf(e.Site, "went BOOM!")
})
p.ParseToEnd()

Prints out '{A/B} site went BOOM!' when a bomb explodes.

type IParticipants added in v1.0.0

type IParticipants interface {
	// ByUserID returns all currently connected players in a map where the key is the user-ID.
	// The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map).
	// Includes spectators.
	ByUserID() map[int]*common.Player
	// ByEntityID returns all currently connected players in a map where the key is the entity-ID.
	// The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map).
	// Includes spectators.
	ByEntityID() map[int]*common.Player
	// AllByUserID returns all currently known players & spectators, including disconnected ones,
	// in a map where the key is the user-ID.
	// The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map).
	// Includes spectators.
	AllByUserID() map[int]*common.Player
	// All returns all currently known players & spectators, including disconnected ones, of the demo.
	// The returned slice is a snapshot and is not updated on changes.
	All() []*common.Player
	// Connected returns all currently connected players & spectators.
	// The returned slice is a snapshot and is not updated on changes.
	Connected() []*common.Player
	// Playing returns all players that aren't spectating or unassigned.
	// The returned slice is a snapshot and is not updated on changes.
	Playing() []*common.Player
	// TeamMembers returns all players belonging to the requested team at this time.
	// The returned slice is a snapshot and is not updated on changes.
	TeamMembers(team common.Team) []*common.Player
	// FindByHandle attempts to find a player by his entity-handle.
	// The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.
	//
	// Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
	FindByHandle(handle int) *common.Player
	// SpottersOf returns a list of all players who have spotted the passed player.
	SpottersOf(spotted *common.Player) (spotters []*common.Player)
	// SpottedBy returns a list of all players that the passed player has spotted.
	SpottedBy(spotter *common.Player) (spotted []*common.Player)
}

IParticipants is an auto-generated interface for Participants. Participants provides helper functions on top of the currently connected players. E.g. ByUserID(), ByEntityID(), TeamMembers(), etc.

See GameState.Participants()

type NetMessageCreator added in v0.5.0

type NetMessageCreator func() proto.Message

NetMessageCreator creates additional net-messages to be dispatched to net-message handlers.

See also: ParserConfig.AdditionalNetMessageCreators & Parser.RegisterNetMessageHandler()

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser can parse a CS:GO demo. Creating a new instance is done via NewParser().

To start off you may use Parser.ParseHeader() to parse the demo header (this can be skipped and will be done automatically if necessary). Further, Parser.ParseNextFrame() and Parser.ParseToEnd() can be used to parse the demo.

Use Parser.RegisterEventHandler() to receive notifications about events.

Example (without error handling):

f, _ := os.Open("/path/to/demo.dem")
p := dem.NewParser(f)
header := p.ParseHeader()
fmt.Println("Map:", header.MapName)
p.RegisterEventHandler(func(e events.BombExplode) {
	fmt.Printf(e.Site, "went BOOM!")
})
p.ParseToEnd()

Prints out '{A/B} site went BOOM!' when a bomb explodes.

Example

This will print all kills of a demo in the format '[[killer]] <[[weapon]] [(HS)] [(WB)]> [[victim]]'

noinspection GoUnhandledErrorResult

package main

import (
	"fmt"
	"os"

	dem "github.com/markus-wa/demoinfocs-golang"
	"github.com/markus-wa/demoinfocs-golang/events"
)

func main() {
	f, err := os.Open("test/cs-demos/default.dem")
	if err != nil {
		panic(err)
	}
	defer f.Close()

	p := dem.NewParser(f)

	// Register handler on kill events
	p.RegisterEventHandler(func(e events.Kill) {
		var hs string
		if e.IsHeadshot {
			hs = " (HS)"
		}
		var wallBang string
		if e.PenetratedObjects > 0 {
			wallBang = " (WB)"
		}
		fmt.Printf("%s <%v%s%s> %s\n", e.Killer, e.Weapon, hs, wallBang, e.Victim)
	})

	// Parse to end
	err = p.ParseToEnd()
	if err != nil {
		panic(err)
	}
}
Output:

func NewParser

func NewParser(demostream io.Reader) *Parser

NewParser creates a new Parser with the default configuration. The demostream io.Reader (e.g. os.File or bytes.Reader) must provide demo data in the '.DEM' format.

See also: NewCustomParser() & DefaultParserConfig

func NewParserWithConfig added in v0.5.0

func NewParserWithConfig(demostream io.Reader, config ParserConfig) *Parser

NewParserWithConfig returns a new Parser with a custom configuration.

See also: NewParser() & ParserConfig

func (*Parser) Cancel

func (p *Parser) Cancel()

Cancel aborts ParseToEnd(). All information that was already read up to this point may still be used (and new events may still be sent out).

func (*Parser) CurrentFrame

func (p *Parser) CurrentFrame() int

CurrentFrame return the number of the current frame, aka. 'demo-tick' (Since demos often have a different tick-rate than the game). Starts with frame 0, should go up to DemoHeader.PlaybackFrames but might not be the case (usually it's just close to it).

func (*Parser) CurrentTime

func (p *Parser) CurrentTime() time.Duration

CurrentTime returns the time elapsed since the start of the demo

func (*Parser) GameState added in v0.4.0

func (p *Parser) GameState() IGameState

GameState returns the current game-state. It contains most of the relevant information about the game such as players, teams, scores, grenades etc.

func (*Parser) Header added in v0.2.0

func (p *Parser) Header() common.DemoHeader

Header returns the DemoHeader which contains the demo's metadata. Only possible after ParserHeader() has been called.

func (*Parser) ParseHeader

func (p *Parser) ParseHeader() (common.DemoHeader, error)

ParseHeader attempts to parse the header of the demo and returns it. If not done manually this will be called by Parser.ParseNextFrame() or Parser.ParseToEnd().

Returns ErrInvalidFileType if the filestamp (first 8 bytes) doesn't match HL2DEMO.

func (*Parser) ParseNextFrame

func (p *Parser) ParseNextFrame() (moreFrames bool, err error)

ParseNextFrame attempts to parse the next frame / demo-tick (not ingame tick).

Returns true unless the demo command 'stop' or an error was encountered.

May return ErrUnexpectedEndOfDemo for incomplete / corrupt demos. May panic if the demo is corrupt in some way.

See also: ParseToEnd() for parsing the complete demo in one go (faster).

func (*Parser) ParseToEnd

func (p *Parser) ParseToEnd() (err error)

ParseToEnd attempts to parse the demo until the end. Aborts and returns ErrCancelled if Cancel() is called before the end.

See also: ParseNextFrame() for other possible errors.

func (*Parser) Progress

func (p *Parser) Progress() float32

Progress returns the parsing progress from 0 to 1. Where 0 means nothing has been parsed yet and 1 means the demo has been parsed to the end.

Might not be 100% correct since it's just based on the reported tick count of the header. May always return 0 if the demo header is corrupt.

func (*Parser) RegisterEventHandler

func (p *Parser) RegisterEventHandler(handler interface{}) dp.HandlerIdentifier

RegisterEventHandler registers a handler for game events.

The handler must be of type func(<EventType>) where EventType is the kind of event to be handled. To catch all events func(interface{}) can be used.

Example:

parser.RegisterEventHandler(func(e events.WeaponFired) {
	fmt.Printf("%s fired his %s\n", e.Shooter.Name, e.Weapon.Weapon)
})

Parameter handler has to be of type interface{} because lolnogenerics.

Returns a identifier with which the handler can be removed via UnregisterEventHandler().

func (*Parser) RegisterNetMessageHandler added in v0.5.0

func (p *Parser) RegisterNetMessageHandler(handler interface{}) dp.HandlerIdentifier

RegisterNetMessageHandler registers a handler for net-messages.

The handler must be of type func(*<MessageType>) where MessageType is the kind of net-message to be handled.

Returns a identifier with which the handler can be removed via UnregisterNetMessageHandler().

See also: RegisterEventHandler()

func (*Parser) ServerClasses added in v1.0.0

func (p *Parser) ServerClasses() st.ServerClasses

ServerClasses returns the server-classes of this demo. These are available after events.DataTablesParsed has been fired.

func (*Parser) TickRate added in v1.8.0

func (p *Parser) TickRate() float64

TickRate returns the tick-rate the server ran on during the game.

func (*Parser) TickTime added in v1.8.0

func (p *Parser) TickTime() time.Duration

TickTime returns the time a single tick takes in seconds.

func (*Parser) UnregisterEventHandler added in v0.4.0

func (p *Parser) UnregisterEventHandler(identifier dp.HandlerIdentifier)

UnregisterEventHandler removes a game event handler via identifier.

The identifier is returned at registration by RegisterEventHandler().

func (*Parser) UnregisterNetMessageHandler added in v0.5.0

func (p *Parser) UnregisterNetMessageHandler(identifier dp.HandlerIdentifier)

UnregisterNetMessageHandler removes a net-message handler via identifier.

The identifier is returned at registration by RegisterNetMessageHandler().

type ParserConfig added in v0.5.0

type ParserConfig struct {
	// MsgQueueBufferSize defines the size of the internal net-message queue.
	// For large demos, fast i/o and slow CPUs higher numbers are suggested and vice versa.
	// The buffer size can easily be in the hundred-thousands to low millions for the best performance.
	// A negative value will make the Parser automatically decide the buffer size during ParseHeader()
	// based on the number of ticks in the demo (nubmer of ticks = buffer size);
	// this is the default behavior for DefaultParserConfig.
	// Zero enforces sequential parsing.
	MsgQueueBufferSize int

	// AdditionalNetMessageCreators maps net-message-IDs to creators (instantiators).
	// The creators should return a new instance of the correct protobuf-message type (from the msg package).
	// Interesting net-message-IDs can easily be discovered with the build-tag 'debugdemoinfocs'; when looking for 'UnhandledMessage'.
	// Check out parsing.go to see which net-messages are already being parsed by default.
	// This is a beta feature and may be changed or replaced without notice.
	AdditionalNetMessageCreators map[int]NetMessageCreator
}

ParserConfig contains the configuration for creating a new Parser.

type Participants added in v1.0.0

type Participants struct {
	// contains filtered or unexported fields
}

Participants provides helper functions on top of the currently connected players. E.g. ByUserID(), ByEntityID(), TeamMembers(), etc.

See GameState.Participants()

func (Participants) All added in v1.0.0

func (ptcp Participants) All() []*common.Player

All returns all currently known players & spectators, including disconnected ones, of the demo. The returned slice is a snapshot and is not updated on changes.

func (Participants) AllByUserID added in v1.7.0

func (ptcp Participants) AllByUserID() map[int]*common.Player

AllByUserID returns all currently known players & spectators, including disconnected ones, in a map where the key is the user-ID. The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map). Includes spectators.

func (Participants) ByEntityID added in v1.0.0

func (ptcp Participants) ByEntityID() map[int]*common.Player

ByEntityID returns all currently connected players in a map where the key is the entity-ID. The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map). Includes spectators.

func (Participants) ByUserID added in v1.0.0

func (ptcp Participants) ByUserID() map[int]*common.Player

ByUserID returns all currently connected players in a map where the key is the user-ID. The returned map is a snapshot and is not updated on changes (not a reference to the actual, underlying map). Includes spectators.

func (Participants) Connected added in v1.1.0

func (ptcp Participants) Connected() []*common.Player

Connected returns all currently connected players & spectators. The returned slice is a snapshot and is not updated on changes.

func (Participants) FindByHandle added in v1.0.0

func (ptcp Participants) FindByHandle(handle int) *common.Player

FindByHandle attempts to find a player by his entity-handle. The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.

Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).

func (Participants) Playing added in v1.0.0

func (ptcp Participants) Playing() []*common.Player

Playing returns all players that aren't spectating or unassigned. The returned slice is a snapshot and is not updated on changes.

func (Participants) SpottedBy added in v1.2.0

func (ptcp Participants) SpottedBy(spotter *common.Player) (spotted []*common.Player)

SpottedBy returns a list of all players that the passed player has spotted.

func (Participants) SpottersOf added in v1.2.0

func (ptcp Participants) SpottersOf(spotted *common.Player) (spotters []*common.Player)

SpottersOf returns a list of all players who have spotted the passed player.

func (Participants) TeamMembers added in v1.0.0

func (ptcp Participants) TeamMembers(team common.Team) []*common.Player

TeamMembers returns all players belonging to the requested team at this time. The returned slice is a snapshot and is not updated on changes.

Directories

Path Synopsis
Package bitread provides a wrapper for github.com/markus-wa/gobitread with CS:GO demo parsing specific helpers.
Package bitread provides a wrapper for github.com/markus-wa/gobitread with CS:GO demo parsing specific helpers.
Package common contains common types, constants and functions used over different demoinfocs packages.
Package common contains common types, constants and functions used over different demoinfocs packages.
Package events contains all events that can be sent out from demoinfocs.Parser.
Package events contains all events that can be sent out from demoinfocs.Parser.
Package fake provides basic mocks for IParser, IGameState and IParticipants.
Package fake provides basic mocks for IParser, IGameState and IParticipants.
Package metadata provides metadata and utility functions, like translations from ingame coordinates to radar image pixels.
Package metadata provides metadata and utility functions, like translations from ingame coordinates to radar image pixels.
Package msg contains the generated protobuf demo message code.
Package msg contains the generated protobuf demo message code.
Package sendtables contains sendtable specific magic and should really be better documented (TODO).
Package sendtables contains sendtable specific magic and should really be better documented (TODO).
fake
Package fake provides basic mocks for IEntity and IProperty.
Package fake provides basic mocks for IEntity and IProperty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL