Subversion Repositories Games.Chess Giants

Rev

Rev 153 | Rev 177 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
// network.cpp
2
 
3
#include "common.h"
4
 
5
 
6
// prototypes of local functions
7
static void EvaluateServerReply (player_t *player);
8
 
9
 
153 pmbaty 10
bool Network_Init (void)
11
{
12
   // this function initializes the network subsystem on operating systems that require it
13
 
14
#ifdef _WIN32
15
   static bool is_winsock_initialized = false;
16
   WSADATA wsa_data;
17
 
18
   if (!is_winsock_initialized)
19
      is_winsock_initialized = (WSAStartup (MAKEWORD (2, 2), &wsa_data) == 0);
20
 
21
   return (is_winsock_initialized); // return whether the network subsystem was successfully initialized
22
#else // !_WIN32
23
   return (true); // all other systems than Win32 don't need to initialize the network
24
#endif // _WIN32
25
}
26
 
27
 
1 pmbaty 28
bool PlayerNetwork_Init (player_t *player)
29
{
30
   // this function initializes the network layer and connects to the chess server
31
 
32
   struct hostent *hostinfo;
33
   struct sockaddr_in service;
34
   unsigned long nonblocking_mode;
35
   char ascii_hostname[256];
36
 
37
   onlineplayers = NULL; // ensure the online players array is empty
38
   onlineplayer_count = 0; // and reset the online players count
39
   onlineplayers_updated = false;
40
 
41
   soughtgames = NULL; // ensure the sought games array is empty
42
   soughtgame_count = 0; // and reset the sought games count
43
   soughtgames_updated = false;
44
   lastsought_time = 0;
45
 
46
   chatterchannels = NULL; // ensure the chatter channels array is empty
47
   chatterchannel_count = 0; // and reset the chatter channels count
48
   chatterchannels_updated = false;
49
   selected_chatterchannel = NULL;
50
 
51
   PlayerCards_Init (); // initialize the player cards array
52
   Challenges_Init (); // initialize the challenges array
53
   Interlocutors_Init (); // initialize the interlocutors array
54
 
55
   server_motd[0] = 0; // reset the server MOTD
56
 
57
   player->is_connected = false; // remember we aren't connected yet
58
   player->is_logged_in = false; // and not logged in either
59
   player->is_in_game = false; // we aren't in game either
60
   player->game_number = 0;
61
   player->remaining_seconds = 0;
62
   player->our_socket = INVALID_SOCKET; // and that we have no socket yet
63
   player->name[0] = 0; // player name undefined
64
 
153 pmbaty 65
   // initialize the network subsystem if required
66
   if (!Network_Init ())
1 pmbaty 67
   {
68
      messagebox.hWndParent = hMainWnd;
69
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
70
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed"));
71
      messagebox.flags = MB_ICONWARNING | MB_OK;
72
      DialogBox_Message (&messagebox); // display a modeless error message box
73
 
74
      PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
75
      return (false);
76
   }
77
 
78
   // get the chess server's IP address from the host name
79
   ConvertTo7BitASCII (ascii_hostname, sizeof (ascii_hostname), options.network.server_address);
80
   hostinfo = gethostbyname (ascii_hostname);
81
   if (hostinfo == NULL)
82
   {
83
      messagebox.hWndParent = hMainWnd;
84
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
85
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed"));
86
      messagebox.flags = MB_ICONWARNING | MB_OK;
87
      DialogBox_Message (&messagebox); // display a modeless error message box
88
 
89
      PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
90
      return (false);
91
   }
92
 
93
   // fill in the sockaddr server structure with the server hostinfo data
94
   service.sin_family = AF_INET;
95
   service.sin_addr.s_addr = inet_addr (inet_ntoa (*(struct in_addr *) hostinfo->h_addr_list[0]));
96
   service.sin_port = htons (options.network.server_port);
97
 
98
   // create our socket
99
   if ((player->our_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
100
   {
101
      messagebox.hWndParent = hMainWnd;
102
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
103
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed"));
104
      messagebox.flags = MB_ICONWARNING | MB_OK;
105
      DialogBox_Message (&messagebox); // display a modeless error message box
106
 
107
      PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
108
      return (false);
109
   }
110
 
111
   // connect the game to the chess server using that socket
112
   if (connect (player->our_socket, (struct sockaddr *) &service, sizeof (service)) == -1)
113
   {
114
      messagebox.hWndParent = hMainWnd;
115
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
116
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed"));
117
      messagebox.flags = MB_ICONWARNING | MB_OK;
118
      DialogBox_Message (&messagebox); // display a modeless error message box
119
 
120
      PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
121
      return (false);
122
   }
123
 
124
   // set it to be non-blocking (but only AFTER the connection is made)
125
   nonblocking_mode = 1;
126
   if (ioctlsocket (player->our_socket, FIONBIO, &nonblocking_mode) == SOCKET_ERROR)
127
   {
128
      messagebox.hWndParent = hMainWnd;
129
      wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
130
      wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_NetworkInitializationFailed"));
131
      messagebox.flags = MB_ICONWARNING | MB_OK;
132
      DialogBox_Message (&messagebox); // display a modeless error message box
133
 
134
      PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
135
      return (false);
136
   }
137
 
138
   // initialize the debug log file
139
   Debug_Init (L"Chess server output.txt");
140
 
141
   player->is_connected = true; // remember we are connected
142
   return (true); // finished, we have a valid, connected socket
143
}
144
 
145
 
146
void PlayerNetwork_Shutdown (player_t *player)
147
{
148
   // this function shutdowns the network layer
149
 
150
   int chatterchannel_index;
151
 
152
   // shutdown the socket if it is open. This will disconnect us from the server.
153
   if (player->our_socket != INVALID_SOCKET)
154
      closesocket (player->our_socket); // close the network socket
155
   player->our_socket = INVALID_SOCKET;
156
 
157
   player->is_connected = false; // remember we are no longer connected
158
   player->is_logged_in = false; // and not logged in either
159
   player->is_in_game = false; // we aren't in game either
160
   player->game_number = 0;
161
   player->remaining_seconds = 0;
162
   player->name[0] = 0; // player name undefined
163
 
164
   server_motd[0] = 0; // reset the server MOTD
165
 
166
   // cycle through all chatter channels we know...
167
   for (chatterchannel_index = 0; chatterchannel_index < chatterchannel_count; chatterchannel_index++)
168
   {
169
      SAFE_free ((void **) &chatterchannels[chatterchannel_index].members); // free their member list
170
      chatterchannels[chatterchannel_index].member_count = 0; // reset their members count
171
   }
172
   SAFE_free ((void **) &chatterchannels); // free the chatter channels array
173
   chatterchannel_count = 0; // and reset the chatter channels count
174
   chatterchannels_updated = false;
175
   selected_chatterchannel = NULL;
176
 
177
   SAFE_free ((void **) &soughtgames); // free the sought games array
178
   soughtgame_count = 0; // and reset the sought games count
179
   soughtgames_updated = false;
180
 
181
   SAFE_free ((void **) &onlineplayers); // free the online players array
182
   onlineplayer_count = 0; // and reset the online players count
183
   onlineplayers_updated = false;
184
 
185
   Interlocutors_Shutdown (); // shutdown the interlocutors
186
   Challenges_Shutdown (); // shutdown the challenges
187
   PlayerCards_Shutdown (); // shutdown the player cards
188
 
189
   // shutdown all possible opened UI windows
190
   if (IsWindow (hChatterChannelsWnd))
191
      DestroyWindow (hChatterChannelsWnd);
192
   hChatterChannelsWnd = NULL;
193
   if (IsWindow (hGamesWnd))
194
      DestroyWindow (hGamesWnd);
195
   hGamesWnd = NULL;
196
   if (IsWindow (hMOTDWnd))
197
      DestroyWindow (hMOTDWnd);
198
   hMOTDWnd = NULL;
199
   if (IsWindow (hOpponentsWnd))
200
      DestroyWindow (hOpponentsWnd);
201
   hOpponentsWnd = NULL;
202
   if (IsWindow (hSoughtWnd))
203
      DestroyWindow (hSoughtWnd);
204
   hSoughtWnd = NULL;
205
 
206
   // shutdown WinSock
207
   WSACleanup ();
208
 
209
   return; // finished
210
}
211
 
212
 
213
bool PlayerNetwork_Think (player_t *player)
214
{
215
   // this function is called once per game tick to listen to the network and react to what the server tells us. Returns TRUE
216
   // if we need to update the scene.
217
 
218
   player_t *local_player;
219
   char *block_start;
220
   char *block_end;
221
   char *ascii_sendbuffer; // mallocated
222
   wchar_t *widechar_buffer; // mallocated
223
   wchar_t *widechar_line;
224
   int send_retval;
225
   int recv_retval;
226
   int byte_index;
227
   int rewrite_index;
228
   int length;
229
   bool do_update;
230
 
231
   // are we NOT connected yet ?
232
   if (!player->is_connected)
233
      return (false); // consistency check: if we aren't connected, don't do anything
234
 
235
   // are we NOT logged in yet AND is our socket valid AND is there nothing in the center of the screen yet ?
236
   if (!player->is_logged_in && (player->our_socket != INVALID_SOCKET) && !the_scene.gui.central_text.is_displayed)
237
   {
140 pmbaty 238
      Scene_UpdateText (&the_scene.gui.central_text, RGBA_TO_RGBACOLOR (255, 255, 255, 191), DURATION_INFINITE, true, LOCALIZE (L"Connecting")); // display "connecting" in the middle of the screen
1 pmbaty 239
      the_scene.gui.want_spinwheel = true; // start spinning wheel
240
   }
241
 
242
   do_update = false; // assume we don't need to update the scene until told otherwise
243
 
244
   ////////////////////////////
245
   // BEGIN listening to server
246
 
247
   // proceed in filling the ascii buffer with what's coming
248
 
249
   // get a hand on the end of the player's recv buffer and compute its remaining size
250
   length = strlen (player->ascii_recvbuffer);
251
 
252
   // if the server sent us something, append it to what we've received
253
   recv_retval = recv (player->our_socket, &player->ascii_recvbuffer[length], player->recvbuffer_size - length, 0);
254
   if (recv_retval > 0)
255
   {
256
      // parse all received data and eradicate all carriage returns. Also convert %'s to a safer glyph.
257
      rewrite_index = 0;
258
      for (byte_index = 0; byte_index < recv_retval; byte_index++)
259
         if (player->ascii_recvbuffer[length + byte_index] != '\r')
260
         {
261
            if (player->ascii_recvbuffer[length + byte_index] == '%')
262
               player->ascii_recvbuffer[length + rewrite_index] = '¤';
263
            else
264
               player->ascii_recvbuffer[length + rewrite_index] = player->ascii_recvbuffer[length + byte_index];
265
            rewrite_index++;
266
         }
267
      player->ascii_recvbuffer[length + rewrite_index] = 0; // terminate the buffer ourselves
268
      length = strlen (player->ascii_recvbuffer); // and update the new recvbuffer's length
269
   }
270
   else if (recv_retval == SOCKET_ERROR)
271
   {
272
      recv_retval = WSAGetLastError (); // ask Windows to be more specific about the error
273
      if (recv_retval == WSAEWOULDBLOCK)
274
         ; // it's okay. We're a non-blocking socket.
275
      else if (recv_retval == WSAETIMEDOUT)
276
      {
277
         messagebox.hWndParent = hMainWnd;
278
         wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
279
         wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ConnectionToChessServerLost"));
280
         messagebox.flags = MB_ICONWARNING | MB_OK;
281
         DialogBox_Message (&messagebox); // display a modeless error message box
282
 
283
         PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
284
         return (false);
285
      }
286
   }
287
 
288
   // END listening to server
289
   //////////////////////////
290
 
291
   //////////////////////////////////
292
   // BEGIN evaluating server replies
293
 
294
   // are we NOT logged in yet ?
295
   if (!player->is_logged_in)
296
   {
297
      // is it a login prompt ?
298
      if ((length > 7) && (strcmp (&player->ascii_recvbuffer[length - 7], "login: ") == 0))
299
      {
300
         Player_SendBuffer_Add (player, 1000, L"%s\n", options.network.login); // send the login string
301
         player->ascii_recvbuffer[0] = 0; // and discard recvbuffer as we've processed this message
302
      }
303
 
304
      // else is it a password prompt ?
305
      else if (((length > 10) && (strcmp (&player->ascii_recvbuffer[length - 10], "password: ") == 0))
306
               || ((length > 3) && (strcmp (&player->ascii_recvbuffer[length - 3], "\":\n") == 0)))
307
      {
308
         Player_SendBuffer_Add (player, 1000, L"%s\n", options.network.password); // send the password string
309
         player->ascii_recvbuffer[0] = 0; // and discard recvbuffer as we've processed this message
310
      }
311
 
312
      // else is it a confirmation that we've successfully logged in ?
313
      else if (((block_start = strstr (player->ascii_recvbuffer, "\n**** Starting FICS session as ")) != NULL)
314
               && (block_end = strstr (player->ascii_recvbuffer, " ****\n")))
315
      {
316
         player->is_logged_in = true; // remember we are logged in
317
         the_scene.gui.central_text.disappear_time = current_time + 1.0f; // fade the "connecting" phrase out now (FIXME: ugly)
318
         the_scene.gui.want_spinwheel = false; // stop spinning wheel
319
         do_update = true; // and update the scene
320
 
321
         block_start += 31; // skip the "\n**** Starting FICS session as " substring
322
         local_player = Player_FindByType (PLAYER_HUMAN); // get a pointer to the local player
323
 
324
         // copy out local player's login name, as reported by server, and convert it to wchar_t
325
         for (byte_index = 0; (byte_index < WCHAR_SIZEOF (local_player->name)) && isalpha (block_start[byte_index]); byte_index++)
326
            local_player->name[byte_index] = (wchar_t) block_start[byte_index]; // copy nickname one character after the other. Very dirty conversion.
327
         if (byte_index < WCHAR_SIZEOF (local_player->name))
328
            local_player->name[byte_index] = 0; // finish the string ourselves
329
         else
330
            local_player->name[WCHAR_SIZEOF (local_player->name) - 1] = 0; // truncate it if neeeded
331
 
332
         server_motd[0] = 0; // remember we haven't read the MOTD yet
333
         the_board.reevaluate = true; // reeevaluate the board (to update the title bar)
334
 
335
         // see if there's more data to parse after this message, in which case move it in place
336
         length = strlen (block_end + 6);
337
         if (length > 0)
338
            memmove (player->ascii_recvbuffer, block_end + 6, length + 1);
339
         else
340
            player->ascii_recvbuffer[0] = 0; // else discard recvbuffer as we've processed this message
341
      }
342
   }
343
 
344
   // else we are logged in
345
   else
346
   {
347
      // see if we have a complete reply block (remember: percent sign was replaced with '¤')
348
      block_end = strstr (player->ascii_recvbuffer, "\nfics¤ ");
349
 
350
      // as long as we can find some...
351
      while (block_end != NULL)
352
      {
353
         *block_end = 0; // break the string here
354
 
355
         // convert the block to wide char and evaluate it, taking action if needed
356
         ConvertToWideChar (player->recvbuffer, player->recvbuffer_size, player->ascii_recvbuffer);
357
         Debug_Log (L"RECEIVED:[%s]\n", player->recvbuffer); // log what we've received
358
         EvaluateServerReply (player); // and evaluate it
359
 
360
         // see if there's more data to parse after this message, in which case move it in place
361
         length = strlen (block_end + 7);
362
         if (length > 0)
363
            memmove (player->ascii_recvbuffer, block_end + 7, length + 1);
364
         else
365
         {
366
            player->ascii_recvbuffer[0] = 0;
367
            break; // it was the last prompt, so discard recvbuffer as we've processed this message
368
         }
369
         block_end = strstr (player->ascii_recvbuffer, "\nfics¤ "); // remember: percent sign was replaced with '¤'
370
      }
371
   }
372
 
373
   // END evaluating server replies
374
   ////////////////////////////////
375
 
171 pmbaty 376
   // have we been notified that the current player just changed ?
377
   if (player->should_wakeup)
1 pmbaty 378
   {
171 pmbaty 379
      // has at least one move been played AND is it the remote player's turn now ?
380
      if ((the_board.move_count > 1) && (Board_ColorToMove (&the_board) == player->color))
381
      {
382
         Debug_Log (L"===Local player just played, sending the chosen move to chess server===\n");
383
         Player_SendBuffer_Add (player, 1000, L"%s\n", the_board.moves[the_board.move_count - 1].pgntext); // send the move string to the chess server
384
      }
385
      player->should_wakeup = false; // remember we took this notification into account
1 pmbaty 386
   }
387
 
388
   // has the user entered some chatter text ?
389
   if (!the_scene.gui.is_entering_text && (the_scene.gui.entered_ccreply.text != NULL))
390
   {
391
      // is player logged in AND has a chatter channel been selected ? if so, send chat string to server
392
      if (player->is_logged_in && (selected_chatterchannel != NULL))
393
         Player_SendBuffer_Add (player, 1000, L"+channel %d\ntell %d %s\n", selected_chatterchannel->id, selected_chatterchannel->id, the_scene.gui.entered_ccreply.text);
394
 
395
      // reset the entered text buffer
396
      SAFE_free ((void **) &the_scene.gui.entered_ccreply.text); // reset the entered text buffer
397
      the_scene.gui.entered_ccreply.text_length = 0; // and set its length to zero
398
   }
399
 
400
   // does the local player want to cancel its last move ? this can be either HIS move or HIS OPPONENTS's move...
401
   local_player = Player_FindByType (PLAYER_HUMAN); // get a pointer to the local player
402
   if ((local_player != NULL) && local_player->wants_cancel)
403
   {
404
      Player_SendBuffer_Add (player, 1000, L"takeback\n"); // send the takeback request to our opponent
405
      Interlocutor_Notify (Interlocutor_FindOrCreate (player->name), LOCALIZE (L"Chat_TakebackRequestSent"), player->name); // send a notification to its chat window
136 pmbaty 406
      the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again)
1 pmbaty 407
      local_player->wants_cancel = false; // don't do this all day long
408
   }
409
   if (player->wants_cancel)
410
   {
411
      Player_SendBuffer_Add (player, 1000, L"takeback\n"); // send the takeback request to our opponent
412
      Interlocutor_Notify (Interlocutor_FindOrCreate (player->name), LOCALIZE (L"Chat_TakebackRequestSent"), player->name); // send a notification to its chat window
136 pmbaty 413
      the_board.game_state = STATE_PLAYING; // remember the game is now playing (in case we wanted to cancel the closing move of a finished game, this opens the game again)
1 pmbaty 414
      player->wants_cancel = false; // don't do this all day long
415
   }
416
 
417
   // if we have something to send, do it
418
   if (!player->sendbuffer_locked && (player->sendbuffer[0] != 0) && (animation_endtime + 1.0f < current_time))
419
   {
420
      // log what we're sending
421
      Debug_Log (L"SENDING:[%s]\n", player->sendbuffer);
422
 
423
      player->sendbuffer_locked = true; // lock the buffer
424
 
425
      // now read line per line (mallocate a line buffer as large as necessary)
426
      length = wcslen (player->sendbuffer) + 1 + 1; // +1 for \n, +1 for null terminator
427
      ascii_sendbuffer = (char *) SAFE_malloc (length, sizeof (char), false);
428
      widechar_buffer = (wchar_t *) SAFE_malloc (length, sizeof (wchar_t), false);
429
      widechar_line = player->sendbuffer; // start at the first character
430
      while ((widechar_line = wcsgets (widechar_buffer, length, widechar_line)) != NULL)
431
      {
432
         wcscat_s (widechar_buffer, length, L"\n"); // put the carriage return back
433
         ConvertTo7BitASCII (ascii_sendbuffer, length, widechar_buffer); // convert to ASCII
434
         send_retval = send (player->our_socket, ascii_sendbuffer, strlen (ascii_sendbuffer), 0); // send data
435
      }
436
      SAFE_free ((void **) &widechar_buffer); // we no longer need the line buffer, so free it
437
      SAFE_free ((void **) &ascii_sendbuffer);
438
 
439
      player->sendbuffer[0] = 0; // what we had to send has been sent, reset the send buffer
440
      player->sendbuffer_locked = false; // and unlock it
441
 
442
      // did send() report an error ?
443
      if (send_retval == SOCKET_ERROR)
444
      {
445
         messagebox.hWndParent = hMainWnd;
446
         wcscpy_s (messagebox.title, WCHAR_SIZEOF (messagebox.title), LOCALIZE (L"ImportantMessage"));
447
         wcscpy_s (messagebox.text, WCHAR_SIZEOF (messagebox.text), LOCALIZE (L"Error_ConnectionToChessServerLost"));
448
         messagebox.flags = MB_ICONERROR | MB_OK;
449
         DialogBox_Message (&messagebox); // display a modeless error message box
450
 
451
         PlayerNetwork_Shutdown (player); // on error, shutdown the network and display an error message
452
         return (true); // on error, cancel
453
      }
454
   }
455
 
456
   return (do_update); // finished
457
}
458
 
459
 
460
static void EvaluateServerReply (player_t *player)
461
{
462
   // this function parses a network reply and evaluates it, deciding what to do
463
 
464
   //////////////////////
465
   // OUT OF GAME REPLIES
466
 
467
   // the MOTD is the first reply to be evaluated
468
   EvaluateServerReply_MOTD (player);
469
 
470
   // evaluate dangerous replies first, i.e. those that contain user-settable text
471
   EvaluateServerReply_Announcement (player);
472
   EvaluateServerReply_ChannelMessage (player);
473
   EvaluateServerReply_PrivateMessage (player);
474
   EvaluateServerReply_Finger (player);
475
 
476
   // the less dangerous replies can now be evaluated without ambiguity
477
   EvaluateServerReply_Seek (player);
478
   EvaluateServerReply_Challenge (player);
479
   EvaluateServerReply_ChallengeAccepted (player);
480
   EvaluateServerReply_ChallengeDeclined (player);
481
   EvaluateServerReply_Takeback (player);
482
   EvaluateServerReply_TakebackDeclinedByOther (player);
483
   EvaluateServerReply_TakebackDeclinedByYou (player);
484
   EvaluateServerReply_PlayNotAllowed (player);
485
   EvaluateServerReply_PlayUnexistent (player);
486
   EvaluateServerReply_PlayWrongRating (player);
487
   EvaluateServerReply_ChannelsAndMembers (player);
488
   EvaluateServerReply_SoughtList (player);
489
   EvaluateServerReply_PlayersList (player);
490
 
491
   //////////////////
492
   // IN GAME REPLIES
493
 
494
   EvaluateServerReply_GameStarting (player);
495
   EvaluateServerReply_GameState (player);
496
   EvaluateServerReply_GameResults (player);
497
 
498
   return; // finished evaluating this reply
499
}