From 53793b695ccbbc12d3ab8d07bdb23fd9af0a799f Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Fri, 23 Sep 2016 18:10:03 -0400 Subject: [PATCH] outlining --- ent/class.go | 6 +++++ ent/env.go | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++- ent/field.go | 47 +++++++++++++++++++++++++++++++++++++ ent/misc.go | 27 ++++++++++++++++++++++ ent/symbol.go | 10 ++++++++ ent/type.go | 4 ++++ ent/value.go | 9 ++++++++ main.go | 4 +++- 8 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 ent/class.go create mode 100644 ent/field.go create mode 100644 ent/misc.go create mode 100644 ent/symbol.go create mode 100644 ent/type.go create mode 100644 ent/value.go diff --git a/ent/class.go b/ent/class.go new file mode 100644 index 0000000..27e2d30 --- /dev/null +++ b/ent/class.go @@ -0,0 +1,6 @@ +package ent + +type class struct { +} + +type classHistory map[int]*class diff --git a/ent/env.go b/ent/env.go index 314e60a..c8e607f 100644 --- a/ent/env.go +++ b/ent/env.go @@ -1,19 +1,81 @@ package ent import ( + "fmt" + "github.com/golang/protobuf/proto" "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" ) type Env struct { - source bit.BufReader + symbols symbolTable + source bit.BufReader + classes map[string]classHistory + fields []field } func (e *Env) Handle(m proto.Message) error { + switch v := m.(type) { + case *dota.CDemoSendTables: + return e.mergeSendTables(v) + } return nil } func (e *Env) setSource(buf []byte) { e.source.SetSource(buf) } + +func (e *Env) mergeSendTables(m *dota.CDemoSendTables) error { + Debug.Printf("merge send tables") + + flat, err := getSerializers(m) + if err != nil { + return wrap(err, "unable to get serializers in sendtables") + } + e.symbols = symbolTable(flat.GetSymbols()) + e.stubClasses(flat) + if err := e.parseFields(flat); err != nil { + return wrap(err, "unable to parse serializer fields") + } + if err := e.parseClasses(flat); err != nil { + return wrap(err, "unable to parse serializers") + } + return nil +} + +// stubs out the classes to be created later. we do this to create empty class +// structs that fields may point to. +func (e *Env) stubClasses(flat *dota.CSVCMsg_FlattenedSerializer) { + serializers := flat.GetSerializers() + if e.classes == nil { + e.classes = make(map[string]classHistory, len(serializers)) + } + for _, s := range serializers { + name := e.symbol(int(s.GetSerializerNameSym())) + v := int(s.GetSerializerVersion()) + if e.classes[name] == nil { + e.classes[name] = make(classHistory, 4) + } + e.classes[name][v] = new(class) + } +} + +func (e *Env) parseFields(flat *dota.CSVCMsg_FlattenedSerializer) error { + e.fields = make([]field, len(flat.GetFields())) + for i, ff := range flat.GetFields() { + f := &e.fields[i] + if err := f.fromProto(ff, e); err != nil { + return err + } + } + return nil +} + +func (e *Env) parseClasses(flat *dota.CSVCMsg_FlattenedSerializer) error { + return fmt.Errorf("nope, not yet") +} + +func (e *Env) symbol(id int) string { return e.symbols[id] } diff --git a/ent/field.go b/ent/field.go new file mode 100644 index 0000000..f8dfdc1 --- /dev/null +++ b/ent/field.go @@ -0,0 +1,47 @@ +package ent + +import ( + "bytes" + "fmt" + "github.com/jordanorelli/hyperstone/dota" +) + +type field struct { + name string + tÿpe +} + +func (f *field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, env *Env) error { + var_name := env.symbol(int(flat.GetVarNameSym())) + var_type := env.symbol(int(flat.GetVarTypeSym())) + + var pretty bytes.Buffer + fmt.Fprintf(&pretty, "{name: %s type: %s", var_name, var_type) + if flat.BitCount != nil { + fmt.Fprintf(&pretty, " bits: %d", flat.GetBitCount()) + } + if flat.LowValue != nil { + fmt.Fprintf(&pretty, " low: %f", flat.GetLowValue()) + } + if flat.HighValue != nil { + fmt.Fprintf(&pretty, " high: %f", flat.GetHighValue()) + } + if flat.EncodeFlags != nil { + fmt.Fprintf(&pretty, " flags: %d", flat.GetEncodeFlags()) + } + if flat.FieldSerializerNameSym != nil { + fmt.Fprintf(&pretty, " serializer: %s", env.symbol(int(flat.GetFieldSerializerNameSym()))) + } + if flat.FieldSerializerVersion != nil { + fmt.Fprintf(&pretty, " s_version: %d", flat.GetFieldSerializerVersion()) + } + if flat.SendNodeSym != nil { + fmt.Fprintf(&pretty, " send: %s", env.symbol(int(flat.GetSendNodeSym()))) + } + if flat.VarEncoderSym != nil { + fmt.Fprintf(&pretty, " var_enc: %s", env.symbol(int(flat.GetVarEncoderSym()))) + } + fmt.Fprint(&pretty, "}") + + return fmt.Errorf("unable to parse type: %s", pretty.String()) +} diff --git a/ent/misc.go b/ent/misc.go new file mode 100644 index 0000000..f79d0db --- /dev/null +++ b/ent/misc.go @@ -0,0 +1,27 @@ +package ent + +import ( + "github.com/golang/protobuf/proto" + + "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" +) + +func getSerializers(m *dota.CDemoSendTables) (*dota.CSVCMsg_FlattenedSerializer, error) { + data := m.GetData() + r := bit.NewBytesReader(data) + + size := int(bit.ReadVarInt(r)) + buf := make([]byte, size) + + r.Read(buf) + if r.Err() != nil { + return nil, wrap(r.Err(), "error reading serializers body") + } + + flat := dota.CSVCMsg_FlattenedSerializer{} + if err := proto.Unmarshal(buf, &flat); err != nil { + return nil, wrap(err, "error unmarshaling serializers body") + } + return &flat, nil +} diff --git a/ent/symbol.go b/ent/symbol.go new file mode 100644 index 0000000..0bb1fe3 --- /dev/null +++ b/ent/symbol.go @@ -0,0 +1,10 @@ +package ent + +type symbol struct { + id int + table *symbolTable +} + +func (s symbol) String() string { return (*s.table)[s.id] } + +type symbolTable []string diff --git a/ent/type.go b/ent/type.go new file mode 100644 index 0000000..31583d9 --- /dev/null +++ b/ent/type.go @@ -0,0 +1,4 @@ +package ent + +type tÿpe interface { +} diff --git a/ent/value.go b/ent/value.go new file mode 100644 index 0000000..453442b --- /dev/null +++ b/ent/value.go @@ -0,0 +1,9 @@ +package ent + +import ( + "github.com/jordanorelli/hyperstone/bit" +) + +type value interface { + read(bit.Reader) error +} diff --git a/main.go b/main.go index 59f3379..454bed5 100644 --- a/main.go +++ b/main.go @@ -146,7 +146,9 @@ func main() { env := new(ent.Env) handle = func(m proto.Message) { sd.Handle(m) - env.Handle(m) + if err := env.Handle(m); err != nil { + bail(1, "%v", err) + } } default: bail(1, "no such action: %s", flag.Arg(0))