From 79200cae38f793874c5d2d9015095bb097286d8f Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Wed, 28 Sep 2016 11:23:25 -0400 Subject: [PATCH] back to this thing again --- ent/class.go | 44 ++++++++++++++++++++++++------- ent/entity.go | 36 +++++++++++++++++++++++++ ent/env.go | 68 ++++++++++++++++++++++++++++++++++++++++-------- ent/selection.go | 29 +++++++++++++++++++++ ent/slotted.go | 7 +++++ ent/type.go | 9 ++++++- ent/vector.go | 9 ++++++- 7 files changed, 180 insertions(+), 22 deletions(-) create mode 100644 ent/entity.go create mode 100644 ent/slotted.go diff --git a/ent/class.go b/ent/class.go index 5e8df3c..9b0216a 100644 --- a/ent/class.go +++ b/ent/class.go @@ -16,21 +16,47 @@ func (c class) String() string { } func (c *class) read(r bit.Reader) (value, error) { - return nil, fmt.Errorf("fart") + bit.ReadBool(r) // ??? + return c.nü(), nil } -type classHistory map[int]*class +func (c *class) nü() entity { + return entity{class: c, slots: make([]value, len(c.fields))} +} + +type classHistory struct { + versions map[int]*class + oldest *class + newest *class +} + +func (h *classHistory) add(c *class) { + if h.oldest == nil || c.version < h.oldest.version { + h.oldest = c + } + if h.newest == nil || c.version > h.newest.version { + h.newest = c + } + if h.versions == nil { + h.versions = make(map[int]*class) + } + h.versions[c.version] = c +} + +func (h *classHistory) version(v int) *class { + if h.versions == nil { + return nil + } + return h.versions[v] +} func classType(spec *typeSpec, env *Env) tÿpe { if spec.serializer != "" { - h := env.classes[spec.serializer] - if h != nil { - class := h[spec.serializerV] - if class != nil { - return class - } - return typeError("class %s exists for spec serializer but can't find version %d", spec.serializer, spec.serializerV) + c := env.classVersion(spec.serializer, spec.serializerV) + if c != nil { + return c } + return typeError("unable to find class named %s with version %d", spec.serializer, spec.serializerV) } return nil } diff --git a/ent/entity.go b/ent/entity.go new file mode 100644 index 0000000..d4fdecb --- /dev/null +++ b/ent/entity.go @@ -0,0 +1,36 @@ +package ent + +import ( + "github.com/jordanorelli/hyperstone/bit" +) + +type entity struct { + class *class + slots []value +} + +func (e *entity) read(r bit.Reader) error { + Debug.Printf("entity %s read", e.className()) + sr := new(selectionReader) + selections, err := sr.readSelections(r, htree) + if err != nil { + return wrap(err, "entity of type %s failed to read selections", e.className()) + } + for _, s := range selections { + if err := s.fillSlots(e, r); err != nil { + return err + } + } + return nil +} + +func (e *entity) className() string { + if e.class != nil { + return e.class.name + } + return "" +} + +func (e *entity) slotType(i int) tÿpe { return e.class.fields[i].tÿpe } +func (e *entity) setSlotValue(i int, v value) { e.slots[i] = v } +func (e *entity) getSlotValue(i int) value { return e.slots[i] } diff --git a/ent/env.go b/ent/env.go index 86cba8c..180fd30 100644 --- a/ent/env.go +++ b/ent/env.go @@ -2,6 +2,7 @@ package ent import ( "github.com/golang/protobuf/proto" + "strconv" "github.com/jordanorelli/hyperstone/bit" "github.com/jordanorelli/hyperstone/dota" @@ -11,14 +12,17 @@ import ( type Env struct { symbols symbolTable source bit.BufReader - classes map[string]classHistory + classes map[string]*classHistory netIds map[int]string fields []field strings *stbl.Dict } func NewEnv() *Env { - e := &Env{strings: stbl.NewDict()} + e := &Env{ + classes: make(map[string]*classHistory), + strings: stbl.NewDict(), + } e.strings.WatchTable("instancebaseline", e.syncBaselineTable) return e } @@ -36,10 +40,10 @@ func (e *Env) Handle(m proto.Message) error { if err := e.mergeSendTables(v); err != nil { return err } - e.syncBaseline() case *dota.CDemoClassInfo: e.mergeClassInfo(v) + e.syncBaseline() } return nil } @@ -71,16 +75,17 @@ func (e *Env) mergeSendTables(m *dota.CDemoSendTables) error { // 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) + c := &class{name: name, version: v} + Debug.Printf("new class: %s", c) + h := e.classes[name] + if h == nil { + h = new(classHistory) + e.classes[name] = h } - e.classes[name][v] = &class{name: name, version: v} + h.add(c) } } @@ -104,7 +109,7 @@ func (e *Env) fillClasses(flat *dota.CSVCMsg_FlattenedSerializer) { for _, s := range flat.GetSerializers() { name := e.symbol(int(s.GetSerializerNameSym())) v := int(s.GetSerializerVersion()) - class := e.classes[name][v] + class := e.classes[name].version(v) class.fields = make([]field, len(s.GetFieldsIndex())) for i, id := range s.GetFieldsIndex() { @@ -136,7 +141,48 @@ func (e *Env) syncBaseline() { } func (e *Env) syncBaselineTable(t *stbl.Table) { - if e.classes == nil { + if e.netIds == nil || len(e.netIds) == 0 { + Debug.Printf("syncBaselines skipped: net ids are nil") + } + if e.classes == nil || len(e.classes) == 0 { Debug.Printf("syncBaselines skipped: classes are nil") } + + r := new(bit.BufReader) + for _, entry := range t.Entries() { + netId, err := strconv.Atoi(entry.Key) + if err != nil { + Debug.Printf("syncBaselines ignored bad key %s: %v", err) + continue + } + className := e.netIds[netId] + if className == "" { + Debug.Printf("syncBaselines couldn't find class with net id %d", netId) + continue + } + c := e.class(className) + if c == nil { + Debug.Printf("syncBaselines couldn't find class named %s", className) + continue + } + Debug.Printf("syncBaselines key: %s className: %s", entry.Key, c.name) + ent := c.nü() + r.SetSource(entry.Value) + if err := ent.read(r); err != nil { + Debug.Printf("syncBaselines failed to fill an entity: %v", err) + } + } +} + +func (e *Env) class(name string) *class { + h := e.classes[name] + if h == nil { + return nil + } + return h.newest +} + +func (e *Env) classVersion(name string, version int) *class { + h := e.classes[name] + return h.version(version) } diff --git a/ent/selection.go b/ent/selection.go index 42f4ab7..12fd643 100644 --- a/ent/selection.go +++ b/ent/selection.go @@ -19,6 +19,35 @@ type selection struct { func (s selection) String() string { return fmt.Sprint(s.path()) } func (s selection) path() []int { return s.vals[:s.count] } +func (s selection) fillSlots(v slotted, r bit.Reader) error { + Debug.Printf("%v fill slots into %v", s, v) + return s.fillSlotsIter(0, v, r) +} + +func (s selection) fillSlotsIter(offset int, dest slotted, r bit.Reader) error { + slot := s.vals[offset] + if s.count-offset <= 0 { + return fmt.Errorf("unable to fill selection %v having count %d at offset %d", s, s.count, offset) + } + switch s.count - offset { + case 1: + t := dest.slotType(slot) + v, err := t.read(r) + if err != nil { + return fmt.Errorf("unable to fill selection: %v", err) + } + dest.setSlotValue(slot, v) + return nil + default: + v := dest.getSlotValue(slot) + vs, ok := v.(slotted) + if !ok { + return fmt.Errorf("destination is not slotted") + } + return s.fillSlotsIter(offset+1, vs, r) + } +} + // selectionReader reads a set of field selections off of the wire. the // selections are represented as arrays of slot positions to be traversed in // order to select an entity slot. diff --git a/ent/slotted.go b/ent/slotted.go new file mode 100644 index 0000000..db620a3 --- /dev/null +++ b/ent/slotted.go @@ -0,0 +1,7 @@ +package ent + +type slotted interface { + slotType(int) tÿpe + setSlotValue(int, value) + getSlotValue(int) value +} diff --git a/ent/type.go b/ent/type.go index 8803c0d..b52d271 100644 --- a/ent/type.go +++ b/ent/type.go @@ -34,7 +34,14 @@ func parseTypeSpec(spec *typeSpec, env *Env) tÿpe { return nil } return coalesce(arrayType, atomType, floatType, handleType, qAngleType, - hSeqType, genericType, vectorType, classType) + hSeqType, genericType, vectorType, classType, unknownType) +} + +func unknownType(spec *typeSpec, env *Env) tÿpe { + Debug.Printf("Unknown Type: %v", spec) + return typeFn(func(r bit.Reader) (value, error) { + return bit.ReadVarInt(r), r.Err() + }) } // a type error is both an error and a type. It represents a type that we were diff --git a/ent/vector.go b/ent/vector.go index 2bdebca..a88d941 100644 --- a/ent/vector.go +++ b/ent/vector.go @@ -10,7 +10,14 @@ func vectorType(spec *typeSpec, env *Env) tÿpe { if spec.encoder != "" { return nil } - return vector_t{elem: floatType(spec, env)} + t := floatType(spec, env) + if _, ok := t.(error); ok { + return t + } + if t == nil { + return nil + } + return vector_t{elem: t} } type vector_t struct {