Example #1
0
// 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
}
Example #2
0
// 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
}