looking at send tables
parent
82dbc58f58
commit
b73b917084
@ -0,0 +1,74 @@
|
|||||||
|
package dt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jordanorelli/hyperstone/dota"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Field struct {
|
||||||
|
_type Symbol
|
||||||
|
name Symbol
|
||||||
|
sendNode Symbol
|
||||||
|
bits *int
|
||||||
|
low *float32
|
||||||
|
high *float32
|
||||||
|
flags *int32
|
||||||
|
serializer *Symbol
|
||||||
|
serializerVersion *int32
|
||||||
|
encoder *Symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Field) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fmt.Fprintf(&buf, "{type: %s name: %s send: %s", f._type, f.name, f.sendNode)
|
||||||
|
if f.bits != nil {
|
||||||
|
fmt.Fprintf(&buf, " bits: %d", *f.bits)
|
||||||
|
}
|
||||||
|
if f.low != nil {
|
||||||
|
fmt.Fprintf(&buf, " low: %f", *f.low)
|
||||||
|
}
|
||||||
|
if f.high != nil {
|
||||||
|
fmt.Fprintf(&buf, " high: %f", *f.high)
|
||||||
|
}
|
||||||
|
if f.flags != nil {
|
||||||
|
fmt.Fprintf(&buf, " flags: %d", *f.flags)
|
||||||
|
}
|
||||||
|
if f.serializer != nil {
|
||||||
|
fmt.Fprintf(&buf, " serializer: %s", *f.serializer)
|
||||||
|
}
|
||||||
|
if f.serializerVersion != nil {
|
||||||
|
fmt.Fprintf(&buf, " serializer_v: %d", *f.serializerVersion)
|
||||||
|
}
|
||||||
|
if f.encoder != nil {
|
||||||
|
fmt.Fprintf(&buf, " encoder: %s", *f.encoder)
|
||||||
|
}
|
||||||
|
fmt.Fprint(&buf, "}")
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, t *SymbolTable) {
|
||||||
|
f._type = t.Symbol(int(flat.GetVarTypeSym()))
|
||||||
|
f.name = t.Symbol(int(flat.GetVarNameSym()))
|
||||||
|
if flat.BitCount == nil {
|
||||||
|
f.bits = nil
|
||||||
|
} else {
|
||||||
|
f.bits = new(int)
|
||||||
|
*f.bits = int(flat.GetBitCount())
|
||||||
|
}
|
||||||
|
f.low = flat.LowValue
|
||||||
|
f.high = flat.HighValue
|
||||||
|
f.flags = flat.EncodeFlags
|
||||||
|
|
||||||
|
if flat.FieldSerializerNameSym == nil {
|
||||||
|
f.serializer = nil
|
||||||
|
} else {
|
||||||
|
f.serializer = new(Symbol)
|
||||||
|
*f.serializer = t.Symbol(int(flat.GetFieldSerializerNameSym()))
|
||||||
|
}
|
||||||
|
|
||||||
|
f.serializerVersion = flat.FieldSerializerVersion
|
||||||
|
// panic if we don't have a send node cause that shit is corrupt yo
|
||||||
|
f.sendNode = t.Symbol(int(*flat.SendNodeSym))
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package dt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jordanorelli/hyperstone/dota"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Serializer struct {
|
||||||
|
Name Symbol
|
||||||
|
Version int
|
||||||
|
Fields []*Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Serializer) fromProto(v *dota.ProtoFlattenedSerializerT, st *SymbolTable, fields []Field) {
|
||||||
|
s.Name = st.Symbol(int(v.GetSerializerNameSym()))
|
||||||
|
s.Version = int(v.GetSerializerVersion())
|
||||||
|
s.Fields = make([]*Field, len(v.GetFieldsIndex()))
|
||||||
|
for i, fi := range v.GetFieldsIndex() {
|
||||||
|
s.Fields[i] = &fields[fi]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package dt
|
||||||
|
|
||||||
|
// the internal representation of table data refers to all labels as
|
||||||
|
// interned strings (symbols). This array of string contains the mapping of
|
||||||
|
// symbol ids to symbol display representations. The sample replay I have
|
||||||
|
// at the time of writing this contains 2215 symbols in its symbol table.
|
||||||
|
// The dota replay format uses an ordered list of symbols.
|
||||||
|
type SymbolTable []string
|
||||||
|
|
||||||
|
func (t *SymbolTable) Symbol(id int) Symbol { return Symbol{id: id, table: t} }
|
||||||
|
|
||||||
|
type Symbol struct {
|
||||||
|
id int
|
||||||
|
table *SymbolTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Symbol) String() string { return (*s.table)[s.id] }
|
@ -0,0 +1,56 @@
|
|||||||
|
package dt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/jordanorelli/hyperstone/dota"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TableSet represents a collection of tables.
|
||||||
|
type TableSet struct {
|
||||||
|
SymbolTable
|
||||||
|
Fields []Field
|
||||||
|
Serializers []Serializer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TableSet) DebugPrint(w io.Writer) {
|
||||||
|
fmt.Fprintln(w, "Symbols:")
|
||||||
|
for _, sym := range t.SymbolTable {
|
||||||
|
fmt.Fprintf(w, "\t%s\n", sym)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, "Fields:")
|
||||||
|
for _, f := range t.Fields {
|
||||||
|
fmt.Fprintf(w, "\t%s\n", f)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, "Serializers:")
|
||||||
|
for _, s := range t.Serializers {
|
||||||
|
fmt.Fprintf(w, "\t%s (%d):\n", s.Name, s.Version)
|
||||||
|
for _, f := range s.Fields {
|
||||||
|
fmt.Fprintf(w, "\t\t%s\n", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseFlattened parses a flattened TableSet definition, as defined by the
|
||||||
|
// Dota replay protobufs.
|
||||||
|
func ParseFlattened(m *dota.CSVCMsg_FlattenedSerializer) *TableSet {
|
||||||
|
ts := &TableSet{SymbolTable: SymbolTable(m.GetSymbols())}
|
||||||
|
ts.parseFields(m.GetFields())
|
||||||
|
ts.parseSerializers(m.GetSerializers())
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TableSet) parseFields(flat []*dota.ProtoFlattenedSerializerFieldT) {
|
||||||
|
ts.Fields = make([]Field, len(flat))
|
||||||
|
for i, f := range flat {
|
||||||
|
ts.Fields[i].fromProto(f, &ts.SymbolTable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TableSet) parseSerializers(flat []*dota.ProtoFlattenedSerializerT) {
|
||||||
|
ts.Serializers = make([]Serializer, len(flat))
|
||||||
|
for i, s := range flat {
|
||||||
|
ts.Serializers[i].fromProto(s, &ts.SymbolTable, ts.Fields)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/jordanorelli/hyperstone/dota"
|
||||||
|
)
|
||||||
|
|
||||||
|
// type CSVCMsg_PacketEntities struct {
|
||||||
|
// MaxEntries *int32
|
||||||
|
// UpdatedEntries *int32
|
||||||
|
// IsDelta *bool
|
||||||
|
// UpdateBaseline *bool
|
||||||
|
// Baseline *int32
|
||||||
|
// DeltaFrom *int32
|
||||||
|
// EntityData []byte
|
||||||
|
// PendingFullFrame *bool
|
||||||
|
// ActiveSpawngroupHandle *uint32
|
||||||
|
// MaxSpawngroupCreationsequence *uint32
|
||||||
|
// }
|
||||||
|
|
||||||
|
func dumpEntities(m proto.Message) {
|
||||||
|
switch v := m.(type) {
|
||||||
|
case *dota.CSVCMsg_PacketEntities:
|
||||||
|
data := v.GetEntityData()
|
||||||
|
if len(data) > 32 {
|
||||||
|
data = data[:32]
|
||||||
|
}
|
||||||
|
fmt.Printf("{MaxEntries: %d UpdatedEntries: %v IsDelta: %t UpdateBaseline: %t Baseline: %d DeltaFrom: %d EntityData: %x PendingFullFrame: %t ActiveSpawngroupHandle: %d}\n", v.GetMaxEntries(), v.GetUpdatedEntries(), v.GetIsDelta(), v.GetUpdateBaseline(), v.GetBaseline(), v.GetDeltaFrom(), data, v.GetPendingFullFrame(), v.GetActiveSpawngroupHandle())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
|
"github.com/jordanorelli/hyperstone/bit"
|
||||||
|
"github.com/jordanorelli/hyperstone/dota"
|
||||||
|
"github.com/jordanorelli/hyperstone/dt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sendTables(m proto.Message) {
|
||||||
|
v, ok := m.(*dota.CDemoSendTables)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendtables only has one field, a binary data field.
|
||||||
|
data := v.GetData()
|
||||||
|
br := bit.NewBytesReader(data)
|
||||||
|
|
||||||
|
// body is length-prefixed
|
||||||
|
size := int(bit.ReadVarInt(br))
|
||||||
|
|
||||||
|
buf := make([]byte, size)
|
||||||
|
br.Read(buf)
|
||||||
|
|
||||||
|
serializer := dota.CSVCMsg_FlattenedSerializer{}
|
||||||
|
if err := proto.Unmarshal(buf, &serializer); err != nil {
|
||||||
|
fmt.Printf("error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := dt.ParseFlattened(&serializer)
|
||||||
|
ts.DebugPrint(os.Stdout)
|
||||||
|
}
|
Loading…
Reference in New Issue