master
Jordan Orelli 8 years ago
parent 6bd601359b
commit a72c51faaf

@ -13,10 +13,12 @@ type Class struct {
// all other entities for this class use this instance as a prototype // all other entities for this class use this instance as a prototype
baseline *Entity baseline *Entity
fp *fieldPath
} }
func (c *Class) New() *Entity { func (c *Class) New() *Entity {
return &Entity{Class: c} return &Entity{Class: c, fields: make(map[string]interface{}, len(c.Fields))}
} }
func (c Class) String() string { func (c Class) String() string {

@ -164,6 +164,10 @@ func (d *Dict) updateBaselines(t *stbl.Table) {
} }
func (d *Dict) syncBaselines() { func (d *Dict) syncBaselines() {
if !d.hasClassinfo() {
Debug.Printf("syncBaselines skip: no classInfo yet")
return
}
Debug.Printf("syncBaselines start") Debug.Printf("syncBaselines start")
if d.base == nil { if d.base == nil {
Debug.Printf("syncBaselines failed: reference to baseline string table is nil") Debug.Printf("syncBaselines failed: reference to baseline string table is nil")

@ -8,6 +8,7 @@ import (
type Entity struct { type Entity struct {
*Class *Class
fields map[string]interface{}
} }
func (e *Entity) Read(br bit.Reader) error { func (e *Entity) Read(br bit.Reader) error {
@ -17,9 +18,8 @@ func (e *Entity) Read(br bit.Reader) error {
Debug.Printf("entity %v read", e) Debug.Printf("entity %v read", e)
fp := newFieldPath() fp := newFieldPath()
if err := fp.read(br, htree); err != nil { if err := fp.read(br, htree, e.Class); err != nil {
return fmt.Errorf("unable to read entity: %v", err) return fmt.Errorf("unable to read entity: %v", err)
} }
Debug.Printf("fieldpath %v", fp.path())
return nil return nil
} }

@ -8,16 +8,17 @@ import (
) )
type Field struct { type Field struct {
_type Symbol _type Symbol // type of data held by the field
name Symbol name Symbol // name of the field
sendNode Symbol sendNode Symbol // not sure what this is
bits *int bits *int // number of bits used to encode field?
low *float32 low *float32 // lower limit of field values
high *float32 high *float32 // upper limit of field values
flags *int32 flags *int32 // dunno what these flags do
serializer *Symbol serializer *Symbol // class on which the field was defined
serializerVersion *int32 serializerVersion *int32 // version of the class on which the field was defined
encoder *Symbol class *Class // source class on which the field was originally defined
encoder *Symbol // binary reader
} }
func (f Field) String() string { func (f Field) String() string {
@ -71,4 +72,5 @@ func (f *Field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, t *SymbolTa
f.serializerVersion = flat.FieldSerializerVersion f.serializerVersion = flat.FieldSerializerVersion
// panic if we don't have a send node cause that shit is corrupt yo // panic if we don't have a send node cause that shit is corrupt yo
f.sendNode = t.Symbol(int(*flat.SendNodeSym)) f.sendNode = t.Symbol(int(*flat.SendNodeSym))
Debug.Printf("new field: %v", f)
} }

@ -5,13 +5,13 @@ import (
"github.com/jordanorelli/hyperstone/bit" "github.com/jordanorelli/hyperstone/bit"
) )
// a fieldpath is a list of integers that is used to walk the type hierarchy to
// identify a given field on a given type.
type fieldPath struct { type fieldPath struct {
// slice of values, to be reused over and over // slice of values, to be reused over and over
vals []int vals []int
// index of the last valid value. e.g., the head of the stack. // index of the last valid value. e.g., the head of the stack.
last int last int
history [][]int
} }
func newFieldPath() *fieldPath { func newFieldPath() *fieldPath {
@ -42,17 +42,36 @@ func (f *fieldPath) replaceAll(fn func(v int) int) {
// reads the sequence of id values off of the provided bit reader given the // reads the sequence of id values off of the provided bit reader given the
// huffman tree of fieldpath ops rooted at the node n // huffman tree of fieldpath ops rooted at the node n
func (f *fieldPath) read(br bit.Reader, n node) error { func (f *fieldPath) read(br bit.Reader, n node, class *Class) error {
f.last = 0 f.last = 0
for fn := walk(n, br); fn != nil; fn = walk(n, br) { for fn := walk(n, br); fn != nil; fn = walk(n, br) {
if err := br.Err(); err != nil { if err := br.Err(); err != nil {
return fmt.Errorf("unable to read fieldpath: reader error: %v", err) return fmt.Errorf("unable to read fieldpath: reader error: %v", err)
} }
fn(f, br) fn(f, br)
Debug.Printf("fieldpath: %v", f.path())
// Debug.Printf("fieldpath: %v", f.getField(class))
} }
return nil return nil
} }
func (f *fieldPath) getField(class *Class) *Field {
if f.last > 0 {
for i := 0; i < f.last; i++ {
if f.vals[i] >= len(class.Fields) {
Info.Fatalf("bad access for field %d on class %v; class has only %d fields", f.vals[i], class, len(class.Fields))
}
field := class.Fields[f.vals[i]]
if field.class == nil {
Info.Fatalf("class %s field at %d is %v, has no class", class, f.vals[i], field)
} else {
class = class.Fields[f.vals[i]].class
}
}
}
return class.Fields[f.vals[f.last]]
}
// the subslice of valid index values that has been read on the fieldpath // the subslice of valid index values that has been read on the fieldpath
func (f *fieldPath) path() []int { func (f *fieldPath) path() []int {
return f.vals[:f.last+1] return f.vals[:f.last+1]

@ -37,6 +37,10 @@ func (n *Namespace) mergeClassInfo(ci *dota.CDemoClassInfo) {
n.idBits = int(math.Floor(math.Log2(float64(len(n.classIds))))) + 1 n.idBits = int(math.Floor(math.Log2(float64(len(n.classIds))))) + 1
} }
func (n *Namespace) hasClassinfo() bool {
return n.classIds != nil && len(n.classIds) > 0
}
// merges the send table data found in the replay protobufs. The send table // merges the send table data found in the replay protobufs. The send table
// data contains a specification for an entity type system. // data contains a specification for an entity type system.
func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error { func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
@ -58,6 +62,8 @@ func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
n.SymbolTable = SymbolTable(flat.GetSymbols()) n.SymbolTable = SymbolTable(flat.GetSymbols())
// the full set of fields that may appear on the classes is read first.
// each class will have a list of fields.
fields := make([]Field, len(flat.GetFields())) fields := make([]Field, len(flat.GetFields()))
for i, f := range flat.GetFields() { for i, f := range flat.GetFields() {
fields[i].fromProto(f, &n.SymbolTable) fields[i].fromProto(f, &n.SymbolTable)
@ -66,15 +72,15 @@ func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
n.classes = make(map[classId]*Class, len(flat.GetSerializers())) n.classes = make(map[classId]*Class, len(flat.GetSerializers()))
n.classesByName = make(map[string]map[int]*Class, len(flat.GetSerializers())) n.classesByName = make(map[string]map[int]*Class, len(flat.GetSerializers()))
// each serializer in the source data generates a class.
for _, c := range flat.GetSerializers() { for _, c := range flat.GetSerializers() {
name := n.Symbol(int(c.GetSerializerNameSym())) name := n.Symbol(int(c.GetSerializerNameSym()))
version := int(c.GetSerializerVersion()) version := int(c.GetSerializerVersion())
Debug.Printf("new class: %s %v", name, version)
class := Class{Name: name, Version: version} class := Class{Name: name, Version: version}
class.fromProto(c, fields) class.fromProto(c, fields)
Debug.Printf("new class: %v", class)
id := classId{name: name, version: version} id := classId{name: name, version: version}
n.classes[id] = &class n.classes[id] = &class
@ -85,6 +91,23 @@ func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
} }
} }
// some fields explicitly reference their origin class (P). that is is, if
// a given field F is included in some class C, the field F having an
// origin class P indicates that the class C has the class P as an
// ancestor. since these references are circular, we unpacked the fields
// first, then the classes, and now we re-visit the fields to set their
// origin class pointers, now that the classes exist.
for i := range fields {
f := &fields[i]
if f.serializer != nil {
if f.serializerVersion != nil {
f.class = n.classesByName[f.serializer.String()][int(*f.serializerVersion)]
} else {
f.class = n.NewestClass(f.serializer.String())
}
}
}
return br.Err() return br.Err()
} }
@ -96,12 +119,8 @@ func (n *Namespace) Class(name string, version int) *Class {
return n.classesByName[name][version] return n.classesByName[name][version]
} }
func (n *Namespace) ClassByNetId(id int) *Class { // retrieves the newest version of a class, as referenced by name.
name, ok := n.classIds[id] func (n *Namespace) NewestClass(name string) *Class {
if !ok {
Debug.Printf("can't find class name for net id %d", id)
return nil
}
versions, newest := n.classesByName[name], -1 versions, newest := n.classesByName[name], -1
for v, _ := range versions { for v, _ := range versions {
if v > newest { if v > newest {
@ -109,8 +128,15 @@ func (n *Namespace) ClassByNetId(id int) *Class {
} }
} }
if newest == -1 { if newest == -1 {
Debug.Printf("class %s has no known versions in its version map", name) Info.Fatalf("class %s has no known versions in its version map", name)
return nil
} }
return versions[newest] return versions[newest]
} }
func (n *Namespace) ClassByNetId(id int) *Class {
name, ok := n.classIds[id]
if !ok {
Info.Fatalf("can't find class name for net id %d", id)
}
return n.NewestClass(name)
}

Loading…
Cancel
Save