99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package parse
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/golang/snappy"
|
|
"github.com/olemorud/replay-parser/demo"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type Frame struct {
|
|
Kind uint64 `json:"kind"` // see demo.proto
|
|
Tick uint64 `json:"tick"` // time elapsed in replay time
|
|
Size uint64 `json:"size"` // size of message in bytes
|
|
Message *demo.CDemoFileInfo `json:"message"` // protobuf encoded message (may be compressed with snappy)
|
|
}
|
|
|
|
// If kind has a certain bit set, the frame message is compressed
|
|
// returns true if frame is compressed
|
|
func isCompressed(frame *Frame) bool {
|
|
return (frame.Kind&uint64(demo.EDemoCommands_DEM_IsCompressed) != 0)
|
|
}
|
|
|
|
// Checks if file header is correct and returns number the address of the last frame
|
|
func First(r *bufio.Reader) (uint64, error) {
|
|
// Check if first 8 bytes of file matches the source 2 replay file header
|
|
header := make([]byte, 8)
|
|
if _, err := io.ReadFull(r, header); err != nil {
|
|
return 0, fmt.Errorf("error when reading file: %v", err)
|
|
}
|
|
if string(header) != SIGNATURE {
|
|
return 0, fmt.Errorf("wrong file signature: %v, should be ", SIGNATURE)
|
|
}
|
|
|
|
// Read last frame
|
|
var offset uint32
|
|
err := binary.Read(r, binary.LittleEndian, &offset)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("error reading number of frames in replay: %v", err)
|
|
}
|
|
|
|
/// remove later
|
|
println("size of demo is", offset, "frames")
|
|
|
|
return uint64(offset), nil
|
|
}
|
|
|
|
// Parses the next frame on the reader
|
|
func DecodeNextFrame(r *bufio.Reader) (*Frame, error) {
|
|
// Read kind, tick, size and message
|
|
frame := new(Frame)
|
|
var err error
|
|
|
|
if frame.Kind, err = binary.ReadUvarint(r); err != nil {
|
|
return nil, fmt.Errorf("error reading frame kind for frame: %v", err)
|
|
}
|
|
|
|
if frame.Tick, err = binary.ReadUvarint(r); err != nil {
|
|
return nil, fmt.Errorf("error reading frame tick for frame: %v", err)
|
|
}
|
|
|
|
if frame.Size, err = binary.ReadUvarint(r); err != nil {
|
|
return nil, fmt.Errorf("error reading frame size for frame: %v", err)
|
|
}
|
|
|
|
message := make([]byte, frame.Size)
|
|
io.ReadFull(r, message)
|
|
|
|
frame.Message = new(demo.CDemoFileInfo)
|
|
|
|
if isCompressed(frame) {
|
|
decoded, err := snappy.Decode(nil, message)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding message: %v", err)
|
|
}
|
|
fmt.Println("I got decompressed :O")
|
|
proto.Unmarshal(decoded, frame.Message)
|
|
} else {
|
|
proto.Unmarshal(message, frame.Message)
|
|
}
|
|
|
|
return frame, nil
|
|
}
|
|
|
|
// Reads every single frame (probably not very efficient)
|
|
func DecodeAllFrames(r *bufio.Reader, frameCount uint64) ([]*Frame, error) {
|
|
replay := make([]*Frame, frameCount)
|
|
|
|
// Decode all frames and add them to *Frame slice
|
|
for i := 0; i < int(frameCount); i++ {
|
|
replay[i], _ = DecodeNextFrame(r)
|
|
}
|
|
|
|
return replay, nil
|
|
}
|