Skip to content

Commit 161565a

Browse files
authored
Merge pull request #412 from akiver/fix-players
fix: players may not be found
2 parents 7c65c04 + 44fb7a2 commit 161565a

File tree

6 files changed

+74
-77
lines changed

6 files changed

+74
-77
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050

5151
- name: Lint Changed Code
5252
run: scripts/lint-changes.sh
53+
continue-on-error: true
5354

5455
- name: Race Tests
5556
run: scripts/race-tests.sh

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: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -456,64 +456,63 @@ func (p *parser) bindNewPlayerS1(playerEntity st.Entity) {
456456
}
457457
}
458458

459-
func (p *parser) bindNewPlayerControllerS2(controllerEntity st.Entity) {
459+
func (p *parser) getOrCreatePlayerFromControllerEntity(controllerEntity st.Entity) *common.Player {
460460
controllerEntityID := controllerEntity.ID()
461+
p.gameState.playerControllerEntities[controllerEntityID] = controllerEntity
461462

462463
rp := p.rawPlayers[controllerEntityID-1]
464+
_, player := p.getOrCreatePlayer(controllerEntityID, rp)
465+
player.Entity = controllerEntity
466+
player.EntityID = controllerEntityID
467+
player.IsBot = controllerEntity.PropertyValueMust("m_steamID").String() == "0"
468+
469+
if player.IsBot {
470+
player.Name = controllerEntity.PropertyValueMust("m_iszPlayerName").String()
471+
player.IsUnknown = false
472+
}
463473

464-
isNew, pl := p.getOrCreatePlayer(controllerEntityID, rp)
474+
return player
475+
}
465476

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)
477+
func (p *parser) bindNewPlayerControllerS2(controllerEntity st.Entity) {
478+
pl := p.getOrCreatePlayerFromControllerEntity(controllerEntity)
471479

472480
controllerEntity.Property("m_iTeamNum").OnUpdate(func(val st.PropertyValue) {
473481
pl.Team = common.Team(val.S2UInt64())
474482
pl.TeamState = p.gameState.Team(pl.Team)
475483
})
476484

477-
pawnProp.OnUpdate(func(val st.PropertyValue) {
478-
pl.PawnEntityID = int(val.S2UInt64()) & constants.EntityHandleIndexMaskSource2
479-
})
480-
481485
controllerEntity.OnDestroy(func() {
482-
delete(p.gameState.playersByEntityID, controllerEntityID)
483-
pl.Entity = nil
486+
delete(p.gameState.playersByEntityID, controllerEntity.ID())
484487
})
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-
}
493488
}
494489

495490
func (p *parser) bindNewPlayerPawnS2(pawnEntity st.Entity) {
496-
player := func() *common.Player {
497-
return p.gameState.Participants().FindByHandle64(pawnEntity.PropertyValueMust("m_hController").Handle())
491+
controllerHandle := pawnEntity.PropertyValueMust("m_hController").Handle()
492+
if controllerHandle == constants.InvalidEntityHandleSource2 {
493+
return
494+
}
495+
496+
controllerEntityID := int(controllerHandle & constants.EntityHandleIndexMaskSource2)
497+
controllerEntity := p.gameState.playerControllerEntities[controllerEntityID]
498+
499+
pl := p.getOrCreatePlayerFromControllerEntity(controllerEntity)
500+
pl.IsConnected = true
501+
502+
if pl.SteamID64 != 0 {
503+
p.eventDispatcher.Dispatch(events.PlayerConnect{Player: pl})
504+
} else {
505+
p.eventDispatcher.Dispatch(events.BotConnect{Player: pl})
498506
}
499507

500508
// Position
501509
pawnEntity.OnPositionUpdate(func(pos r3.Vector) {
502-
pl := player()
503-
if pl == nil {
504-
return
505-
}
506-
507510
if pl.IsAlive() {
508511
pl.LastAlivePosition = pos
509512
}
510513
})
511514

512515
pawnEntity.Property("m_flFlashDuration").OnUpdate(func(val st.PropertyValue) {
513-
pl := player()
514-
if pl == nil {
515-
return
516-
}
517516

518517
if val.Float() == 0 {
519518
pl.FlashTick = 0
@@ -533,40 +532,29 @@ func (p *parser) bindNewPlayerPawnS2(pawnEntity st.Entity) {
533532
}
534533
})
535534

536-
p.bindPlayerWeaponsS2(pawnEntity, player)
535+
p.bindPlayerWeaponsS2(pawnEntity, pl)
537536

538537
pawnEntity.Property("m_pWeaponServices.m_hActiveWeapon").OnUpdate(func(val st.PropertyValue) {
539-
pl := player()
540-
if pl == nil {
541-
return
542-
}
543-
544538
pl.IsReloading = false
545539
})
546540

547541
pawnEntity.Property("m_bIsDefusing").OnUpdate(func(val st.PropertyValue) {
548-
pl := player()
549-
if pl == nil {
550-
return
551-
}
552-
553542
pl.IsDefusing = val.BoolVal()
554543
})
555544

556545
spottedByMaskProp := pawnEntity.Property("m_bSpottedByMask.0000")
557546
if spottedByMaskProp != nil {
558-
pl := player()
559-
if pl == nil {
560-
return
561-
}
562-
563547
spottersChanged := func(val st.PropertyValue) {
564548
p.eventDispatcher.Dispatch(events.PlayerSpottersChanged{Spotted: pl})
565549
}
566550

567551
spottedByMaskProp.OnUpdate(spottersChanged)
568552
pawnEntity.Property("m_bSpottedByMask.0001").OnUpdate(spottersChanged)
569553
}
554+
555+
pawnEntity.OnDestroy(func() {
556+
pl.IsConnected = false
557+
})
570558
}
571559

572560
const maxWeapons = 64
@@ -621,12 +609,7 @@ func (p *parser) bindPlayerWeapons(playerEntity st.Entity, pl *common.Player) {
621609
}
622610
}
623611

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

pkg/demoinfocs/game_events.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -516,16 +516,16 @@ func (geh gameEventHandler) playerBlind(data map[string]*msg.CSVCMsg_GameEventKe
516516
}
517517

518518
func (geh gameEventHandler) flashBangDetonate(data map[string]*msg.CSVCMsg_GameEventKeyT) {
519-
if geh.parser.isSource2() && !geh.parser.disableMimicSource1GameEvents {
520-
return
521-
}
522519

523520
nadeEvent := geh.nadeEvent(data, common.EqFlash)
524521

525522
geh.gameState().lastFlash.player = nadeEvent.Thrower
526-
geh.dispatch(events.FlashExplode{
527-
GrenadeEvent: nadeEvent,
528-
})
523+
524+
if !geh.parser.isSource2() || geh.parser.isSource2() && !geh.parser.disableMimicSource1GameEvents {
525+
geh.dispatch(events.FlashExplode{
526+
GrenadeEvent: nadeEvent,
527+
})
528+
}
529529
}
530530

531531
func (geh gameEventHandler) heGrenadeDetonate(data map[string]*msg.CSVCMsg_GameEventKeyT) {
@@ -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: 23 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.)
@@ -238,16 +239,17 @@ func (gs gameState) EntityByHandle(handle uint64) st.Entity {
238239

239240
func newGameState(demoInfo demoInfoProvider) *gameState {
240241
gs := &gameState{
241-
playersByEntityID: make(map[int]*common.Player),
242-
playersByUserID: make(map[int]*common.Player),
243-
playersBySteamID32: make(map[uint32]*common.Player),
244-
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
245-
infernos: make(map[int]*common.Inferno),
246-
weapons: make(map[int]*common.Equipment),
247-
hostages: make(map[int]*common.Hostage),
248-
entities: make(map[int]st.Entity),
249-
thrownGrenades: make(map[*common.Player][]*common.Equipment),
250-
flyingFlashbangs: make([]*FlyingFlashbang, 0),
242+
playerControllerEntities: make(map[int]st.Entity),
243+
playersByEntityID: make(map[int]*common.Player),
244+
playersByUserID: make(map[int]*common.Player),
245+
playersBySteamID32: make(map[uint32]*common.Player),
246+
grenadeProjectiles: make(map[int]*common.GrenadeProjectile),
247+
infernos: make(map[int]*common.Inferno),
248+
weapons: make(map[int]*common.Equipment),
249+
hostages: make(map[int]*common.Hostage),
250+
entities: make(map[int]st.Entity),
251+
thrownGrenades: make(map[*common.Player][]*common.Equipment),
252+
flyingFlashbangs: make([]*FlyingFlashbang, 0),
251253
lastFlash: lastFlash{
252254
projectileByPlayer: make(map[*common.Player]*common.GrenadeProjectile),
253255
},
@@ -428,7 +430,13 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
428430
func (ptcp participants) FindByPawnHandle(handle uint64) *common.Player {
429431
entityID := entityIDFromHandle(handle, ptcp.getIsSource2())
430432
for _, player := range ptcp.All() {
431-
if player.PawnEntityID == entityID {
433+
pawnEntity := player.PlayerPawnEntity()
434+
435+
if pawnEntity == nil {
436+
continue
437+
}
438+
439+
if pawnEntity.ID() == entityID {
432440
return player
433441
}
434442
}

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)