decode the fields

master
Jordan Orelli 8 years ago
parent def4a5224d
commit 3c32042d65

@ -0,0 +1,17 @@
package ent
import (
"strconv"
)
type array struct {
slots []interface{}
_slotType string
decoder
}
func (a *array) slotName(slot int) string { return strconv.Itoa(slot) }
func (a *array) slotValue(slot int) interface{} { return a.slots[slot] }
func (a *array) slotType(slot int) string { return a._slotType }
func (a *array) slotDecoder(slot int) decoder { return a.decoder }
func (a *array) setSlotValue(slot int, val interface{}) { a.slots[slot] = val }

@ -19,12 +19,17 @@ type Class struct {
fieldNames map[string]int
}
func (c *Class) New(serial int) *Entity {
return &Entity{
Class: c,
slots: make([]interface{}, len(c.Fields)),
serial: serial,
func (c *Class) New(serial int, baseline bool) *Entity {
e := &Entity{
Class: c,
slots: make([]interface{}, len(c.Fields)),
serial: serial,
isBaseline: baseline,
}
for slot := range e.slots {
e.slots[slot] = c.Fields[slot].initializer()
}
return e
}
func (c Class) String() string {

@ -0,0 +1,20 @@
package ent
import (
"strconv"
)
type cutlVector struct {
slots []interface{}
_slotType string
decoder
}
func (v *cutlVector) slotName(slot int) string { return strconv.Itoa(slot) }
func (v *cutlVector) slotValue(slot int) interface{} { return v.slots[slot] }
func (v *cutlVector) slotType(slot int) string { return v._slotType }
func (v *cutlVector) slotDecoder(slot int) decoder { return v.decoder }
func (v *cutlVector) setSlotValue(slot int, val interface{}) {
v.slots[slot] = val
}

@ -44,26 +44,27 @@ func newFieldDecoder(n *Namespace, f *Field) decoder {
// for compound types such as handles, vectors (in the c++ std::vector
// sense), and arrays
ts := parseTypeName(n, typeName)
switch ts.kind {
switch f.typeSpec.kind {
case t_element:
Debug.Printf("weird typespec: we shouldn't have elements here: %v", ts)
Debug.Printf("weird typespec: we shouldn't have elements here: %v", f.typeSpec)
return func(bit.Reader) interface{} {
Info.Fatalf("unable to decode element of type: %v", ts.name)
Info.Fatalf("unable to decode element of type: %v", f.typeSpec.name)
return nil
}
case t_object:
return func(br bit.Reader) interface{} {
Debug.Printf("unable to decode object of type: %v", ts.name)
Debug.Printf("unable to decode object of type: %v", f.typeSpec.name)
return decodeVarInt32(br)
}
case t_array:
return arrayDecoder(n, f, ts)
return arrayDecoder(n, f)
case t_template:
return templateDecoder(f, ts)
return templateDecoder(f)
case t_pointer:
return decodeBool
}
return nil
panic("fart")
}
func decodeBool(br bit.Reader) interface{} { return bit.ReadBool(br) }
@ -85,10 +86,8 @@ func decodeColor(br bit.Reader) interface{} {
func entityDecoder(c *Class) decoder {
return func(br bit.Reader) interface{} {
if bit.ReadBool(br) {
return c.New(-1)
}
return nil
bit.ReadBool(br) // what does this do
return c.New(-1, false)
}
}
@ -201,18 +200,28 @@ func qangleDecoder(f *Field) decoder {
}
}
func arrayDecoder(n *Namespace, f *Field, ts typeSpec) decoder {
return decodeVarInt32
func arrayDecoder(n *Namespace, f *Field) decoder {
return func(br bit.Reader) interface{} {
Debug.Printf("dunno what this int32 val does in array decoder: %d", bit.ReadVarInt32(br))
if f.initializer != nil {
return f.initializer()
}
return nil
}
}
func templateDecoder(f *Field, ts typeSpec) decoder {
switch ts.template {
func templateDecoder(f *Field) decoder {
switch f.typeSpec.template {
case "CHandle":
return decodeVarInt32
case "CStrongHandle":
return decodeVarInt64
case "CUtlVector":
return decodeVarInt32
return func(br bit.Reader) interface{} {
v := decodeVarInt32(br)
Debug.Printf("dunno what this varint is for in the cutlvector decoder: %v", v)
return v
}
}
return nil
}

@ -72,7 +72,7 @@ func (d *Dict) createEntity(id int) error {
if class == nil {
return fmt.Errorf("unable to create entity %d: no class found for class name %s, version %d", className, classV)
}
e := class.New(serial)
e := class.New(serial, false)
d.entities[id] = e
Debug.Printf("create entity id: %d serial: %d classId: %d className: %v class: %v\n", id, serial, classId, className, class)
return fillSlots(e, class.Name.String(), d.sr, d.br)
@ -190,7 +190,7 @@ func (d *Dict) syncBaselines() {
}
if c.baseline == nil {
c.baseline = c.New(-1)
c.baseline = c.New(-1, true)
}
if e.Value == nil || len(e.Value) == 0 {

@ -2,12 +2,22 @@ package ent
type Entity struct {
*Class
serial int
slots []interface{}
serial int
slots []interface{}
isBaseline bool
}
func (e *Entity) slotName(n int) string { return e.Class.Fields[n].name.String() }
func (e *Entity) slotType(n int) string { return e.Class.Fields[n]._type.String() }
func (e *Entity) slotValue(n int) interface{} { return e.slots[n] }
func (e *Entity) slotName(n int) string { return e.Class.Fields[n].name.String() }
func (e *Entity) slotType(n int) string { return e.Class.Fields[n]._type.String() }
func (e *Entity) slotValue(n int) interface{} {
v := e.slots[n]
if v != nil {
return v
}
if !e.isBaseline && e.Class.baseline != nil {
return e.Class.baseline.slotValue(n)
}
return nil
}
func (e *Entity) slotDecoder(n int) decoder { return e.Class.Fields[n].decoder }
func (e *Entity) setSlotValue(n int, v interface{}) { e.slots[n] = v }

@ -8,7 +8,8 @@ import (
)
type Field struct {
_type Symbol // type of data held by the field
_type Symbol // type of data held by the field
typeSpec typeSpec
name Symbol // name of the field
sendNode Symbol // not sure what this is
bits uint // number of bits used to encode field?
@ -20,7 +21,8 @@ type Field struct {
class *Class // source class on which the field was originally defined
encoder *Symbol // binary encoder, named explicitly in protobuf
decoder // decodes field values from a bit stream
isTemplate bool // whether or not the field is a template type
initializer func() interface{}
isTemplate bool // whether or not the field is a template type
templateType string
elemType string
}
@ -56,6 +58,7 @@ func (f *Field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, t *SymbolTa
f.flags = int(flat.GetEncodeFlags())
f.low = flat.GetLowValue()
f.high = flat.GetHighValue()
f.initializer = nilInitializer
if flat.FieldSerializerNameSym == nil {
f.serializer = nil
@ -69,3 +72,30 @@ func (f *Field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, t *SymbolTa
f.sendNode = t.Symbol(int(*flat.SendNodeSym))
Debug.Printf("new field: %v", f)
}
// creates a new field which is a sort of virtual field that represents what a
// field woudl look like if we had one for a container field's elements.
// honestly this is a really shitty hack it just seems easier than rewriting
// the newFieldDecoder logic.
func (f *Field) memberField() *Field {
mf := new(Field)
*mf = *f
mf.typeSpec = *f.typeSpec.member
// yeahhhh
mf._type = Symbol{0, &SymbolTable{mf.typeSpec.name}}
return mf
}
func (f *Field) isContainer() bool {
if f.typeSpec.kind == t_array {
return true
}
if f.typeSpec.kind == t_template {
if f.typeSpec.template == "CUtlVector" {
return true
}
}
return false
}
func nilInitializer() interface{} { return nil }

@ -86,7 +86,5 @@ func floatDecoder(f *Field) decoder {
// reads an IEEE 754 binary float value off of the stream
func ieeeFloat32Decoder(br bit.Reader) interface{} {
u := uint32(br.ReadBits(32))
Debug.Printf("ieee float32 decode bits: %d", u)
return math.Float32frombits(u)
return math.Float32frombits(uint32(br.ReadBits(32)))
}

@ -107,6 +107,32 @@ func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
}
}
// for some fields, we want to initialize a zero value on the baseline
// instance. specifically, we do this for arrays so that we can't try
// to index into nil.
f.typeSpec = parseTypeName(n, f._type.String())
if f.isContainer() {
mf := f.memberField()
fn := newFieldDecoder(n, mf)
if f.typeSpec.kind == t_array {
f.initializer = func() interface{} {
return &array{
slots: make([]interface{}, f.typeSpec.size),
_slotType: mf._type.String(),
decoder: fn,
}
}
} else if f.typeSpec.kind == t_template && f.typeSpec.template == "CUtlVector" {
f.initializer = func() interface{} {
return &cutlVector{
slots: make([]interface{}, f.typeSpec.size),
_slotType: mf._type.String(),
decoder: fn,
}
}
}
}
// we also wait until after we've discovered all of the classes to
// build the field decoder functions, because some fields are
// themselves entities.

@ -21,22 +21,24 @@ func (s selection) path() []int { return s.vals[:s.count] }
func (s selection) fill(offset int, displayPath string, dest slotted, br bit.Reader) error {
slot := s.vals[offset]
switch s.count - offset {
case 0:
if s.count-offset <= 0 {
panic("selection makes no sense")
}
switch s.count - offset {
case 1:
fn := dest.slotDecoder(slot)
if fn == nil {
switch v := dest.(type) {
switch dest.(type) {
case *Entity:
Debug.Printf("%s %s (%s)", s, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot))
Info.Fatalf("%v entity has no decoder for slot %d (%v)", v.Class, slot, v.Class.Fields[slot])
return nil
// Info.Fatalf("%v entity has no decoder for slot %d (%v)", v.Class, slot, v.Class.Fields[slot])
default:
Info.Fatalf("slotted value %v has no decoder for slot %d", dest, slot)
Info.Printf("slotted value %v has no decoder for slot %d", dest, slot)
return nil
}
}
old := dest.slotValue(slot)
Debug.Printf("%s %s (%s): %v", s, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot), old)
val := fn(br)
dest.setSlotValue(slot, val)
Debug.Printf("%s %s (%s): %v -> %v", s, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot), old, val)
@ -45,7 +47,7 @@ func (s selection) fill(offset int, displayPath string, dest slotted, br bit.Rea
v := dest.slotValue(slot)
vs, ok := v.(slotted)
if !ok {
Info.Fatalf("child selection %s at offset %d refers to a slot (%d: %s) that contains a non-slotted type: %s", s, offset, slot, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot))
Info.Printf("child selection %s at offset %d refers to a slot (%d: %s) that contains a non-slotted type: %s with value: %v", s, offset, slot, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot), v)
return fmt.Errorf("child selection refers to a slot that doesn't contain a slotted value")
}
return s.fill(offset+1, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), vs, br)

@ -11,6 +11,7 @@ const (
t_object // c++ object type that is not a known element class
t_array // c++ array type
t_template // c++ template type
t_pointer // c++ pointer
)
// constant identifiers
@ -40,6 +41,13 @@ func parseTypeName(n *Namespace, s string) typeSpec {
return t
}
if strings.HasSuffix(s, "*") {
t.kind = t_pointer
t.member = new(typeSpec)
*t.member = parseTypeName(n, s[:len(s)-2])
return t
}
// presumably this is some sort of array type
if strings.ContainsRune(s, '[') {
memName, count := parseArrayName(s)

Loading…
Cancel
Save