diff --git a/pkg/demoinfocs/sendtables2/entity.go b/pkg/demoinfocs/sendtables2/entity.go index e86d6424..25994133 100644 --- a/pkg/demoinfocs/sendtables2/entity.go +++ b/pkg/demoinfocs/sendtables2/entity.go @@ -438,6 +438,38 @@ func (e *Entity) readFields(r *reader, paths *[]*fieldPath) { } } +const ( + updateFlagDelete = 0b10 + updateFlagVisibleInPVS = 0b10000 +) + +type updateType = uint32 + +const ( + updateTypeEnter updateType = iota + updateTypeLeave + updateTypeDelta + updateTypePreserve +) + +func readEntityUpdateType(r *reader, hasVisBits uint32) (updateType, uint32) { + flags := r.readBits(2) + if flags&0x01 != 0 { + return updateTypeLeave, flags + } + if flags&0x02 != 0 { + return updateTypeEnter, flags + } + if hasVisBits != 0 { + flags = r.readBits(2) << 3 + if flags&0x08 != 0 { + return updateTypePreserve, flags + } + } + + return updateTypeDelta, flags +} + // Internal Callback for OnCSVCMsg_PacketEntities. func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error { r := newReader(m.GetEntityData()) @@ -445,7 +477,6 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error { var ( index = int32(-1) updates = int(m.GetUpdatedEntries()) - cmd uint32 classId int32 serial int32 ) @@ -467,6 +498,7 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error { paths = make([]*fieldPath, 0) ) + hasVisBits := m.GetHasPvsVisBits() for ; updates > 0; updates-- { var ( e *Entity @@ -476,64 +508,62 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error { next := index + int32(r.readUBitVar()) + 1 index = next - cmd = r.readBits(2) - if cmd == 0 && m.GetHasPvsVisBits() > 0 { - cmd = r.readBits(2) << 3 - if cmd&0x08 == 8 { - continue - } - } - if cmd&0x01 == 0 { - if cmd&0x02 != 0 { - classId = int32(r.readBits(p.classIdSize)) - serial = int32(r.readBits(17)) - r.readVarUint32() - - class := p.classesById[classId] - if class == nil { - _panicf("unable to find new class %d", classId) - } + updateType, flags := readEntityUpdateType(r, hasVisBits) + switch updateType { + case updateTypeEnter: + classId = int32(r.readBits(p.classIdSize)) + serial = int32(r.readBits(17)) + r.readVarUint32() - baseline := p.classBaselines[classId] - if baseline == nil { - _panicf("unable to find new baseline %d", classId) - } + class := p.classesById[classId] + if class == nil { + _panicf("unable to find new class %d", classId) + } - e = newEntity(index, serial, class) - p.entities[index] = e + baseline := p.classBaselines[classId] + if baseline == nil { + _panicf("unable to find new baseline %d", classId) + } - e.readFields(newReader(baseline), &paths) - paths = paths[:0] + e = newEntity(index, serial, class) + p.entities[index] = e - e.readFields(r, &paths) - paths = paths[:0] + e.readFields(newReader(baseline), &paths) + paths = paths[:0] - // Fire created-handlers so update-handlers can be registered - for _, h := range class.createdHandlers { - h(e) - } + e.readFields(r, &paths) + paths = paths[:0] - // Fire all post-creation actions - for _, f := range e.onCreateFinished { - f() - } + // Fire created-handlers so update-handlers can be registered + for _, h := range class.createdHandlers { + h(e) + } - op = st.EntityOpCreated | st.EntityOpEntered - } else { - if e = p.entities[index]; e == nil { - _panicf("unable to find existing entity %d", index) - } + // Fire all post-creation actions + for _, f := range e.onCreateFinished { + f() + } - op = st.EntityOpUpdated - if !e.active { - e.active = true - op |= st.EntityOpEntered - } + op = st.EntityOpCreated | st.EntityOpEntered + case updateTypeDelta: + if e = p.entities[index]; e == nil { + _panicf("unable to find existing entity %d", index) + } - e.readFields(r, &paths) - paths = paths[:0] + op = st.EntityOpUpdated + if !e.active { + e.active = true + op |= st.EntityOpEntered } - } else { + + e.readFields(r, &paths) + paths = paths[:0] + // todo: handle visibility + // visibleInPVS := hasVisBits == 0 || flags&updateFlagVisibleInPVS != 0 + // fmt.Println("visible in pvs", visibleInPVS) + case updateTypePreserve: + // visibleInPVS := hasVisBits == 0 || flags&updateFlagVisibleInPVS != 0 + case updateTypeLeave: e = p.entities[index] if e == nil { continue @@ -545,7 +575,7 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error { } op = st.EntityOpLeft - if cmd&0x02 != 0 { + if flags&updateFlagDelete != 0 { op |= st.EntityOpDeleted e.Destroy()