Skip to content

Commit 9a6bb61

Browse files
authored
Merge pull request #144 from markus-wa/issue-142
Fix ItemEquip.Player == nil if bot takes over player fixes #142
2 parents bd95f6d + ff51c27 commit 9a6bb61

File tree

3 files changed

+95
-98
lines changed

3 files changed

+95
-98
lines changed

game_events.go

Lines changed: 91 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ func (geh gameEventHandler) dispatch(event interface{}) {
5555
geh.parser.eventDispatcher.Dispatch(event)
5656
}
5757

58-
func (geh gameEventHandler) delay(event interface{}) {
59-
geh.parser.delayedEvents = append(geh.parser.delayedEvents, event)
60-
}
61-
6258
func (geh gameEventHandler) gameState() *GameState {
6359
return geh.parser.gameState
6460
}
@@ -76,73 +72,84 @@ type gameEventHandlerFunc func(map[string]*msg.CSVCMsg_GameEventKeyT)
7672
func newGameEventHandler(parser *Parser) gameEventHandler {
7773
geh := gameEventHandler{parser: parser}
7874

75+
delay := func(f gameEventHandlerFunc) gameEventHandlerFunc {
76+
return func(data map[string]*msg.CSVCMsg_GameEventKeyT) {
77+
parser.delayedEventHandlers = append(parser.delayedEventHandlers, func() {
78+
f(data)
79+
})
80+
}
81+
}
7982
geh.gameEventNameToHandler = map[string]gameEventHandlerFunc{
8083
// sorted alphabetically
81-
"announce_phase_end": nil, // Dunno
82-
"begin_new_match": geh.beginNewMatch, // Match started
83-
"bomb_beep": nil, // Bomb beep
84-
"bomb_begindefuse": geh.bombBeginDefuse, // Defuse started
85-
"bomb_beginplant": geh.bombBeginPlant, // Plant started
86-
"bomb_defused": geh.bombDefused, // Defuse finished
87-
"bomb_dropped": geh.bombDropped, // Bomb dropped
88-
"bomb_exploded": geh.bombExploded, // Bomb exploded
89-
"bomb_pickup": geh.bombPickup, // Bomb picked up
90-
"bomb_planted": geh.bombPlanted, // Plant finished
91-
"bot_takeover": geh.botTakeover, // Bot got taken over
92-
"buytime_ended": nil, // Not actually end of buy time, seems to only be sent once per game at the start
93-
"cs_match_end_restart": nil, // Yawn
94-
"cs_pre_restart": nil, // Not sure, doesn't seem to be important
95-
"cs_round_final_beep": nil, // Final beep
96-
"cs_round_start_beep": nil, // Round start beeps
97-
"cs_win_panel_match": geh.csWinPanelMatch, // Not sure, maybe match end event???
98-
"cs_win_panel_round": nil, // Win panel, (==end of match?)
99-
"decoy_detonate": geh.decoyDetonate, // Decoy exploded/expired
100-
"decoy_started": geh.decoyStarted, // Decoy started
101-
"endmatch_cmm_start_reveal_items": nil, // Drops
102-
"flashbang_detonate": geh.flashBangDetonate, // Flash exploded
103-
"hegrenade_detonate": geh.heGrenadeDetonate, // HE exploded
104-
"hltv_chase": nil, // Don't care
105-
"hltv_fixed": nil, // Dunno
106-
"hltv_status": nil, // Don't know
107-
"inferno_expire": geh.infernoExpire, // Incendiary expired
108-
"inferno_startburn": geh.infernoStartBurn, // Incendiary exploded/started
109-
"item_equip": geh.itemEquip, // Equipped, I think
110-
"item_pickup": geh.itemPickup, // Picked up or bought?
111-
"item_remove": geh.itemRemove, // Dropped?
112-
"other_death": nil, // Dunno
113-
"player_blind": geh.playerBlind, // Player got blinded by a flash
114-
"player_changename": nil, // Name change
115-
"player_connect": geh.playerConnect, // Bot connected or player reconnected, players normally come in via string tables & data tables
116-
"player_connect_full": nil, // Connecting finished
117-
"player_death": geh.playerDeath, // Player died
118-
"player_disconnect": geh.playerDisconnect, // Player disconnected (kicked, quit, timed out etc.)
119-
"player_falldamage": nil, // Falldamage
120-
"player_footstep": geh.playerFootstep, // Footstep sound
121-
"player_hurt": geh.playerHurt, // Player got hurt
122-
"player_jump": geh.playerJump, // Player jumped
123-
"player_spawn": nil, // Player spawn
124-
"player_team": geh.playerTeam, // Player changed team
125-
"round_announce_final": geh.roundAnnounceFinal, // 30th round for normal de_, not necessarily matchpoint
126-
"round_announce_last_round_half": geh.roundAnnounceLastRoundHalf, // Last round of the half
127-
"round_announce_match_point": nil, // Match point announcement
128-
"round_announce_match_start": nil, // Special match start announcement
129-
"round_announce_warmup": nil, // Dunno
130-
"round_end": geh.roundEnd, // Round ended and the winner was announced
131-
"round_freeze_end": geh.roundFreezeEnd, // Round start freeze ended
132-
"round_mvp": geh.roundMVP, // Round MVP was announced
133-
"round_officially_ended": geh.roundOfficiallyEnded, // The event after which you get teleported to the spawn (=> You can still walk around between round_end and this event)
134-
"round_poststart": nil, // Ditto
135-
"round_prestart": nil, // Ditto
136-
"round_start": geh.roundStart, // Round started
137-
"round_time_warning": nil, // Round time warning
138-
"server_cvar": nil, // Dunno
139-
"smokegrenade_detonate": geh.smokeGrenadeDetonate, // Smoke popped
140-
"smokegrenade_expired": geh.smokeGrenadeExpired, // Smoke expired
141-
"tournament_reward": nil, // Dunno
142-
"weapon_fire": geh.weaponFire, // Weapon was fired
143-
"weapon_fire_on_empty": nil, // Sounds boring
144-
"weapon_reload": geh.weaponReload, // Weapon reloaded
145-
"weapon_zoom": nil, // Zooming in
84+
"announce_phase_end": nil, // Dunno
85+
"begin_new_match": geh.beginNewMatch, // Match started
86+
"bomb_beep": nil, // Bomb beep
87+
"bomb_begindefuse": geh.bombBeginDefuse, // Defuse started
88+
"bomb_beginplant": geh.bombBeginPlant, // Plant started
89+
"bomb_defused": geh.bombDefused, // Defuse finished
90+
"bomb_dropped": geh.bombDropped, // Bomb dropped
91+
"bomb_exploded": geh.bombExploded, // Bomb exploded
92+
"bomb_pickup": geh.bombPickup, // Bomb picked up
93+
"bomb_planted": geh.bombPlanted, // Plant finished
94+
"bot_takeover": geh.botTakeover, // Bot got taken over
95+
"buytime_ended": nil, // Not actually end of buy time, seems to only be sent once per game at the start
96+
"cs_match_end_restart": nil, // Yawn
97+
"cs_pre_restart": nil, // Not sure, doesn't seem to be important
98+
"cs_round_final_beep": nil, // Final beep
99+
"cs_round_start_beep": nil, // Round start beeps
100+
"cs_win_panel_match": geh.csWinPanelMatch, // Not sure, maybe match end event???
101+
"cs_win_panel_round": nil, // Win panel, (==end of match?)
102+
"decoy_detonate": geh.decoyDetonate, // Decoy exploded/expired
103+
"decoy_started": delay(geh.decoyStarted), // Decoy started. Delayed because projectile entity is not yet created
104+
"endmatch_cmm_start_reveal_items": nil, // Drops
105+
"flashbang_detonate": geh.flashBangDetonate, // Flash exploded
106+
"hegrenade_detonate": geh.heGrenadeDetonate, // HE exploded
107+
"hltv_chase": nil, // Don't care
108+
"hltv_fixed": nil, // Dunno
109+
"hltv_status": nil, // Don't know
110+
"inferno_expire": geh.infernoExpire, // Incendiary expired
111+
"inferno_startburn": delay(geh.infernoStartBurn), // Incendiary exploded/started. Delayed because inferno entity is not yet created
112+
"item_equip": delay(geh.itemEquip), // Equipped / weapon swap, I think. Delayed because of #142 - Bot entity possibly not yet created
113+
"item_pickup": delay(geh.itemPickup), // Picked up or bought? Delayed because of #119 - Equipment.UniqueID()
114+
"item_remove": geh.itemRemove, // Dropped?
115+
"other_death": nil, // Dunno
116+
"player_blind": delay(geh.playerBlind), // Player got blinded by a flash. Delayed because Player.FlashDuration hasn't been updated yet
117+
"player_changename": nil, // Name change
118+
"player_connect": geh.playerConnect, // Bot connected or player reconnected, players normally come in via string tables & data tables
119+
"player_connect_full": nil, // Connecting finished
120+
"player_death": geh.playerDeath, // Player died
121+
"player_disconnect": geh.playerDisconnect, // Player disconnected (kicked, quit, timed out etc.)
122+
"player_falldamage": nil, // Falldamage
123+
"player_footstep": geh.playerFootstep, // Footstep sound
124+
"player_hurt": geh.playerHurt, // Player got hurt
125+
"player_jump": geh.playerJump, // Player jumped
126+
"player_spawn": nil, // Player spawn
127+
128+
// Player changed team. Delayed for two reasons
129+
// - team IDs of other players changing teams in the same tick might not have changed yet
130+
// - player entities might not have been re-created yet after a reconnect
131+
"player_team": delay(geh.playerTeam),
132+
"round_announce_final": geh.roundAnnounceFinal, // 30th round for normal de_, not necessarily matchpoint
133+
"round_announce_last_round_half": geh.roundAnnounceLastRoundHalf, // Last round of the half
134+
"round_announce_match_point": nil, // Match point announcement
135+
"round_announce_match_start": nil, // Special match start announcement
136+
"round_announce_warmup": nil, // Dunno
137+
"round_end": geh.roundEnd, // Round ended and the winner was announced
138+
"round_freeze_end": geh.roundFreezeEnd, // Round start freeze ended
139+
"round_mvp": geh.roundMVP, // Round MVP was announced
140+
"round_officially_ended": geh.roundOfficiallyEnded, // The event after which you get teleported to the spawn (=> You can still walk around between round_end and this event)
141+
"round_poststart": nil, // Ditto
142+
"round_prestart": nil, // Ditto
143+
"round_start": geh.roundStart, // Round started
144+
"round_time_warning": nil, // Round time warning
145+
"server_cvar": nil, // Dunno
146+
"smokegrenade_detonate": geh.smokeGrenadeDetonate, // Smoke popped
147+
"smokegrenade_expired": geh.smokeGrenadeExpired, // Smoke expired
148+
"tournament_reward": nil, // Dunno
149+
"weapon_fire": geh.weaponFire, // Weapon was fired
150+
"weapon_fire_on_empty": nil, // Sounds boring
151+
"weapon_reload": geh.weaponReload, // Weapon reloaded
152+
"weapon_zoom": nil, // Zooming in
146153
}
147154

148155
return geh
@@ -284,9 +291,7 @@ func (geh gameEventHandler) playerHurt(data map[string]*msg.CSVCMsg_GameEventKey
284291
}
285292

286293
func (geh gameEventHandler) playerBlind(data map[string]*msg.CSVCMsg_GameEventKeyT) {
287-
// Player.FlashDuration hasn't been updated yet,
288-
// so we need to wait until the end of the tick before dispatching
289-
geh.delay(events.PlayerFlashed{
294+
geh.dispatch(events.PlayerFlashed{
290295
Player: geh.playerByUserID32(data["userid"].GetValShort()),
291296
Attacker: geh.gameState().lastFlasher,
292297
})
@@ -308,7 +313,7 @@ func (geh gameEventHandler) heGrenadeDetonate(data map[string]*msg.CSVCMsg_GameE
308313
}
309314

310315
func (geh gameEventHandler) decoyStarted(data map[string]*msg.CSVCMsg_GameEventKeyT) {
311-
geh.delay(events.DecoyStart{
316+
geh.dispatch(events.DecoyStart{
312317
GrenadeEvent: geh.nadeEvent(data, common.EqDecoy),
313318
})
314319
}
@@ -332,7 +337,7 @@ func (geh gameEventHandler) smokeGrenadeExpired(data map[string]*msg.CSVCMsg_Gam
332337
}
333338

334339
func (geh gameEventHandler) infernoStartBurn(data map[string]*msg.CSVCMsg_GameEventKeyT) {
335-
geh.delay(events.FireGrenadeStart{
340+
geh.dispatch(events.FireGrenadeStart{
336341
GrenadeEvent: geh.nadeEvent(data, common.EqIncendiary),
337342
})
338343
}
@@ -382,25 +387,18 @@ func (geh gameEventHandler) playerTeam(data map[string]*msg.CSVCMsg_GameEventKey
382387
if player != nil {
383388
if player.Team != newTeam {
384389
player.Team = newTeam
385-
386-
oldTeam := common.Team(data["oldteam"].GetValByte())
387-
// Delayed for two reasons
388-
// - team IDs of other players changing teams in the same tick might not have changed yet
389-
// - player entities might not have been re-created yet after a reconnect
390-
geh.delay(events.PlayerTeamChange{
391-
Player: player,
392-
IsBot: data["isbot"].GetValBool(),
393-
Silent: data["silent"].GetValBool(),
394-
NewTeam: newTeam,
395-
NewTeamState: geh.gameState().Team(newTeam),
396-
OldTeam: oldTeam,
397-
OldTeamState: geh.gameState().Team(oldTeam),
398-
})
399-
} else {
400-
geh.dispatch(events.ParserWarn{
401-
Message: "Player team swap game-event occurred but player.Team == newTeam",
402-
})
403390
}
391+
392+
oldTeam := common.Team(data["oldteam"].GetValByte())
393+
geh.dispatch(events.PlayerTeamChange{
394+
Player: player,
395+
IsBot: data["isbot"].GetValBool(),
396+
Silent: data["silent"].GetValBool(),
397+
NewTeam: newTeam,
398+
NewTeamState: geh.gameState().Team(newTeam),
399+
OldTeam: oldTeam,
400+
OldTeamState: geh.gameState().Team(oldTeam),
401+
})
404402
} else {
405403
geh.dispatch(events.ParserWarn{
406404
Message: "Player team swap game-event occurred but player is nil",
@@ -479,8 +477,7 @@ func (geh gameEventHandler) itemEquip(data map[string]*msg.CSVCMsg_GameEventKeyT
479477

480478
func (geh gameEventHandler) itemPickup(data map[string]*msg.CSVCMsg_GameEventKeyT) {
481479
player, weapon := geh.itemEvent(data)
482-
// Delayed because of #119 - Equipment.UniqueID()
483-
geh.parser.delayedEvents = append(geh.parser.delayedEvents, events.ItemPickup{
480+
geh.dispatch(events.ItemPickup{
484481
Player: player,
485482
Weapon: *weapon,
486483
})

parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ type Parser struct {
7272
gameEventDescs map[int32]*msg.CSVCMsg_GameEventListDescriptorT // Maps game-event IDs to descriptors
7373
grenadeModelIndices map[int]common.EquipmentElement // Used to map model indices to grenades (used for grenade projectiles)
7474
stringTables []*msg.CSVCMsg_CreateStringTable // Contains all created sendtables, needed when updating them
75-
delayedEvents []interface{} // Contains events that need to be dispatched at the end of a tick (e.g. flash events because FlashDuration isn't updated before that)
75+
delayedEventHandlers []func() // Contains event handlers that need to be executed at the end of a tick (e.g. flash events because FlashDuration isn't updated before that)
7676
}
7777

7878
// NetMessageCreator creates additional net-messages to be dispatched to net-message handlers.

parsing.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,10 @@ var frameParsedToken = new(frameParsedTokenType)
333333
func (p *Parser) handleFrameParsed(*frameParsedTokenType) {
334334
// PlayerFlashed events need to be dispatched at the end of the tick
335335
// because Player.FlashDuration is updated after the game-events are parsed.
336-
for _, e := range p.delayedEvents {
337-
p.eventDispatcher.Dispatch(e)
336+
for _, eventHandler := range p.delayedEventHandlers {
337+
eventHandler()
338338
}
339-
p.delayedEvents = p.delayedEvents[:0]
339+
p.delayedEventHandlers = p.delayedEventHandlers[:0]
340340

341341
p.currentFrame++
342342
p.eventDispatcher.Dispatch(events.TickDone{})

0 commit comments

Comments
 (0)