Skip to content

Commit

Permalink
Merge pull request #510 from markus-wa/fix-array-decoding
Browse files Browse the repository at this point in the history
fix array decoding
  • Loading branch information
markus-wa authored Feb 19, 2024
2 parents 24ab81c + 18bd5cb commit 600fc4e
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 29 deletions.
14 changes: 9 additions & 5 deletions pkg/demoinfocs/datatables.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ func (p *parser) bindBomb() {
bombEntity.Property("m_bStartedArming").OnUpdate(func(val st.PropertyValue) {
if val.BoolVal() {
if p.isSource2() {
planter := p.gameState.Participants().FindByPawnHandle(bombEntity.PropertyValueMust("m_hOwnerEntity").Handle())
planterHandle := bombEntity.PropertyValueMust("m_hOwnerEntity").Handle()
ctlHandle := p.gameState.entities[entityIDFromHandle(planterHandle, true)].PropertyValueMust("m_hController").Handle()
ctlID := p.gameState.entities[entityIDFromHandle(ctlHandle, true)].ID()
planter := p.gameState.playersByEntityID[ctlID]

planter.IsPlanting = true
p.gameState.currentPlanter = planter

Expand Down Expand Up @@ -703,7 +707,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 +732,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 +746,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 +762,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
1 change: 1 addition & 0 deletions pkg/demoinfocs/game_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
// Returns nil if not found.
func (ptcp participants) FindByPawnHandle(handle uint64) *common.Player {
entityID := entityIDFromHandle(handle, ptcp.getIsSource2())

for _, player := range ptcp.All() {
pawnEntity := player.PlayerPawnEntity()

Expand Down
Binary file modified pkg/demoinfocs/s2_CMsgSource1LegacyGameEventList.pb.bin
Binary file not shown.
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
}

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)
}

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)
}

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
25 changes: 20 additions & 5 deletions pkg/demoinfocs/sendtables2/field_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (s *fieldState) get(fp *fieldPath) interface{} {
z := 0
for i := 0; i <= fp.last; i++ {
z = fp.path[i]
if len(x.state) < z+2 {
if len(x.state) < z+1 {
return nil
}
if i == fp.last {
Expand All @@ -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]
}
}
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)

return dec
}

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)
}

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

Expand Down

0 comments on commit 600fc4e

Please sign in to comment.