@@ -72,84 +72,99 @@ type gameEventHandlerFunc func(map[string]*msg.CSVCMsg_GameEventKeyT)
7272func newGameEventHandler (parser * Parser ) gameEventHandler {
7373 geh := gameEventHandler {parser : parser }
7474
75+ // some events need to be delayed until their data is available
76+ // some events can't be delayed because the required state is lost by the end of the tick
77+ // TODO: maybe we're supposed to delay all of them and store the data we need until the end of the tick
7578 delay := func (f gameEventHandlerFunc ) gameEventHandlerFunc {
7679 return func (data map [string ]* msg.CSVCMsg_GameEventKeyT ) {
7780 parser .delayedEventHandlers = append (parser .delayedEventHandlers , func () {
7881 f (data )
7982 })
8083 }
8184 }
85+
86+ // some events only need to be delayed at the start of the demo until players are connected
87+ delayIfNoPlayers := func (f gameEventHandlerFunc ) gameEventHandlerFunc {
88+ return func (data map [string ]* msg.CSVCMsg_GameEventKeyT ) {
89+ if len (parser .gameState .playersByUserID ) == 0 {
90+ delay (f )
91+ } else {
92+ f (data )
93+ }
94+ }
95+ }
96+
8297 geh .gameEventNameToHandler = map [string ]gameEventHandlerFunc {
8398 // sorted alphabetically
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
99+ "announce_phase_end" : nil , // Dunno
100+ "begin_new_match" : geh .beginNewMatch , // Match started
101+ "bomb_beep" : nil , // Bomb beep
102+ "bomb_begindefuse" : geh .bombBeginDefuse , // Defuse started
103+ "bomb_beginplant" : geh .bombBeginPlant , // Plant started
104+ "bomb_defused" : geh .bombDefused , // Defuse finished
105+ "bomb_dropped" : geh .bombDropped , // Bomb dropped
106+ "bomb_exploded" : geh .bombExploded , // Bomb exploded
107+ "bomb_pickup" : geh .bombPickup , // Bomb picked up
108+ "bomb_planted" : geh .bombPlanted , // Plant finished
109+ "bot_takeover" : geh .botTakeover , // Bot got taken over
110+ "buytime_ended" : nil , // Not actually end of buy time, seems to only be sent once per game at the start
111+ "cs_match_end_restart" : nil , // Yawn
112+ "cs_pre_restart" : nil , // Not sure, doesn't seem to be important
113+ "cs_round_final_beep" : nil , // Final beep
114+ "cs_round_start_beep" : nil , // Round start beeps
115+ "cs_win_panel_match" : geh .csWinPanelMatch , // Not sure, maybe match end event???
116+ "cs_win_panel_round" : nil , // Win panel, (==end of match?)
117+ "decoy_detonate" : geh .decoyDetonate , // Decoy exploded/expired
118+ "decoy_started" : delay (geh .decoyStarted ), // Decoy started. Delayed because projectile entity is not yet created
119+ "endmatch_cmm_start_reveal_items" : nil , // Drops
120+ "flashbang_detonate" : geh .flashBangDetonate , // Flash exploded
121+ "hegrenade_detonate" : geh .heGrenadeDetonate , // HE exploded
122+ "hltv_chase" : nil , // Don't care
123+ "hltv_fixed" : nil , // Dunno
124+ "hltv_status" : nil , // Don't know
125+ "inferno_expire" : geh .infernoExpire , // Incendiary expired
126+ "inferno_startburn" : delay (geh .infernoStartBurn ), // Incendiary exploded/started. Delayed because inferno entity is not yet created
127+ "item_equip" : delay (geh .itemEquip ), // Equipped / weapon swap, I think. Delayed because of #142 - Bot entity possibly not yet created
128+ "item_pickup" : delay (geh .itemPickup ), // Picked up or bought? Delayed because of #119 - Equipment.UniqueID()
129+ "item_remove" : geh .itemRemove , // Dropped?
130+ "other_death" : nil , // Dunno
131+ "player_blind" : delay (geh .playerBlind ), // Player got blinded by a flash. Delayed because Player.FlashDuration hasn't been updated yet
132+ "player_changename" : nil , // Name change
133+ "player_connect" : geh .playerConnect , // Bot connected or player reconnected, players normally come in via string tables & data tables
134+ "player_connect_full" : nil , // Connecting finished
135+ "player_death" : delayIfNoPlayers ( geh .playerDeath ), // Player died
136+ "player_disconnect" : geh .playerDisconnect , // Player disconnected (kicked, quit, timed out etc.)
137+ "player_falldamage" : nil , // Falldamage
138+ "player_footstep" : delayIfNoPlayers ( geh .playerFootstep ), // Footstep sound.- Delayed because otherwise Player might be nil
139+ "player_hurt" : geh .playerHurt , // Player got hurt
140+ "player_jump" : geh .playerJump , // Player jumped
141+ "player_spawn" : nil , // Player spawn
127142
128143 // Player changed team. Delayed for two reasons
129144 // - team IDs of other players changing teams in the same tick might not have changed yet
130145 // - player entities might not have been re-created yet after a reconnect
131146 "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
147+ "round_announce_final" : geh .roundAnnounceFinal , // 30th round for normal de_, not necessarily matchpoint
148+ "round_announce_last_round_half" : geh .roundAnnounceLastRoundHalf , // Last round of the half
149+ "round_announce_match_point" : nil , // Match point announcement
150+ "round_announce_match_start" : nil , // Special match start announcement
151+ "round_announce_warmup" : nil , // Dunno
152+ "round_end" : geh .roundEnd , // Round ended and the winner was announced
153+ "round_freeze_end" : geh .roundFreezeEnd , // Round start freeze ended
154+ "round_mvp" : geh .roundMVP , // Round MVP was announced
155+ "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)
156+ "round_poststart" : nil , // Ditto
157+ "round_prestart" : nil , // Ditto
158+ "round_start" : geh .roundStart , // Round started
159+ "round_time_warning" : nil , // Round time warning
160+ "server_cvar" : nil , // Dunno
161+ "smokegrenade_detonate" : geh .smokeGrenadeDetonate , // Smoke popped
162+ "smokegrenade_expired" : geh .smokeGrenadeExpired , // Smoke expired
163+ "tournament_reward" : nil , // Dunno
164+ "weapon_fire" : delayIfNoPlayers ( geh .weaponFire ), // Weapon was fired
165+ "weapon_fire_on_empty" : nil , // Sounds boring
166+ "weapon_reload" : geh .weaponReload , // Weapon reloaded
167+ "weapon_zoom" : nil , // Zooming in
153168 }
154169
155170 return geh
0 commit comments