// Internal callback for CSVCMsg_PacketEntities. func (p *Parser) onCSVCMsg_PacketEntities(m *dota.CSVCMsg_PacketEntities) error { // Skip processing if we're configured not to. if !p.ProcessPacketEntities { return nil } _debugfl(5, "pTick=%d isDelta=%v deltaFrom=%d updatedEntries=%d maxEntries=%d baseline=%d updateBaseline=%v", p.Tick, m.GetIsDelta(), m.GetDeltaFrom(), m.GetUpdatedEntries(), m.GetMaxEntries(), m.GetBaseline(), m.GetUpdateBaseline()) // Skip processing full updates after the first. We'll process deltas instead. if !m.GetIsDelta() && p.packetEntityFullPackets > 0 { return nil } // Updates pending updates := []*packetEntityUpdate{} r := NewReader(m.GetEntityData()) index := int32(-1) pe := &PacketEntity{} ok := false // Iterate over all entries for i := 0; i < int(m.GetUpdatedEntries()); i++ { // Read the index delta from the buffer. This is an implementation // from Alice. An alternate implementation from Yasha has the same result. delta := r.readUBitVar() index += int32(delta) + 1 _debugfl(5, "index delta is %d to %d", delta, index) // Read the type of update based on two booleans. // This appears to be backwards from source 1: // true+true used to be "create", now appears to be false+true? // This seems suspcious. eventType := EntityEventType_None if r.readBoolean() { if r.readBoolean() { eventType = EntityEventType_Delete } else { eventType = EntityEventType_Leave } } else { if r.readBoolean() { eventType = EntityEventType_Create } else { eventType = EntityEventType_Update } } _debugfl(5, "update type is %d, %v", eventType, index) // Proceed based on the update type switch eventType { case EntityEventType_Create: // Create a new PacketEntity. pe = &PacketEntity{ Index: index, ClassId: int32(r.readBits(p.classIdSize)), Serial: int32(r.readBits(17)), Properties: NewProperties(), } // We don't know what this is used for. r.readVarUint32() // Get the associated class if pe.ClassName, ok = p.ClassInfo[pe.ClassId]; !ok { _panicf("unable to find class %d", pe.ClassId) } // Get the associated baseline if pe.ClassBaseline, ok = p.ClassBaselines[pe.ClassId]; !ok { _panicf("unable to find class baseline %d", pe.ClassId) } // Get the associated serializer if pe.flatTbl, ok = p.serializers[pe.ClassName][0]; !ok { _panicf("unable to find serializer for class %s", pe.ClassName) } // Register the packetEntity with the parser. p.PacketEntities[index] = pe // Read properties pe.Properties.Merge(ReadProperties(r, pe.flatTbl)) case EntityEventType_Update: // Find the existing packetEntity pe, ok = p.PacketEntities[index] if !ok { _panicf("unable to find packet entity %d for update", index) } // Read properties and update the packetEntity pe.Properties.Merge(ReadProperties(r, pe.flatTbl)) case EntityEventType_Delete: if pe, ok = p.PacketEntities[index]; !ok { _panicf("unable to find packet entity %d for delete", index) } delete(p.PacketEntities, index) case EntityEventType_Leave: // TODO: Decide how we want to handle this } // Add the update to the list of pending updates. updates = append(updates, &packetEntityUpdate{pe, eventType}) } // Update the full packet count. if !m.GetIsDelta() { p.packetEntityFullPackets += 1 } // Offer all packet entity updates to callback handlers. This is done // only after all updates have been processed to ensure consistent state. for _, u := range updates { for _, h := range p.packetEntityHandlers { if err := h(u.pe, u.t); err != nil { return err } } } return nil }
// Internal callback for CSVCMsg_PacketEntities. func (p *Parser) onCSVCMsg_PacketEntities(m *dota.CSVCMsg_PacketEntities) error { // XXX: Remove once we've gotten readProperties working. return nil defer func() { if err := recover(); err != nil { _debugf("recovered: %s", err) } }() _debugf("pTick=%d isDelta=%v deltaFrom=%d updatedEntries=%d maxEntries=%d baseline=%d updateBaseline=%v", p.Tick, m.GetIsDelta(), m.GetDeltaFrom(), m.GetUpdatedEntries(), m.GetMaxEntries(), m.GetBaseline(), m.GetUpdateBaseline()) r := newReader(m.GetEntityData()) index := int32(-1) ok := false // Iterate over all entries for i := 0; i < int(m.GetUpdatedEntries()); i++ { // Read the index delta from the buffer. This is an implementation // from Alice. An alternate implementation from Yasha has the same result. delta := r.readUBitVar() index += int32(delta) + 1 _debugf("index delta is %d to %d", delta, index) // Read the type of update based on two booleans. // This appears to be backwards from source 1: // true+true used to be "create", now appears to be false+true? // This seems suspcious. updateType := " " if r.readBoolean() { if r.readBoolean() { updateType = "D" } else { updateType = "?" } } else { if r.readBoolean() { updateType = "C" } else { updateType = "U" } } _debugf("update type is %s", updateType) // Proceed based on the update type switch updateType { case "C": // Create a new packetEntity. pe := &packetEntity{ index: index, classId: int32(r.readBits(p.classIdSize)), properties: make(map[string]interface{}), } // Skip the 10 serial bits for now. r.seekBits(10) // Get the associated class. if pe.className, ok = p.classInfo[pe.classId]; !ok { _panicf("unable to find class %d", pe.classId) } // Get the associated send table. if pe.sendTable, ok = p.sendTables.getTableByName(pe.className); !ok { _panicf("unable to find sendtable for class %s", pe.className) } // Register the packetEntity with the parser. p.packetEntities[index] = pe _debugf("created a pe: %+v", pe) // Read properties and set them in the packetEntity pe.properties = readProperties(r, pe.sendTable) case "U": // Find the existing packetEntity pe, ok := p.packetEntities[index] if !ok { _panicf("unable to find packet entity %d for update", index) } // Read properties and update the packetEntity for k, v := range readProperties(r, pe.sendTable) { pe.properties[k] = v } case "D": if _, ok := p.packetEntities[index]; !ok { _panicf("unable to find packet entity %d for delete", index) } else { delete(p.packetEntities, index) } } } return nil }