diff --git a/datagram.go b/datagram.go index 2e4035e..d4cd581 100644 --- a/datagram.go +++ b/datagram.go @@ -2,11 +2,8 @@ package main import ( "fmt" - "io" "github.com/golang/protobuf/proto" - "github.com/jordanorelli/hyperstone/bit" - "github.com/jordanorelli/hyperstone/dota" ) // datagram represents the top-level envelope in the dota replay format. All @@ -24,42 +21,14 @@ func (g dataGram) String() string { return fmt.Sprintf("{dataGram cmd: %v tick: %v size: %d body: %x}", g.cmd, g.tick, len(g.body), g.body) } -func (g *dataGram) check(dump bool) error { - if g.cmd != EDemoCommands_DEM_Packet { - return fmt.Errorf("wrong command type in openPacket: %v", g.cmd) +func (g *dataGram) Open(m *messageFactory) (proto.Message, error) { + msg := m.BuildDatagram(g.cmd) + if msg == nil { + return nil, fmt.Errorf("skipped") } - - packet := new(dota.CDemoPacket) - if err := proto.Unmarshal(g.body, packet); err != nil { - return wrap(err, "onPacket unable to unmarshal message body") - } - - br := bit.NewBytesReader(packet.GetData()) - for { - t := entityType(br.ReadUBitVar()) - s := br.ReadVarInt() - b := make([]byte, s) - br.Read(b) - switch err := br.Err(); err { - case nil: - break - case io.EOF: - return nil - default: - return err - } - if dump { - fmt.Printf("\t%v\n", entity{t: t, size: uint32(s), body: b}) - } - e := messages.BuildEntity(t) - if e == nil { - fmt.Printf("\tno known entity for type id %d size: %d\n", int(t), len(b)) - continue - } - err := proto.Unmarshal(b, e) - if err != nil { - fmt.Printf("entity unmarshal error: %v\n", err) - } + err := proto.Unmarshal(g.body, msg) + if err != nil { + return nil, err } - return nil + return msg, nil } diff --git a/parser.go b/parser.go index ef141fb..bfd33f7 100644 --- a/parser.go +++ b/parser.go @@ -4,10 +4,11 @@ import ( "bufio" "fmt" "io" - "reflect" "github.com/golang/protobuf/proto" "github.com/golang/snappy" + "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" ) type parser struct { @@ -43,27 +44,58 @@ func (p *parser) run() error { if err != nil { return wrap(err, "read datagram error in run loop") } - if p.dumpDatagrams { - fmt.Println(gram) - } + p.handleDataGram(gram) + } +} - if len(gram.body) == 0 { - continue - } +func (p *parser) handleDataGram(d *dataGram) error { + if p.dumpDatagrams { + fmt.Println(d) + } - switch gram.cmd { - case EDemoCommands_DEM_Packet: - if err := gram.check(p.dumpPackets); err != nil { - fmt.Printf("error: %v\n", err) - } + if len(d.body) == 0 { + return nil + } + + msg, err := d.Open(&messages) + if err != nil { + fmt.Printf("datagram open error: %v\n", err) + return nil + } + + switch v := msg.(type) { + case *dota.CDemoPacket: + p.handleDemoPacket(v) + } + return nil +} + +func (p *parser) handleDemoPacket(packet *dota.CDemoPacket) error { + br := bit.NewBytesReader(packet.GetData()) + for { + t := entityType(br.ReadUBitVar()) + s := br.ReadVarInt() + b := make([]byte, s) + br.Read(b) + switch err := br.Err(); err { + case nil: + break + case io.EOF: + return nil default: - m := messages.BuildDatagram(gram.cmd) - if m != nil { - err := proto.Unmarshal(gram.body, m) - if err != nil { - fmt.Printf("cmd unmarshal error unpacking data of length %d with cmd type %s into message type %v: %v\n", len(gram.body), gram.cmd, reflect.TypeOf(m), err) - } - } + return err + } + if p.dumpPackets { + fmt.Printf("\t%v\n", entity{t: t, size: uint32(s), body: b}) + } + e := messages.BuildEntity(t) + if e == nil { + fmt.Printf("\tno known entity for type id %d size: %d\n", int(t), len(b)) + continue + } + err := proto.Unmarshal(b, e) + if err != nil { + fmt.Printf("entity unmarshal error: %v\n", err) } } }