Skip to content

Commit f111430

Browse files
committed
fix: players may not be found
1 parent 9bc3001 commit f111430

File tree

5 files changed

+63
-78
lines changed

5 files changed

+63
-78
lines changed

pkg/demoinfocs/common/player.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type Player struct {
3333
IsPlanting bool
3434
IsReloading bool
3535
IsUnknown bool // Used to identify unknown/broken players. see https://github.com/markus-wa/demoinfocs-golang/issues/162
36-
PawnEntityID int
3736
}
3837

3938
func (p *Player) PlayerPawnEntity() st.Entity {

pkg/demoinfocs/datatables.go

Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -458,62 +458,52 @@ func (p *parser) bindNewPlayerS1(playerEntity st.Entity) {
458458

459459
func (p *parser) bindNewPlayerControllerS2(controllerEntity st.Entity) {
460460
controllerEntityID := controllerEntity.ID()
461-
462-
rp := p.rawPlayers[controllerEntityID-1]
463-
464-
isNew, pl := p.getOrCreatePlayer(controllerEntityID, rp)
465-
466-
pl.EntityID = controllerEntityID
467-
pl.Entity = controllerEntity
468-
pl.IsConnected = true
469-
pawnProp := controllerEntity.Property("m_hPawn")
470-
pl.PawnEntityID = int(pawnProp.Value().S2UInt64() & constants.EntityHandleIndexMaskSource2)
471-
472-
controllerEntity.Property("m_iTeamNum").OnUpdate(func(val st.PropertyValue) {
473-
pl.Team = common.Team(val.S2UInt64())
474-
pl.TeamState = p.gameState.Team(pl.Team)
475-
})
476-
477-
pawnProp.OnUpdate(func(val st.PropertyValue) {
478-
pl.PawnEntityID = int(val.S2UInt64()) & constants.EntityHandleIndexMaskSource2
479-
})
461+
p.gameState.playerControllerEntities[controllerEntityID] = controllerEntity
480462

481463
controllerEntity.OnDestroy(func() {
482464
delete(p.gameState.playersByEntityID, controllerEntityID)
483-
pl.Entity = nil
484465
})
485-
486-
if isNew {
487-
if pl.SteamID64 != 0 {
488-
p.eventDispatcher.Dispatch(events.PlayerConnect{Player: pl})
489-
} else {
490-
p.eventDispatcher.Dispatch(events.BotConnect{Player: pl})
491-
}
492-
}
493466
}
494467

495468
func (p *parser) bindNewPlayerPawnS2(pawnEntity st.Entity) {
496-
player := func() *common.Player {
497-
return p.gameState.Participants().FindByHandle64(pawnEntity.PropertyValueMust("m_hController").Handle())
469+
controllerHandle := pawnEntity.PropertyValueMust("m_hController").Handle()
470+
if controllerHandle == constants.InvalidEntityHandleSource2 {
471+
return
472+
}
473+
474+
controllerEntityID := int(controllerHandle & constants.EntityHandleIndexMaskSource2)
475+
controllerEntity := p.gameState.playerControllerEntities[controllerEntityID]
476+
477+
rp := p.rawPlayers[controllerEntityID-1]
478+
_, pl := p.getOrCreatePlayer(controllerEntityID, rp)
479+
pl.Entity = controllerEntity
480+
pl.EntityID = controllerEntity.ID()
481+
pl.IsConnected = true
482+
pl.IsBot = controllerEntity.PropertyValueMust("m_steamID").String() == "0"
483+
if pl.IsBot {
484+
pl.Name = controllerEntity.PropertyValueMust("m_iszPlayerName").String()
485+
pl.IsUnknown = false
486+
}
487+
488+
if pl.SteamID64 != 0 {
489+
p.eventDispatcher.Dispatch(events.PlayerConnect{Player: pl})
490+
} else {
491+
p.eventDispatcher.Dispatch(events.BotConnect{Player: pl})
498492
}
499493

500494
// Position
501495
pawnEntity.OnPositionUpdate(func(pos r3.Vector) {
502-
pl := player()
503-
if pl == nil {
504-
return
505-
}
506-
507496
if pl.IsAlive() {
508497
pl.LastAlivePosition = pos
509498
}
510499
})
511500

501+
pawnEntity.Property("m_iTeamNum").OnUpdate(func(val st.PropertyValue) {
502+
pl.Team = common.Team(val.S2UInt64())
503+
pl.TeamState = p.gameState.Team(pl.Team)
504+
})
505+
512506
pawnEntity.Property("m_flFlashDuration").OnUpdate(func(val st.PropertyValue) {
513-
pl := player()
514-
if pl == nil {
515-
return
516-
}
517507

518508
if val.Float() == 0 {
519509
pl.FlashTick = 0
@@ -533,40 +523,29 @@ func (p *parser) bindNewPlayerPawnS2(pawnEntity st.Entity) {
533523
}
534524
})
535525

536-
p.bindPlayerWeaponsS2(pawnEntity, player)
526+
p.bindPlayerWeaponsS2(pawnEntity, pl)
537527

538528
pawnEntity.Property("m_pWeaponServices.m_hActiveWeapon").OnUpdate(func(val st.PropertyValue) {
539-
pl := player()
540-
if pl == nil {
541-
return
542-
}
543-
544529
pl.IsReloading = false
545530
})
546531

547532
pawnEntity.Property("m_bIsDefusing").OnUpdate(func(val st.PropertyValue) {
548-
pl := player()
549-
if pl == nil {
550-
return
551-
}
552-
553533
pl.IsDefusing = val.BoolVal()
554534
})
555535

556536
spottedByMaskProp := pawnEntity.Property("m_bSpottedByMask.0000")
557537
if spottedByMaskProp != nil {
558-
pl := player()
559-
if pl == nil {
560-
return
561-
}
562-
563538
spottersChanged := func(val st.PropertyValue) {
564539
p.eventDispatcher.Dispatch(events.PlayerSpottersChanged{Spotted: pl})
565540
}
566541

567542
spottedByMaskProp.OnUpdate(spottersChanged)
568543
pawnEntity.Property("m_bSpottedByMask.0001").OnUpdate(spottersChanged)
569544
}
545+
546+
pawnEntity.OnDestroy(func() {
547+
pl.IsConnected = false
548+
})
570549
}
571550

572551
const maxWeapons = 64
@@ -621,12 +600,7 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
621600
}
622601
}
623602

624-
func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, getPlayer func() *common.Player) {
625-
pl := getPlayer()
626-
if pl == nil {
627-
return
628-
}
629-
603+
func (p *parser) bindPlayerWeaponsS2(pawnEntity st.Entity, pl *common.Player) {
630604
var cache [maxWeapons]uint64
631605
for i := range cache {
632606
i2 := i // Copy for passing to handler

pkg/demoinfocs/game_events.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,9 @@ func (geh gameEventHandler) playerConnect(data map[string]*msg.CSVCMsg_GameEvent
627627
}
628628
}
629629

630-
geh.parser.setRawPlayer(int(data["index"].GetValByte()), pl)
630+
if !geh.parser.isSource2() {
631+
geh.parser.setRawPlayer(int(data["index"].GetValByte()), pl)
632+
}
631633
}
632634

633635
func (geh gameEventHandler) playerDisconnect(data map[string]*msg.CSVCMsg_GameEventKeyT) {

pkg/demoinfocs/game_state.go

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ type gameState struct {
2020
ingameTick int
2121
tState common.TeamState
2222
ctState common.TeamState
23-
playersByUserID map[int]*common.Player // Maps user-IDs to players
24-
playersByEntityID map[int]*common.Player // Maps entity-IDs to players
25-
playersBySteamID32 map[uint32]*common.Player // Maps 32-bit-steam-IDs to players
26-
playerResourceEntity st.Entity // CCSPlayerResource entity instance, contains scoreboard info and more
23+
playersByUserID map[int]*common.Player // Maps user-IDs to players
24+
playersByEntityID map[int]*common.Player // Maps entity-IDs to players
25+
playersBySteamID32 map[uint32]*common.Player // Maps 32-bit-steam-IDs to players
26+
playerResourceEntity st.Entity // CCSPlayerResource entity instance, contains scoreboard info and more
27+
playerControllerEntities map[int]st.Entity
2728
grenadeProjectiles map[int]*common.GrenadeProjectile // Maps entity-IDs to active nade-projectiles. That's grenades that have been thrown, but have not yet detonated.
2829
infernos map[int]*common.Inferno // Maps entity-IDs to active infernos.
2930
weapons map[int]*common.Equipment // Maps entity IDs to weapons. Used to remember what a weapon is (p250 / cz etc.)
@@ -232,16 +233,17 @@ func (gs gameState) EntityByHandle(handle uint64) st.Entity {
232233

233234
func newGameState(demoInfo demoInfoProvider) *gameState {
234235
gs := &gameState{
235-
playersByEntityID: make(map[int]*common.Player),
236-
playersByUserID: make(map[int]*common.Player),
237-
playersBySteamID32: make(map[uint32]*common.Player),
238-
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
239-
infernos: make(map[int]*common.Inferno),
240-
weapons: make(map[int]*common.Equipment),
241-
hostages: make(map[int]*common.Hostage),
242-
entities: make(map[int]st.Entity),
243-
thrownGrenades: make(map[*common.Player][]*common.Equipment),
244-
flyingFlashbangs: make([]*FlyingFlashbang, 0),
236+
playerControllerEntities: make(map[int]st.Entity),
237+
playersByEntityID: make(map[int]*common.Player),
238+
playersByUserID: make(map[int]*common.Player),
239+
playersBySteamID32: make(map[uint32]*common.Player),
240+
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
241+
infernos: make(map[int]*common.Inferno),
242+
weapons: make(map[int]*common.Equipment),
243+
hostages: make(map[int]*common.Hostage),
244+
entities: make(map[int]st.Entity),
245+
thrownGrenades: make(map[*common.Player][]*common.Equipment),
246+
flyingFlashbangs: make([]*FlyingFlashbang, 0),
245247
lastFlash: lastFlash{
246248
projectileByPlayer: make(map[*common.Player]*common.GrenadeProjectile),
247249
},
@@ -422,7 +424,11 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
422424
func (ptcp participants) FindByPawnHandle(handle uint64) *common.Player {
423425
entityID := entityIDFromHandle(handle, ptcp.getIsSource2())
424426
for _, player := range ptcp.All() {
425-
if player.PawnEntityID == entityID {
427+
pawnEntity := player.PlayerPawnEntity()
428+
if pawnEntity == nil {
429+
continue
430+
}
431+
if pawnEntity.ID() == entityID {
426432
return player
427433
}
428434
}

pkg/demoinfocs/stringtables.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ func (p *parser) handleCreateStringTableS1(tab *msg.CSVCMsg_CreateStringTable) {
589589
}
590590

591591
func (p *parser) parseUserInfo(data []byte, playerIndex int) {
592+
if _, exists := p.rawPlayers[playerIndex]; exists {
593+
return
594+
}
595+
592596
var userInfo msgs2.CMsgPlayerInfo
593597
err := proto.Unmarshal(data, &userInfo)
594598
if err != nil {

0 commit comments

Comments
 (0)