Skip to content

Commit 600fc4e

Browse files
authored
Merge pull request #510 from markus-wa/fix-array-decoding
fix array decoding
2 parents 24ab81c + 18bd5cb commit 600fc4e

File tree

8 files changed

+93
-29
lines changed

8 files changed

+93
-29
lines changed

pkg/demoinfocs/datatables.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ func (p *parser) bindBomb() {
112112
bombEntity.Property("m_bStartedArming").OnUpdate(func(val st.PropertyValue) {
113113
if val.BoolVal() {
114114
if p.isSource2() {
115-
planter := p.gameState.Participants().FindByPawnHandle(bombEntity.PropertyValueMust("m_hOwnerEntity").Handle())
115+
planterHandle := bombEntity.PropertyValueMust("m_hOwnerEntity").Handle()
116+
ctlHandle := p.gameState.entities[entityIDFromHandle(planterHandle, true)].PropertyValueMust("m_hController").Handle()
117+
ctlID := p.gameState.entities[entityIDFromHandle(ctlHandle, true)].ID()
118+
planter := p.gameState.playersByEntityID[ctlID]
119+
116120
planter.IsPlanting = true
117121
p.gameState.currentPlanter = planter
118122

@@ -703,7 +707,7 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
703707
func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
704708
const inventoryCapacity = 64
705709

706-
var inventorySize uint64 = 64
710+
inventorySize := 64
707711

708712
type eq struct {
709713
*common.Equipment
@@ -728,7 +732,7 @@ func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
728732
setPlayerInventory := func() {
729733
inventory := make(map[int]*common.Equipment, inventorySize)
730734

731-
for i := uint64(0); i < inventorySize; i++ {
735+
for i := 0; i < inventorySize; i++ {
732736
val := pawnEntity.Property(playerWeaponPrefixS2 + fmt.Sprintf("%04d", i)).Value()
733737
if val.Any == nil {
734738
continue
@@ -742,7 +746,7 @@ func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
742746
}
743747

744748
pawnEntity.Property("m_pWeaponServices.m_hMyWeapons").OnUpdate(func(pv st.PropertyValue) {
745-
inventorySize = pv.S2UInt64()
749+
inventorySize = len(pv.S2Array())
746750
setPlayerInventory()
747751
})
748752

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

759763
entityWasCreated := entityID != constants.EntityHandleIndexMaskSource2
760764

761-
if uint64(i) < inventorySize {
765+
if i < inventorySize {
762766
if entityWasCreated {
763767
existingWeapon, exists := playerInventory[i]
764768
if exists {

pkg/demoinfocs/game_state.go

+1
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
430430
// Returns nil if not found.
431431
func (ptcp participants) FindByPawnHandle(handle uint64) *common.Player {
432432
entityID := entityIDFromHandle(handle, ptcp.getIsSource2())
433+
433434
for _, player := range ptcp.All() {
434435
pawnEntity := player.PlayerPawnEntity()
435436

Binary file not shown.

pkg/demoinfocs/sendtables/propdecoder.go

+4
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

+35-10
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

+12-9
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

+20-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func (s *fieldState) get(fp *fieldPath) interface{} {
1515
z := 0
1616
for i := 0; i <= fp.last; i++ {
1717
z = fp.path[i]
18-
if len(x.state) < z+2 {
18+
if len(x.state) < z+1 {
1919
return nil
2020
}
2121
if i == fp.last {
@@ -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 {
@@ -56,5 +62,14 @@ func max(a, b int) int {
5662
if a > b {
5763
return a
5864
}
65+
66+
return b
67+
}
68+
69+
func min(a, b int) int {
70+
if a < b {
71+
return a
72+
}
73+
5974
return b
6075
}

pkg/demoinfocs/sendtables2/serializer.go

+12
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)