nevrcap

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2025 License: MIT Imports: 16 Imported by: 2

README

nevrcap

High-performance telemetry processing and streaming library for NEVR lobby session data.

Overview

This package provides optimized processing of game session frames with support for:

  • High-frequency frame processing
  • Event detection between consecutive frames
  • Multiple streaming codecs (.nevrcap, .echoreplay, WebSocket)
  • File format conversion utilities

Installation

go get github.com/echotools/nevrcap

Building

Manual build steps:

# Download dependencies
go mod download
go mod tidy

# Build the library
make all

# Run tests
go test -v ./...

# Run benchmarks
go test -bench=. -benchmem

Usage

Frame Processing
import "github.com/echotools/nevrcap"

// Create processor
processor := nevrcap.NewFrameProcessor()

// Process raw game data
frame, err := processor.ProcessFrame(sessionData, userBonesData, timestamp)
if err != nil {
    log.Fatal(err)
}

// Events are automatically detected
fmt.Printf("Detected %d events in frame %d\n", len(frame.Events), frame.FrameIndex)
Streaming Codecs
Zstd Codec (.nevrcap files)
// Writing
writer, err := nevrcap.NewZstdCodecWriter("capture.nevrcap")
if err != nil {
    log.Fatal(err)
}
defer writer.Close()

// Write header
header := &rtapi.TelemetryHeader{
    CaptureId: uuid.Must(uuiid.NewV4()),
    CreatedAt: timestamppb.Now(),
}
err = writer.WriteHeader(header)
if err != nil {
    log.Fatal(err)
}

// Write frames
err = writer.WriteFrame(frame)
if err != nil {
    log.Fatal(err)
}

// Reading
reader, err := nevrcap.NewZstdCodecReader("capture.nevrcap")
if err != nil {
    log.Fatal(err)
}
defer reader.Close()

header, err := reader.ReadHeader()
if err != nil {
    log.Fatal(err)
}

frame, err := reader.ReadFrame()
if err != nil {
    log.Fatal(err)
}
EchoReplay Codec (.echoreplay files)
// Reading
reader, err := nevrcap.NewEchoReplayFileReader("replay.echoreplay")
if err != nil {
    log.Fatal(err)
}
defer reader.Close()

frames, err := reader.ReadFrames()
if err != nil {
    log.Fatal(err)
}
File Conversion
// Convert .echoreplay to .nevrcap
err := nevrcap.ConvertEchoReplayToNevrcap("input.echoreplay", "output.nevrcap")

// Convert .nevrcap to .echoreplay  
err := nevrcap.ConvertNevrcapToEchoReplay("input.nevrcap", "output.echoreplay")

Event Detection

The system automatically detects various game events:

Game State Events
  • Round started/ended
  • Match ended
  • Scoreboard updates
  • Game paused/unpaused
Player Events
  • Player joined/left
  • Team switches
  • Emote playing
Disc Events
  • Possession changes
  • Disc thrown/caught
Stat Events
  • Saves, stuns, passes
  • Catches, steals, blocks
  • Interceptions, assists
  • Shots taken

File Formats

.nevrcap Format
  • Compression: Zstd
  • Serialization: Protocol Buffers
  • Structure: Header + length-delimited frames
  • Features: Event detection, streaming support
  • Size: ~57% of .echoreplay size
.echoreplay Format
  • Compression: ZIP
  • Serialization: JSON
  • Structure: ZIP archive with replay.txt
  • Features: Legacy compatibility
  • Size: Baseline reference

Benchmarks

Run benchmarks:

go test -bench=. -benchmem

Quick benchmark (just frame processing):

go test -bench=BenchmarkFrameProcessing -benchtime=1s

See BENCHMARKS.md for detailed performance metrics.

Optimization Features

  1. Pre-allocated Structures: Reuses objects to minimize GC pressure
  2. Efficient Event Detection: O(1) player lookups using maps
  3. Streaming Support: Processes data incrementally
  4. High-Performance Compression: Zstd provides optimal speed/size ratio
  5. Memory Pooling: Minimal allocations for high-frequency operations

Contributing

When adding new event types:

  1. Update protobuf definitions in nevr-common/proto/rtapi/telemetry_v1.proto
  2. Regenerate protobuf code: go generate or ./scripts/build.sh
  3. Add detection logic in events.go
  4. Add tests in *_test.go files
  5. Update benchmarks if needed
  6. Run the full test suite: go test -v ./...

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrCodecNotConfiguredForWriting = fmt.Errorf("codec not configured for writing")

	EchoReplayTimeFormat = "2006/01/02 15:04:05.000"
)

Functions

func BatchConvert

func BatchConvert(sourcePattern, targetDir string, toNevrcap bool) error

BatchConvert converts multiple files

func ConvertEchoReplayToNevrcap

func ConvertEchoReplayToNevrcap(echoReplayPath, nevrcapPath string) error

ConvertEchoReplayToNevrcap converts a .echoreplay file to a .nevrcap file

func ConvertNevrcapToEchoReplay

func ConvertNevrcapToEchoReplay(nevrcapPath, echoReplayPath string) error

ConvertNevrcapToEchoReplay converts a .nevrcap file to a .echoreplay file

func ConvertUncompressedEchoReplayToNevrcap

func ConvertUncompressedEchoReplayToNevrcap(echoReplayPath, nevrcapPath string) error

ConvertUncompressedEchoReplayToNevrcap converts with optimizations for benchmarking

Types

type DiscState

type DiscState struct {
	HasPossession bool
	PlayerSlot    int32 // -1 if no player has possession
}

DiscState represents disc possession state

type EchoReplayCodec

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

EchoReplayCodec handles .echoreplay file format (zip format)

Example

ExampleEchoReplayCodec demonstrates how to use the optimized codec

// Create a new codec for writing
codec, err := NewEchoReplayCodecWriter("example_optimized.echoreplay")
if err != nil {
	fmt.Printf("Error creating codec: %v\n", err)
	return
}
defer codec.Close()

// Write some frames
for i := 0; i < 1000; i++ {
	frame := &rtapi.LobbySessionStateFrame{
		Timestamp: timestamppb.New(time.Now().Add(time.Duration(i) * time.Millisecond)),
		Session: &apigame.SessionResponse{
			SessionId: uuid.Must(uuid.NewV4()).String(),
		},
	}

	if err := codec.WriteFrame(frame); err != nil {
		fmt.Printf("Error writing frame: %v\n", err)
		return
	}

	// Check buffer size periodically
	if i%100 == 0 {
		fmt.Printf("Buffer size after %d frames: %d bytes\n", i+1, codec.GetBufferSize())
	}
}

fmt.Printf("Final buffer size: %d bytes\n", codec.GetBufferSize())

// Cleanup
os.Remove("example_optimized.echoreplay")
fmt.Println("Optimized codec example completed successfully")

func NewEchoReplayCodecWriter

func NewEchoReplayCodecWriter(filename string) (*EchoReplayCodec, error)

NewEchoReplayCodecWriter creates a new EchoReplay codec for writing

func NewEchoReplayFileReader

func NewEchoReplayFileReader(filename string) (*EchoReplayCodec, error)

NewEchoReplayFileReader creates a new EchoReplay codec for reading

func (*EchoReplayCodec) Close

func (e *EchoReplayCodec) Close() error

Close closes the codec and underlying files

func (*EchoReplayCodec) Finalize

func (e *EchoReplayCodec) Finalize() error

Finalize writes the buffered data to the zip file and closes it

func (*EchoReplayCodec) FlushBuffer

func (e *EchoReplayCodec) FlushBuffer() error

FlushBuffer forces a flush of the internal buffer (useful for periodic flushing)

func (*EchoReplayCodec) GetBufferSize

func (e *EchoReplayCodec) GetBufferSize() int

GetBufferSize returns the current size of the internal buffer

func (*EchoReplayCodec) HasNext

func (e *EchoReplayCodec) HasNext() bool

HasNext checks if there are more frames to read

func (*EchoReplayCodec) ReadFrame

ReadFrame reads the next frame from the .echoreplay file

func (*EchoReplayCodec) ReadFrames

func (e *EchoReplayCodec) ReadFrames() ([]*rtapi.LobbySessionStateFrame, error)

ReadFrames reads all frames from the .echoreplay file

func (*EchoReplayCodec) WriteFrame

func (e *EchoReplayCodec) WriteFrame(frame *rtapi.LobbySessionStateFrame) error

WriteFrame writes a frame to the .echoreplay file using optimized buffer operations

func (*EchoReplayCodec) WriteFrameBatch

func (e *EchoReplayCodec) WriteFrameBatch(frames []*rtapi.LobbySessionStateFrame) error

WriteFrameBatch writes multiple frames efficiently in a single operation

func (*EchoReplayCodec) WriteReplayFrame

func (e *EchoReplayCodec) WriteReplayFrame(dst *bytes.Buffer, frame *rtapi.LobbySessionStateFrame) int

WriteReplayFrame writes a frame using optimized buffer operations (same approach as writer_replay_file.go)

type EchoReplayFrame

type EchoReplayFrame struct {
	Timestamp   string                       `json:"timestamp"`
	Session     *apigame.SessionResponse     `json:"session"`
	PlayerBones *apigame.PlayerBonesResponse `json:"user_bones,omitempty"`
}

EchoReplayFrame represents a frame in the .echoreplay format

type EventDetector

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

EventDetector efficiently detects events between consecutive frames

func NewEventDetector

func NewEventDetector() *EventDetector

NewEventDetector creates a new event detector

func (*EventDetector) DetectEvents

func (ed *EventDetector) DetectEvents(prevFrame, currentFrame *rtapi.LobbySessionStateFrame) []*rtapi.LobbySessionEvent

DetectEvents analyzes two consecutive frames and returns detected events

func (*EventDetector) Reset

func (ed *EventDetector) Reset()

Reset clears the event detector state

type FrameProcessor

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

FrameProcessor handles high-performance processing of game frames optimized for up to 600 Hz operation

func NewFrameProcessor

func NewFrameProcessor() *FrameProcessor

NewFrameProcessor creates a new optimized frame processor

func (*FrameProcessor) ProcessFrame

func (fp *FrameProcessor) ProcessFrame(sessionResponseData, userBonesData []byte, timestamp time.Time) (*rtapi.LobbySessionStateFrame, error)

ProcessFrame takes raw session and user bones data and processes it into a rtapi.LobbySessionStateFrame This is optimized for high-frequency invocation (up to 600 Hz)

func (*FrameProcessor) Reset

func (fp *FrameProcessor) Reset()

Reset clears the processor state

type ScoreboardState

type ScoreboardState struct {
	BluePoints       int32
	OrangePoints     int32
	BlueRoundScore   int32
	OrangeRoundScore int32
	GameClock        string
}

ScoreboardState represents the scoring state

type ZstdCodec

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

ZstdCodec handles streaming to/from Zstd-compressed .nevrcap files

func NewZstdCodecReader

func NewZstdCodecReader(filename string) (*ZstdCodec, error)

NewZstdCodecReader creates a new Zstd codec for reading .nevrcap files

func NewZstdCodecWriter

func NewZstdCodecWriter(filename string) (*ZstdCodec, error)

NewZstdCodecWriter creates a new Zstd codec for writing .nevrcap files

func (*ZstdCodec) Close

func (z *ZstdCodec) Close() error

Close closes the codec and underlying file

func (*ZstdCodec) ReadFrame

func (z *ZstdCodec) ReadFrame() (*rtapi.LobbySessionStateFrame, error)

ReadFrame reads a frame from the file

func (*ZstdCodec) ReadHeader

func (z *ZstdCodec) ReadHeader() (*rtapi.TelemetryHeader, error)

ReadHeader reads the nevrcap header from the file

func (*ZstdCodec) WriteFrame

func (z *ZstdCodec) WriteFrame(frame *rtapi.LobbySessionStateFrame) error

WriteFrame writes a frame to the file

func (*ZstdCodec) WriteHeader

func (z *ZstdCodec) WriteHeader(header *rtapi.TelemetryHeader) error

WriteHeader writes the nevrcap header to the file

Jump to

Keyboard shortcuts

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