// Dumps the json representation of the new FlattenedSerializer Packets func dumpSendTables(m *dota.CDemoSendTables) string { // This packet just contains a single large buffer r := newReader(m.GetData()) // The buffer starts with a varint encoded length size := int(r.readVarUint32()) if size != r.remBytes() { _panicf("expected %d additional bytes, got %d", size, r.remBytes()) } // Read the rest of the buffer as a CSVCMsg_FlattenedSerializer. buf := r.readBytes(size) msg := &dota.CSVCMsg_FlattenedSerializer{} if err := proto.Unmarshal(buf, msg); err != nil { _panicf("cannot decode proto: %s", err) } str, _ := json.MarshalIndent(msg, "", " ") // two space ident return string(str) }
// Parses a CDemoSendTables packet func (p *Parser) parseSendTables(m *dota.CDemoSendTables, pst *propertySerializerTable) *flattenedSerializers { // This packet just contains a single large buffer r := newReader(m.GetData()) // The buffer starts with a varint encoded length size := r.readVarUint32() if size != r.remBytes() { _panicf("expected %d additional bytes, got %d", size, r.remBytes()) } // Read the rest of the buffer as a CSVCMsg_FlattenedSerializer. buf := r.readBytes(size) msg := &dota.CSVCMsg_FlattenedSerializer{} if err := proto.Unmarshal(buf, msg); err != nil { _panicf("cannot decode proto: %s", err) } // Create the flattenedSerializers object and fill it fs := &flattenedSerializers{ Serializers: make(map[string]map[int32]*dt), proto: msg, pst: pst, build: p.GameBuild, } // Iterate through all flattened serializers and fill their properties for _, o := range msg.GetSerializers() { sName := msg.GetSymbols()[o.GetSerializerNameSym()] sVer := o.GetSerializerVersion() if fs.Serializers[sName] == nil { fs.Serializers[sName] = make(map[int32]*dt) } fs.Serializers[sName][sVer] = fs.recurseTable(o) } return fs }
// Parses a CDemoSendTables buffer, producing a sendTables object. func parseSendTables(m *dota.CDemoSendTables) (*sendTables, error) { // This packet just contains a single large buffer r := newReader(m.GetData()) // The buffer starts with a varint encoded length size := int(r.readVarUint32()) if size != r.remBytes() { _panicf("expected %d additional bytes, got %d", size, r.remBytes()) } // Read the rest of the buffer as a CSVCMsg_FlattenedSerializer. buf := r.readBytes(size) msg := &dota.CSVCMsg_FlattenedSerializer{} if err := proto.Unmarshal(buf, msg); err != nil { _panicf("cannot decode proto: %s", err) } // Create a list of sendProps props := make([]*sendProp, 0) for _, o := range msg.GetFields() { p := &sendProp{ dtIndex: o.GetVarTypeSym(), dtName: msg.GetSymbols()[o.GetVarTypeSym()], varIndex: o.GetVarNameSym(), varName: msg.GetSymbols()[o.GetVarNameSym()], bitCount: o.BitCount, lowValue: o.LowValue, highValue: o.HighValue, fieldSerializerVersion: o.FieldSerializerVersion, sendNodeIndex: o.GetSendNodeSym(), sendNodeName: msg.GetSymbols()[o.GetSendNodeSym()], } if o.EncodeFlags != nil { p.encodeFlags = proto.Uint32(uint32(*o.EncodeFlags)) } if o.FieldSerializerNameSym != nil { p.fieldSerializerIndex = o.FieldSerializerNameSym p.fieldSerializerName = proto.String(msg.GetSymbols()[o.GetFieldSerializerNameSym()]) } props = append(props, p) } // Create a map of sendTables tables := make(map[string]*sendTable) for _, o := range msg.GetSerializers() { // Create the basic table. t := &sendTable{ index: o.GetSerializerNameSym(), name: msg.GetSymbols()[o.GetSerializerNameSym()], version: o.GetSerializerVersion(), props: make([]*sendProp, 0), } // Iterate through prop field indexes. for _, pid := range o.GetFieldsIndex() { // Get the property at the given index. prop := props[int(pid)] // If the prop has a serializer, inherit its properties if prop.fieldSerializerIndex != nil { // Find the serializer. ser, ok := tables[*prop.fieldSerializerName] if !ok { _panicf("unable to find serializer %d (%s)", *prop.fieldSerializerIndex, *prop.fieldSerializerName) } // Iterate through serializer props, adding them to the table. // Property names are subclassed as "%propVarName.%serializerVarName" for _, p := range ser.props { p2 := p.copy() p2.serializedFromIndex = prop.fieldSerializerIndex p2.serializedFromName = prop.fieldSerializerName p2.varName = _sprintf("%s.%s", prop.varName, p.varName) t.props = append(t.props, p2) } continue } // For normal props (without serializers), extract base type name // and element count, then store those as props in the table. typName, typCount, err := prop.typeInfo() if err != nil { _panicf("unable to flatten property %s: %s", prop.Describe(), err) } // Iterate through elements, adding them as new properties to the table. // Single element properties are named using the property var name. // Multiple element properties are named as "%propVarName.N". for i := 0; i < typCount; i++ { p2 := prop.copy() p2.dtName = typName if typCount > 1 { p2.varName = _sprintf("%s.%04d", prop.varName, i) } t.props = append(t.props, p2) } } tables[t.name] = t } // Return a sendTables object return &sendTables{tables: tables, props: props}, nil }