Skip to content

Commit c5aace3

Browse files
committed
fix array decoding #509
1 parent 06fbbc5 commit c5aace3

File tree

6 files changed

+77
-27
lines changed

6 files changed

+77
-27
lines changed

pkg/demoinfocs/datatables.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
703703
func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
704704
const inventoryCapacity = 64
705705

706-
var inventorySize uint64 = 64
706+
inventorySize := 64
707707

708708
type eq struct {
709709
*common.Equipment
@@ -728,7 +728,7 @@ func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
728728
setPlayerInventory := func() {
729729
inventory := make(map[int]*common.Equipment, inventorySize)
730730

731-
for i := uint64(0); i < inventorySize; i++ {
731+
for i := 0; i < inventorySize; i++ {
732732
val := pawnEntity.Property(playerWeaponPrefixS2 + fmt.Sprintf("%04d", i)).Value()
733733
if val.Any == nil {
734734
continue
@@ -742,7 +742,7 @@ func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
742742
}
743743

744744
pawnEntity.Property("m_pWeaponServices.m_hMyWeapons").OnUpdate(func(pv st.PropertyValue) {
745-
inventorySize = pv.S2UInt64()
745+
inventorySize = len(pv.S2Array())
746746
setPlayerInventory()
747747
})
748748

@@ -758,7 +758,7 @@ func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
758758

759759
entityWasCreated := entityID != constants.EntityHandleIndexMaskSource2
760760

761-
if uint64(i) < inventorySize {
761+
if i < inventorySize {
762762
if entityWasCreated {
763763
existingWeapon, exists := playerInventory[i]
764764
if exists {

pkg/demoinfocs/sendtables/propdecoder.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ func (v PropertyValue) S2UInt64() uint64 {
152152
return v.Any.(uint64)
153153
}
154154

155+
func (v PropertyValue) S2Array() []any {
156+
return v.Any.([]any)
157+
}
158+
155159
func (v PropertyValue) S2UInt32() uint32 {
156160
return v.Any.(uint32)
157161
}

pkg/demoinfocs/sendtables2/entity.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,21 @@ func (p property) Name() string {
5858
}
5959

6060
func (p property) Value() st.PropertyValue {
61+
v := p.entity.Get(p.name)
62+
63+
fs, ok := v.(*fieldState)
64+
if ok {
65+
v = fs.state
66+
}
67+
6168
return st.PropertyValue{
6269
VectorVal: r3.Vector{},
6370
IntVal: 0,
6471
Int64Val: 0,
6572
ArrayVal: nil,
6673
StringVal: "",
6774
FloatVal: 0,
68-
Any: p.entity.Get(p.name),
75+
Any: v,
6976
S2: true,
7077
}
7178
}
@@ -416,12 +423,30 @@ func (e *Entity) readFields(r *reader, paths *[]*fieldPath) {
416423
readFieldPaths(r, paths)
417424

418425
for _, fp := range *paths {
419-
decoder := e.class.serializer.getDecoderForFieldPath(fp, 0)
426+
f := e.class.serializer.getFieldForFieldPath(fp, 0)
427+
name := e.class.getNameForFieldPath(fp)
428+
decoder, base := e.class.serializer.getDecoderForFieldPath2(fp, 0)
420429

421430
val := decoder(r)
422-
e.state.set(fp, val)
423431

424-
for _, h := range e.updateHandlers[e.class.getNameForFieldPath(fp)] {
432+
if base && (f.model == fieldModelVariableArray || f.model == fieldModelVariableTable) {
433+
oldFS := e.state.get(fp)
434+
fs := newFieldState()
435+
436+
fs.state = make([]interface{}, val.(uint64))
437+
438+
if oldFS != nil {
439+
copy(fs.state, oldFS.(*fieldState).state[:min(len(fs.state), len(oldFS.(*fieldState).state))])
440+
}
441+
442+
e.state.set(fp, fs)
443+
444+
val = fs.state
445+
} else {
446+
e.state.set(fp, val)
447+
}
448+
449+
for _, h := range e.updateHandlers[name] {
425450
h(st.PropertyValue{
426451
VectorVal: r3.Vector{},
427452
IntVal: 0,
@@ -446,7 +471,7 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error {
446471
index = int32(-1)
447472
updates = int(m.GetUpdatedEntries())
448473
cmd uint32
449-
classId int32
474+
classID int32
450475
serial int32
451476
)
452477

@@ -485,18 +510,18 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error {
485510
}
486511
if cmd&0x01 == 0 {
487512
if cmd&0x02 != 0 {
488-
classId = int32(r.readBits(p.classIdSize))
513+
classID = int32(r.readBits(p.classIdSize))
489514
serial = int32(r.readBits(17))
490515
r.readVarUint32()
491516

492-
class := p.classesById[classId]
517+
class := p.classesById[classID]
493518
if class == nil {
494-
_panicf("unable to find new class %d", classId)
519+
_panicf("unable to find new class %d", classID)
495520
}
496521

497-
baseline := p.classBaselines[classId]
522+
baseline := p.classBaselines[classID]
498523
if baseline == nil {
499-
_panicf("unable to find new baseline %d", classId)
524+
_panicf("unable to find new baseline %d", classID)
500525
}
501526

502527
e = newEntity(index, serial, class)

pkg/demoinfocs/sendtables2/field.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -208,31 +208,34 @@ func (f *field) getTypeForFieldPath(fp *fieldPath, pos int) *fieldType {
208208
return f.fieldType
209209
}
210210

211-
func (f *field) getDecoderForFieldPath(fp *fieldPath, pos int) fieldDecoder {
211+
func (f *field) getDecoderForFieldPath(fp *fieldPath, pos int) (fieldDecoder, bool) {
212212
switch f.model {
213213
case fieldModelFixedArray:
214-
return f.decoder
214+
return f.decoder, false
215215

216216
case fieldModelFixedTable:
217217
if fp.last == pos-1 {
218-
return f.baseDecoder
218+
return f.baseDecoder, true
219219
}
220-
return f.serializer.getDecoderForFieldPath(fp, pos)
220+
221+
return f.serializer.getDecoderForFieldPath2(fp, pos)
221222

222223
case fieldModelVariableArray:
223224
if fp.last == pos {
224-
return f.childDecoder
225+
return f.childDecoder, false
225226
}
226-
return f.baseDecoder
227+
228+
return f.baseDecoder, true
227229

228230
case fieldModelVariableTable:
229231
if fp.last >= pos+1 {
230-
return f.serializer.getDecoderForFieldPath(fp, pos+1)
232+
return f.serializer.getDecoderForFieldPath2(fp, pos+1)
231233
}
232-
return f.baseDecoder
234+
235+
return f.baseDecoder, true
233236
}
234237

235-
return f.decoder
238+
return f.decoder, false
236239
}
237240

238241
func (f *field) getFieldPathForName(fp *fieldPath, name string) bool {

pkg/demoinfocs/sendtables2/field_state.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@ func (s *fieldState) set(fp *fieldPath, v interface{}) {
3434
z := 0
3535
for i := 0; i <= fp.last; i++ {
3636
z = fp.path[i]
37-
if y := len(x.state); y < z+2 {
38-
z := make([]interface{}, max(z+2, y*2))
39-
copy(z, x.state)
40-
x.state = z
37+
if y := len(x.state); y <= z {
38+
newCap := max(z+2, y*2)
39+
if newCap > cap(x.state) {
40+
newSlice := make([]interface{}, z+1, newCap)
41+
copy(newSlice, x.state)
42+
x.state = newSlice
43+
} else {
44+
// Re-slice to update the length without allocating new memory
45+
x.state = x.state[:z+1]
46+
}
4147
}
4248
if i == fp.last {
4349
if _, ok := x.state[z].(*fieldState); !ok {

pkg/demoinfocs/sendtables2/serializer.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ func (s *serializer) getDecoderForFieldPath(fp *fieldPath, pos int) fieldDecoder
4545
if len(s.fields) <= index {
4646
_panicf("serializer %s: field path %s has no field (%d)", s.name, fp, index)
4747
}
48+
49+
dec, _ := s.fields[index].getDecoderForFieldPath(fp, pos+1)
50+
51+
return dec
52+
}
53+
54+
func (s *serializer) getDecoderForFieldPath2(fp *fieldPath, pos int) (fieldDecoder, bool) {
55+
index := fp.path[pos]
56+
if len(s.fields) <= index {
57+
_panicf("serializer %s: field path %s has no field (%d)", s.name, fp, index)
58+
}
59+
4860
return s.fields[index].getDecoderForFieldPath(fp, pos+1)
4961
}
5062

0 commit comments

Comments
 (0)