Skip to content

Commit

Permalink
fix array decoding #509
Browse files Browse the repository at this point in the history
  • Loading branch information
markus-wa committed Feb 15, 2024
1 parent 06fbbc5 commit d7f89fd
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 27 deletions.
8 changes: 4 additions & 4 deletions pkg/demoinfocs/datatables.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
const inventoryCapacity = 64

var inventorySize uint64 = 64
inventorySize := 64

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

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

pawnEntity.Property("m_pWeaponServices.m_hMyWeapons").OnUpdate(func(pv st.PropertyValue) {
inventorySize = pv.S2UInt64()
inventorySize = len(pv.S2Array())
setPlayerInventory()
})

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

entityWasCreated := entityID != constants.EntityHandleIndexMaskSource2

if uint64(i) < inventorySize {
if i < inventorySize {
if entityWasCreated {
existingWeapon, exists := playerInventory[i]
if exists {
Expand Down
4 changes: 4 additions & 0 deletions pkg/demoinfocs/sendtables/propdecoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ func (v PropertyValue) S2UInt64() uint64 {
return v.Any.(uint64)
}

func (v PropertyValue) S2Array() []any {
return v.Any.([]any)
}

func (v PropertyValue) S2UInt32() uint32 {
return v.Any.(uint32)
}
Expand Down
45 changes: 35 additions & 10 deletions pkg/demoinfocs/sendtables2/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,21 @@ func (p property) Name() string {
}

func (p property) Value() st.PropertyValue {
v := p.entity.Get(p.name)

fs, ok := v.(*fieldState)
if ok {
v = fs.state

Check warning on line 65 in pkg/demoinfocs/sendtables2/entity.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/entity.go#L65

Added line #L65 was not covered by tests
}

return st.PropertyValue{
VectorVal: r3.Vector{},
IntVal: 0,
Int64Val: 0,
ArrayVal: nil,
StringVal: "",
FloatVal: 0,
Any: p.entity.Get(p.name),
Any: v,
S2: true,
}
}
Expand Down Expand Up @@ -416,12 +423,30 @@ func (e *Entity) readFields(r *reader, paths *[]*fieldPath) {
readFieldPaths(r, paths)

for _, fp := range *paths {
decoder := e.class.serializer.getDecoderForFieldPath(fp, 0)
f := e.class.serializer.getFieldForFieldPath(fp, 0)
name := e.class.getNameForFieldPath(fp)
decoder, base := e.class.serializer.getDecoderForFieldPath2(fp, 0)

val := decoder(r)
e.state.set(fp, val)

for _, h := range e.updateHandlers[e.class.getNameForFieldPath(fp)] {
if base && (f.model == fieldModelVariableArray || f.model == fieldModelVariableTable) {
oldFS := e.state.get(fp)
fs := newFieldState()

fs.state = make([]interface{}, val.(uint64))

if oldFS != nil {
copy(fs.state, oldFS.(*fieldState).state[:min(len(fs.state), len(oldFS.(*fieldState).state))])
}

e.state.set(fp, fs)

val = fs.state
} else {
e.state.set(fp, val)
}

for _, h := range e.updateHandlers[name] {
h(st.PropertyValue{
VectorVal: r3.Vector{},
IntVal: 0,
Expand All @@ -446,7 +471,7 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error {
index = int32(-1)
updates = int(m.GetUpdatedEntries())
cmd uint32
classId int32
classID int32
serial int32
)

Expand Down Expand Up @@ -485,18 +510,18 @@ func (p *Parser) OnPacketEntities(m *msgs2.CSVCMsg_PacketEntities) error {
}
if cmd&0x01 == 0 {
if cmd&0x02 != 0 {
classId = int32(r.readBits(p.classIdSize))
classID = int32(r.readBits(p.classIdSize))
serial = int32(r.readBits(17))
r.readVarUint32()

class := p.classesById[classId]
class := p.classesById[classID]
if class == nil {
_panicf("unable to find new class %d", classId)
_panicf("unable to find new class %d", classID)

Check warning on line 519 in pkg/demoinfocs/sendtables2/entity.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/entity.go#L519

Added line #L519 was not covered by tests
}

baseline := p.classBaselines[classId]
baseline := p.classBaselines[classID]
if baseline == nil {
_panicf("unable to find new baseline %d", classId)
_panicf("unable to find new baseline %d", classID)

Check warning on line 524 in pkg/demoinfocs/sendtables2/entity.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/entity.go#L524

Added line #L524 was not covered by tests
}

e = newEntity(index, serial, class)
Expand Down
21 changes: 12 additions & 9 deletions pkg/demoinfocs/sendtables2/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,31 +208,34 @@ func (f *field) getTypeForFieldPath(fp *fieldPath, pos int) *fieldType {
return f.fieldType
}

func (f *field) getDecoderForFieldPath(fp *fieldPath, pos int) fieldDecoder {
func (f *field) getDecoderForFieldPath(fp *fieldPath, pos int) (fieldDecoder, bool) {
switch f.model {
case fieldModelFixedArray:
return f.decoder
return f.decoder, false

case fieldModelFixedTable:
if fp.last == pos-1 {
return f.baseDecoder
return f.baseDecoder, true
}
return f.serializer.getDecoderForFieldPath(fp, pos)

return f.serializer.getDecoderForFieldPath2(fp, pos)

case fieldModelVariableArray:
if fp.last == pos {
return f.childDecoder
return f.childDecoder, false
}
return f.baseDecoder

return f.baseDecoder, true

case fieldModelVariableTable:
if fp.last >= pos+1 {
return f.serializer.getDecoderForFieldPath(fp, pos+1)
return f.serializer.getDecoderForFieldPath2(fp, pos+1)
}
return f.baseDecoder

return f.baseDecoder, true
}

return f.decoder
return f.decoder, false
}

func (f *field) getFieldPathForName(fp *fieldPath, name string) bool {
Expand Down
23 changes: 19 additions & 4 deletions pkg/demoinfocs/sendtables2/field_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@ func (s *fieldState) set(fp *fieldPath, v interface{}) {
z := 0
for i := 0; i <= fp.last; i++ {
z = fp.path[i]
if y := len(x.state); y < z+2 {
z := make([]interface{}, max(z+2, y*2))
copy(z, x.state)
x.state = z
if y := len(x.state); y <= z {
newCap := max(z+2, y*2)
if newCap > cap(x.state) {
newSlice := make([]interface{}, z+1, newCap)
copy(newSlice, x.state)
x.state = newSlice
} else {
// Re-slice to update the length without allocating new memory
x.state = x.state[:z+1]

Check warning on line 45 in pkg/demoinfocs/sendtables2/field_state.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/field_state.go#L45

Added line #L45 was not covered by tests
}
}
if i == fp.last {
if _, ok := x.state[z].(*fieldState); !ok {
Expand All @@ -56,5 +62,14 @@ func max(a, b int) int {
if a > b {
return a
}

return b
}

func min(a, b int) int {
if a < b {
return a
}

return b
}
12 changes: 12 additions & 0 deletions pkg/demoinfocs/sendtables2/serializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ func (s *serializer) getDecoderForFieldPath(fp *fieldPath, pos int) fieldDecoder
if len(s.fields) <= index {
_panicf("serializer %s: field path %s has no field (%d)", s.name, fp, index)
}

dec, _ := s.fields[index].getDecoderForFieldPath(fp, pos+1)

Check warning on line 49 in pkg/demoinfocs/sendtables2/serializer.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/serializer.go#L49

Added line #L49 was not covered by tests

return dec

Check warning on line 51 in pkg/demoinfocs/sendtables2/serializer.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/serializer.go#L51

Added line #L51 was not covered by tests
}

func (s *serializer) getDecoderForFieldPath2(fp *fieldPath, pos int) (fieldDecoder, bool) {
index := fp.path[pos]
if len(s.fields) <= index {
_panicf("serializer %s: field path %s has no field (%d)", s.name, fp, index)

Check warning on line 57 in pkg/demoinfocs/sendtables2/serializer.go

View check run for this annotation

Codecov / codecov/patch

pkg/demoinfocs/sendtables2/serializer.go#L57

Added line #L57 was not covered by tests
}

return s.fields[index].getDecoderForFieldPath(fp, pos+1)
}

Expand Down

0 comments on commit d7f89fd

Please sign in to comment.