]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi.cpp
use a better multi_sw_ok_to_commit() check
[taylor/freespace2.git] / src / network / multi.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Network/Multi.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C file that contains high-level multiplayer functions
16  *
17  * $Log$
18  * Revision 1.5  2002/06/09 04:41:23  relnev
19  * added copyright header
20  *
21  * Revision 1.4  2002/05/27 00:40:47  theoddone33
22  * Fix net_addr vs net_addr_t
23  *
24  * Revision 1.3  2002/05/26 20:22:48  theoddone33
25  * Most of network/ works
26  *
27  * Revision 1.2  2002/05/07 03:16:47  theoddone33
28  * The Great Newline Fix
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:10  root
31  * Initial import.
32  *
33  * 
34  * 47    9/15/99 1:45a Dave
35  * Don't init joystick on standalone. Fixed campaign mode on standalone.
36  * Fixed no-score-report problem in TvT
37  * 
38  * 46    8/24/99 1:49a Dave
39  * Fixed client-side afterburner stuttering. Added checkbox for no version
40  * checking on PXO join. Made button info passing more friendly between
41  * client and server.
42  * 
43  * 45    8/22/99 5:53p Dave
44  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
45  * instead of ship designations for multiplayer players.
46  * 
47  * 44    8/22/99 1:19p Dave
48  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
49  * which d3d cards are detected.
50  * 
51  * 43    8/19/99 10:59a Dave
52  * Packet loss detection.
53  * 
54  * 42    8/16/99 4:05p Dave
55  * Big honking checkin.
56  * 
57  * 41    8/06/99 12:34a Dave
58  * Be more careful about resetting timestamps.
59  * 
60  * 40    8/04/99 2:24a Dave
61  * Fixed escort gauge ordering for dogfight.
62  * 
63  * 39    7/26/99 5:50p Dave
64  * Revised ingame join. Better? We'll see....
65  * 
66  * 38    7/08/99 10:53a Dave
67  * New multiplayer interpolation scheme. Not 100% done yet, but still
68  * better than the old way.
69  * 
70  * 37    7/06/99 4:24p Dave
71  * Mid-level checkin. Starting on some potentially cool multiplayer
72  * smoothness crap.
73  * 
74  * 36    7/03/99 5:50p Dave
75  * Make rotated bitmaps draw properly in padlock views.
76  * 
77  * 35    6/21/99 7:24p Dave
78  * netplayer pain packet. Added type E unmoving beams.
79  * 
80  * 34    6/07/99 9:51p Dave
81  * Consolidated all multiplayer ports into one.
82  * 
83  * 33    6/04/99 9:52a Dave
84  * Fixed some rendering problems.
85  * 
86  * 32    5/22/99 6:05p Dave
87  * Fixed a few localization # problems.
88  * 
89  * 31    5/22/99 5:35p Dave
90  * Debrief and chatbox screens. Fixed small hi-res HUD bug.
91  * 
92  * 30    5/14/99 1:59p Andsager
93  * Multiplayer message for subsystem cargo revealed.
94  * 
95  * 29    4/29/99 2:29p Dave
96  * Made flak work much better in multiplayer.
97  * 
98  * 28    4/28/99 11:13p Dave
99  * Temporary checkin of artillery code.
100  * 
101  * 27    4/25/99 7:43p Dave
102  * Misc small bug fixes. Made sun draw properly.
103  * 
104  * 26    4/25/99 3:02p Dave
105  * Build defines for the E3 build.
106  * 
107  * 25    4/12/99 10:07p Dave
108  * Made network startup more forgiving. Added checkmarks to dogfight
109  * screen for players who hit commit.
110  * 
111  * 24    4/09/99 2:21p Dave
112  * Multiplayer beta stuff. CD checking.
113  * 
114  * 23    3/19/99 9:51a Dave
115  * Checkin to repair massive source safe crash. Also added support for
116  * pof-style nebulae, and some new weapons code.
117  * 
118  * 23    3/11/99 5:53p Dave
119  * More network optimization. Spliced in Dell OEM planet bitmap crap.
120  * 
121  * 22    3/10/99 6:50p Dave
122  * Changed the way we buffer packets for all clients. Optimized turret
123  * fired packets. Did some weapon firing optimizations.
124  * 
125  * 21    3/09/99 6:24p Dave
126  * More work on object update revamping. Identified several sources of
127  * unnecessary bandwidth.
128  * 
129  * 20    3/08/99 7:03p Dave
130  * First run of new object update system. Looks very promising.
131  * 
132  * 19    3/02/99 4:40p Jasons
133  * Be more careful when calling server-lost-contact popup (make sure other
134  * popups aren't active)
135  * 
136  * 18    3/01/99 7:39p Dave
137  * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
138  * don't mix respawn points.
139  * 
140  * 17    2/23/99 2:29p Dave
141  * First run of oldschool dogfight mode. 
142  * 
143  * 16    2/19/99 2:55p Dave
144  * Temporary checking to report the winner of a squad war match.
145  * 
146  * 15    2/17/99 2:10p Dave
147  * First full run of squad war. All freespace and tracker side stuff
148  * works.
149  * 
150  * 14    2/12/99 6:16p Dave
151  * Pre-mission Squad War code is 95% done.
152  * 
153  * 13    2/11/99 3:08p Dave
154  * PXO refresh button. Very preliminary squad war support.
155  * 
156  * 12    1/14/99 12:48a Dave
157  * Todo list bug fixes. Made a pass at putting briefing icons back into
158  * FRED. Sort of works :(
159  * 
160  * 11    1/12/99 5:45p Dave
161  * Moved weapon pipeline in multiplayer to almost exclusively client side.
162  * Very good results. Bandwidth goes down, playability goes up for crappy
163  * connections. Fixed object update problem for ship subsystems.
164  * 
165  * 10    12/14/98 12:13p Dave
166  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
167  * Need to test now.
168  * 
169  * 9     12/03/98 5:22p Dave
170  * Ported over Freespace 1 multiplayer ships.tbl and weapons.tbl
171  * checksumming.
172  * 
173  * 8     11/19/98 4:19p Dave
174  * Put IPX sockets back in psnet. Consolidated all multiplayer config
175  * files into one.
176  * 
177  * 7     11/19/98 8:03a Dave
178  * Full support for D3-style reliable sockets. Revamped packet lag/loss
179  * system, made it receiver side and at the lowest possible level.
180  * 
181  * 6     11/17/98 11:12a Dave
182  * Removed player identification by address. Now assign explicit id #'s.
183  * 
184  * 5     11/12/98 12:13a Dave
185  * Tidied code up for multiplayer test. Put in network support for flak
186  * guns.
187  *  
188  *
189  * $NoKeywords: $
190  */
191
192 #ifndef PLAT_UNIX
193 #include <winsock2.h>
194 #endif
195
196 #include "pstypes.h"
197 #include "multi.h"
198 #include "multiutil.h"
199 #include "multimsgs.h"
200 #include "psnet.h"
201 #include "linklist.h"
202 #include "object.h"
203 #include "ship.h"
204 #include "hud.h"
205 #include "timer.h"
206 #include "player.h"
207 #include "missionload.h"
208 #include "missionparse.h"
209 #include "missionshipchoice.h"
210 #include "gamesequence.h"
211 #include "freespace.h"
212 #include "osapi.h"
213 #include "math.h"
214 #include "mouse.h"
215 #include "stats.h"
216 #include "stand_server.h"
217 #include "multi_xfer.h"
218 #include "multiui.h"
219 #include "key.h"
220 #include "multilag.h"
221 #include "multiutil.h"
222 #include "multi_ingame.h"
223 #include "bmpman.h"
224 #include "popup.h"
225 #include "cmdline.h"
226 #include "chatbox.h"
227 #include "multiteamselect.h"
228 #include "multi_data.h"
229 #include "multi_kick.h"
230 #include "multi_campaign.h"
231 #include "multi_voice.h"
232 #include "multi_team.h"
233 #include "multi_respawn.h"
234 #include "multi_pmsg.h"
235 #include "multi_endgame.h"
236 #include "missiondebrief.h"
237 #include "multi_pause.h"
238 #include "multi_obj.h"
239 #include "missiongoals.h"
240 #include "multi_log.h"
241 #include "multi_rate.h"
242 #include "hudescort.h"
243 #include "alphacolors.h"
244 #include "osregistry.h"
245 #include "multi_fstracker.h"
246 #include "multi_sw.h"
247
248
249 // ----------------------------------------------------------------------------------------
250 // Basic module scope defines
251 //
252 //
253
254 // timestamp defines
255 // #define NETGAME_SEND_TIME                                                            1000                                    // time between sending netgame update packets
256 // #define STATE_SEND_TIME                                                                      1000                                    // time between sending netplayer state packets
257 // #define GAMEINFO_SEND_TIME                                                           3000                                    // time between sending game information packets
258 // #define PING_SEND_TIME                                                                       2000                                    // time between player pings
259 // #define INGAME_UPDATE_TIME                                                           1000                                    // time limit between ingame join operations
260 #define NETGAME_SEND_TIME                                                               2                                               // time between sending netgame update packets
261 #define STATE_SEND_TIME                                                                 2                                               // time between sending netplayer state packets
262 #define GAMEINFO_SEND_TIME                                                              3                                               // time between sending game information packets
263 #define PING_SEND_TIME                                                                  2                                               // time between player pings
264 #define BYTES_SENT_TIME                                                                 5                                               // every five seconds
265
266 // netplayer stuff
267 #define CULL_ZOMBIE_TIME                                                                1000                                    //      zombies are checked for at this interval (in milliseconds)
268
269 // object update stuff
270 #define SEND_POS_INTERVAL                                                               30                                              // min time in milliseconds between sending position updates
271
272 // local network buffer stuff
273 #define MAX_NET_BUFFER                                                                  (1024 * 16)                     // define and variable declaration for our local tcp buffer
274 #define NUM_REENTRANT_LEVELS                                                    3
275
276 // time (in fixed seconds) to put up dialog about no contect from server
277 #define MULTI_SERVER_MAX_TIMEOUT                                                (F1_0 * 4)                                      // after this number of milliseoncds, stop client simulation
278 #define MULTI_SERVER_MAX_TIMEOUT_LARGE                          (F1_0 * 40)                                     // done anytime not in mission
279 #define MULTI_SERVER_WAIT_TIME                                          (F1_0 * 60)                                     // wait 60 seconds to reconnect with the server
280 #define MULTI_SERVER_GONE                                                               1
281 #define MULTI_SERVER_ALIVE                                                              2
282
283 #define DISCONNECT_TIMEOUT                                                              (F1_0 * 10)                                     // 10 seconds to timeout someone who cannot connnect
284
285 // define for when to show "slow network" icon
286 #define MULTI_SERVER_SLOW_PING_TIME                                     700                                     // when average ping time to server reaches this -- display hud icon
287
288 // update times for clients ships based on object update level
289 #define MULTI_CLIENT_UPDATE_TIME                                                333
290
291 int Multi_display_netinfo = 1;
292
293 // ----------------------------------------------------------------------------------------
294 // Multiplayer vars
295 //
296 //
297
298 // net player vars              
299 net_player Net_players[MAX_PLAYERS];                                                    // array of all netplayers in the game
300 net_player *Net_player;                                                                                         // pointer to console's net_player entry
301
302 // network object management
303 ushort Next_ship_signature;                                                                             // next permanent network signature to assign to an object
304 ushort Next_asteroid_signature;                                                                 // next signature for an asteroid
305 ushort Next_non_perm_signature;                                                                 // next non-permanent network signature to assign to an object
306 ushort Next_debris_signature;                                                                           // next debris signature
307
308 // netgame vars
309 netgame_info Netgame;                                                                                           // netgame information
310 int Multi_mission_loaded = 0;                                                                           // flag, so that we dont' load the mission more than once client side
311 int Ingame_join_net_signature = -1;                                                             // signature for the player obj for use when joining ingame
312 int Multi_button_info_ok = 0;                                                                           // flag saying it is ok to apply critical button info on a client machine
313 int Multi_button_info_id = 0;                                                                           // identifier of the stored button info to be applying
314
315 // low level networking vars
316 const int HEADER_LENGTH = 1;                                                                                                    // 1 byte (packet type)
317
318 // misc data
319 active_game* Active_game_head;                                                                  // linked list of active games displayed on Join screen
320 int Active_game_count;                                                                                          // for interface screens as well
321 CFILE* Multi_chat_stream;                                                                                       // for streaming multiplayer chat strings to a file
322 int Multi_has_cd = 0;                                                                                           // if this machine has a cd or not (call multi_common_verify_cd() to set this)
323 int Multi_connection_speed;                                                                             // connection speed of this machine.
324 int Multi_num_players_at_start = 0;                                                             // the # of players present (kept track of only on the server) at the very start of the mission
325 short Multi_id_num = 0;                                                                                         // for assigning player id #'s
326
327 // permanent server list
328 server_item* Game_server_head;                                                          // list of permanent game servers to be querying
329
330 // timestamp data
331 time_t Netgame_send_time = -1;                                                  // timestamp used to send netgame info to players before misison starts
332 time_t State_send_time = -1;                                                            // timestamp used to send state information to the host before a mission starts
333 time_t Gameinfo_send_time = -1;                                                 // timestamp used by master to send game information to clients
334 time_t Next_ping_time = -1;                                                             // when we should next ping all
335 int Multi_server_check_count = 0;                                       // var to keep track of reentrancy when checking server status
336 time_t Next_bytes_time = -1;                                                            // bytes sent
337
338 // how often each player gets updated
339 int Multi_client_update_times[MAX_PLAYERS];     // client update packet timestamp
340
341 // local network buffer data
342 static ubyte net_buffer[NUM_REENTRANT_LEVELS][MAX_NET_BUFFER];
343 static ubyte Multi_read_count;
344
345 int Multi_restr_query_timestamp = -1;
346 join_request Multi_restr_join_request;
347 net_addr_t Multi_restr_addr;                            
348 int Multi_join_restr_mode = -1;
349
350 SDL_COMPILE_TIME_ASSERT(addr, sizeof(Multi_restr_addr.addr) == IP_ADDRESS_LENGTH);
351
352 static fix Multi_server_wait_start;                             // variable to hold start time when waiting to reestablish with server
353
354 // non API master tracker vars
355 char Multi_tracker_login[100] = "";
356 char Multi_tracker_passwd[100] = "";
357 char Multi_tracker_squad_name[100] = "";
358 int Multi_tracker_id = -1;
359 char Multi_tracker_id_string[255];
360
361 // current file checksum
362 ushort Multi_current_file_checksum = 0;
363 int Multi_current_file_length = -1;
364
365
366 // -------------------------------------------------------------------------------------------------
367 //      multi_init() is called only once, at game start-up.  Get player address + port, initialize the
368 // network players list.
369 //
370 //
371
372 void multi_init()
373 {
374         int idx;
375         const char *ptr = NULL;
376
377         // read in config file
378         multi_options_read_config();
379
380         SDL_assert( Net_player == NULL );
381         Multi_id_num = 0;
382
383         // clear out all netplayers
384         memset(Net_players, 0, sizeof(net_player) * MAX_PLAYERS);
385         for(idx=0; idx<MAX_PLAYERS; idx++){
386                 Net_players[idx].reliable_socket = INVALID_SOCKET;
387         }
388
389         // initialize the local netplayer
390         Net_player = &Net_players[0];   
391         Net_player->tracker_player_id = Multi_tracker_id;
392         Net_player->player = Player;
393         Net_player->flags = 0;  
394         Net_player->s_info.xfer_handle = -1;
395         Net_player->player_id = multi_get_new_id();
396         Net_player->client_cinfo_seq = 0;
397         Net_player->client_server_seq = 0;              
398
399         // get our connection speed
400         Multi_connection_speed = multi_get_connection_speed();                  
401         
402         // initialize other stuff
403         multi_log_init();
404
405         // load up common multiplayer icons
406         multi_load_common_icons();      
407
408
409         // attempt to load up master tracker registry info (login and password)
410         Multi_tracker_id = -1;
411
412         // pxo login and password
413         ptr = os_config_read_string("PXO", "Login", NULL);
414
415         if (ptr) {
416                 SDL_strlcpy(Multi_tracker_login, ptr, SDL_arraysize(Multi_tracker_login));
417         } else {
418                 nprintf(("Network", "Error reading in PXO login data\n"));
419                 SDL_zero(Multi_tracker_login);
420         }
421
422         ptr = os_config_read_string("PXO", "Password", NULL);
423
424         if (ptr) {
425                 SDL_strlcpy(Multi_tracker_passwd, ptr, SDL_arraysize(Multi_tracker_passwd));
426         } else {
427                 nprintf(("Network", "Error reading PXO password\n"));
428                 SDL_zero(Multi_tracker_passwd);
429         }
430
431         // pxo squad name
432         ptr = os_config_read_string("PXO", "SquadName", NULL);
433
434         if (ptr) {
435                 SDL_strlcpy(Multi_tracker_squad_name, ptr, SDL_arraysize(Multi_tracker_squad_name));
436         } else {
437                 nprintf(("Network", "Error reading in PXO squad name\n"));
438                 SDL_zero(Multi_tracker_squad_name);
439         }
440 }
441
442 // this is an important function which re-initializes any variables required in multiplayer games. 
443 // Always make sure globals you add are re-initialized here !!!!
444 void multi_vars_init()
445 {
446         // initialize this variable right away.  Used in game_level_init for init'ing the player
447         Next_ship_signature = SHIP_SIG_MIN;             
448         Next_asteroid_signature = ASTEROID_SIG_MIN;
449         Next_non_perm_signature = NPERM_SIG_MIN;   
450         Next_debris_signature = DEBRIS_SIG_MIN;
451         
452         // server-client critical stuff
453         Multi_button_info_ok = 0;
454         Multi_button_info_id = 0;
455
456         // Ingame join stuff
457         Ingame_join_net_signature = -1;
458
459         // Netgame stuff
460         Netgame.game_state = NETGAME_STATE_FORMING;     
461
462         // team select stuff
463         Multi_ts_inited = 0;    
464
465         // load send stuff
466         Multi_mission_loaded = 0;   // client side              
467
468         // restricted game stuff
469         Multi_restr_query_timestamp = -1;       
470
471         // respawn stuff        
472         Multi_server_check_count = 0;
473
474         // reentrant variable
475         Multi_read_count = 0;
476
477         // unset the "have cd" var
478         // NOTE: we unset this here because we are going to be calling multi_common_verify_cd() 
479         //       immediately after this (in multi_level_init() to re-check the status)
480         Multi_has_cd = 0;
481
482         // current file checksum
483         Multi_current_file_checksum = 0;
484         Multi_current_file_length = -1;
485
486         Active_game_head = NULL;
487         Game_server_head = NULL;
488
489         // only the server should ever care about this
490         Multi_id_num = 0;
491 }
492
493 // -------------------------------------------------------------------------------------------------
494 //      multi_level_init() is called whenever the player starts a multiplayer game
495 //
496 //
497
498 void multi_level_init() 
499 {
500         int idx;
501
502         // NETLOG
503         ml_string(NOX("multi_level_init()"));
504
505         // initialize the Net_players array
506         for(idx=0;idx<MAX_PLAYERS;idx++) {
507                 // close all sockets down just for good measure
508                 psnet_rel_close_socket(&Net_players[idx].reliable_socket);
509
510                 memset(&Net_players[idx],0,sizeof(net_player));
511                 Net_players[idx].reliable_socket = INVALID_SOCKET;
512
513                 Net_players[idx].s_info.xfer_handle = -1;
514                 Net_players[idx].p_info.team = 0;
515         }
516
517         // initialize the Players array
518         for(idx=0;idx<MAX_PLAYERS;idx++){
519                 if(Player == &Players[idx]){
520                         continue;
521                 }
522                 memset(&Players[idx],0,sizeof(player));
523         }
524
525         multi_vars_init();      
526
527         // initialize the fake lag/loss system
528 #ifdef MULTI_USE_LAG
529         multi_lag_init();
530 #endif
531
532         // initialize the kick system
533         multi_kick_init();
534
535         // initialize all file xfer stuff
536         multi_xfer_init(multi_file_xfer_notify);
537
538         // close the chatbox (if one exists)
539         chatbox_close();        
540
541         // reset the data xfer system
542         multi_data_reset();
543
544         // initialize the voice system
545         multi_voice_init();
546
547         // intialize the pause system
548         multi_pause_reset();
549
550         // initialize endgame stuff
551         multi_endgame_init();
552
553         // initialize respawning
554         multi_respawn_init();
555
556         // initialize all netgame timestamps
557    multi_reset_timestamps();
558
559         // flush psnet sockets
560         psnet_flush();
561 }
562
563 // multi_check_listen() calls low level psnet routine to see if we have a connection from a client we
564 // should accept.
565 void multi_check_listen()
566 {
567         int i;
568         net_addr_t addr;
569         PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
570
571         // call psnet routine which calls select to see if we need to check for a connect from a client
572         // by passing addr, we are telling check_for_listen to do the accept and return who it was from in
573         // addr.  The
574         sock = psnet_rel_check_for_listen(&addr);
575         if ( sock != INVALID_SOCKET ) {
576                 // be sure that my address and the server address are set correctly.
577                 if ( !psnet_same(&Psnet_my_addr, &Net_player->p_info.addr) ){
578                         Net_player->p_info.addr = Psnet_my_addr;
579                 }
580
581                 if ( !psnet_same(&Psnet_my_addr, &(Netgame.server_addr)) ){
582                         Netgame.server_addr = Psnet_my_addr;
583                 }
584
585                 // the connection was accepted in check_for_listen.  Find the netplayer whose address we connected
586                 // with and assign the socket descriptor
587                 for (i = 0; i < MAX_PLAYERS; i++ ) {
588                         if ( (Net_players[i].flags & NETINFO_FLAG_CONNECTED) && (!memcmp(&(addr.addr), &(Net_players[i].p_info.addr.addr), IP_ADDRESS_LENGTH)) ) {
589                                 // mark this flag so we know he's "fully" connected
590                                 Net_players[i].flags |= NETINFO_FLAG_RELIABLE_CONNECTED;
591                                 Net_players[i].reliable_socket = sock;
592
593                                 // send player information to the joiner
594                                 send_accept_player_data( &Net_players[i], (Net_players[i].flags & NETINFO_FLAG_INGAME_JOIN)?1:0 );
595
596                                 // send a netgame update so the new client has all the necessary settings
597                                 send_netgame_update_packet();   
598
599                                 // if this is a team vs. team game, send an update
600                                 if(Netgame.type_flags & NG_TYPE_TEAM){
601                                         multi_team_send_update();
602                                 }
603
604                                 // NETLOG
605                                 ml_printf(NOX("Accepted TCP connection from %s"), Net_players[i].player == NULL ? NOX("Unknown") : Net_players[i].player->callsign);                            
606                                 break;
607                         }
608                 }
609
610                 // if we didn't find a player, close the socket
611                 if ( i == MAX_PLAYERS ) {
612                         nprintf(("Network", "Got accept on my listen socket, but unknown player.  Closing socket.\n"));
613                         psnet_rel_close_socket(&sock);
614                 }
615         }
616 }
617
618 // returns true is server hasn't been heard from in N seconds. false otherwise
619 int multi_client_server_dead()
620 {
621         fix this_time, last_time, max;
622
623         // get the last time we have heard from the server.  If greater than some default, then maybe
624         // display some icon on the HUD indicating slow network connection.  if greater than some higher
625         // max, stop simulating on the client side until we hear from the server again.
626         this_time = timer_get_fixed_seconds();
627         last_time = Netgame.server->last_heard_time;
628         // check for wrap!  must return 0
629         if ( last_time > this_time )
630                 return 0;
631
632         this_time -= last_time;
633
634         // if in mission, use the smaller timeout value.  Outside of mission, use a large one.
635         if ( MULTI_IN_MISSION ){
636                 max = MULTI_SERVER_MAX_TIMEOUT;
637         } else {
638                 max = MULTI_SERVER_MAX_TIMEOUT_LARGE;
639         }
640
641         if ( this_time > max){
642                 return 1;
643         } else {
644                 return 0;
645         }
646 }
647
648 void multi_process_incoming();          // prototype for function later in this module
649
650 // function to process network data in hopes of getting info back from server
651 int multi_client_wait_on_server()
652 {
653         int is_dead;
654
655         is_dead = multi_client_server_dead();
656
657         // if the server is back alive, tell our popup
658         if ( !is_dead ){
659                 return MULTI_SERVER_ALIVE;
660         }
661
662         // on release version -- keep popup active for 60 seconds, then bail
663 #ifdef NDEBUG
664         fix this_time = timer_get_fixed_seconds();
665         // if the timer wrapped:
666         if ( this_time < Multi_server_wait_start ) {
667                 Multi_server_wait_start = timer_get_fixed_seconds();
668                 return FALSE;
669         }
670         // check to see if timeout expired
671         this_time -= Multi_server_wait_start;
672         if ( this_time > MULTI_SERVER_WAIT_TIME ){
673                 return MULTI_SERVER_GONE;
674         }
675 #endif
676
677         return FALSE;
678 }
679
680 // function called by multiplayer clients to stop simulating when they have not heard from the server
681 // in a while.
682 void multi_client_check_server()
683 {
684         int rval;
685
686         SDL_assert( MULTIPLAYER_CLIENT );       
687
688         // this function can get called while in the popup code below.  So we include this check as a
689         // reentrancy check.
690         if ( Multi_server_check_count )
691                 return;
692
693         // make sure we have a valid server
694         if(Netgame.server == NULL){
695                 return;
696         }
697
698         Multi_server_check_count++;
699         if(multi_client_server_dead()){
700                 Netgame.flags |= NG_FLAG_SERVER_LOST;
701         } else {
702                 Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
703         }
704
705         if(Netgame.flags & NG_FLAG_SERVER_LOST) {
706                 if(!(Game_mode & GM_IN_MISSION) && !popup_active()){    
707                         // need to start a popup
708                         Multi_server_wait_start = timer_get_fixed_seconds();
709                         rval = popup_till_condition( multi_client_wait_on_server, XSTR("Cancel",641), XSTR("Contact lost with server.  Stopping simulation until contact reestablished.  Press Cancel to exit game.",642) );
710                         
711                         if ( !rval || (rval == MULTI_SERVER_GONE) ) {                           
712                                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);                                                              
713                         }
714                         Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
715                 }
716         }
717
718         Multi_server_check_count--;
719 }
720
721
722 // -------------------------------------------------------------------------------------------------
723 //      process_packet_normal() will determine what sort of packet it is, and send it to the appropriate spot.
724 //      Prelimiary verification of the magic number and checksum are done here.  
725 //
726
727 void process_packet_normal(ubyte* data, header *header_info)
728 {
729         switch ( data[0] ) {
730
731                 case JOIN:
732                         process_join_packet(data, header_info);
733                         break;
734
735                 case GAME_CHAT:
736                         process_game_chat_packet( data, header_info );
737                         break;
738
739                 case NOTIFY_NEW_PLAYER:
740                         process_new_player_packet(data, header_info);
741                         break;
742
743                 case HUD_MSG:
744                         process_hud_message(data, header_info);
745                         break;
746
747                 case MISSION_MESSAGE:
748                         process_mission_message_packet( data, header_info );
749                         break;
750
751                 case LEAVE_GAME:
752                         process_leave_game_packet(data, header_info);
753                         break;
754
755                 case GAME_QUERY:
756                         process_game_query(data, header_info);
757                         break;
758
759                 case GAME_ACTIVE:
760                         process_game_active_packet(data, header_info);
761                         break;
762
763                 case GAME_INFO:
764                         process_game_info_packet( data, header_info );
765                         break;          
766
767                 case SECONDARY_FIRED_AI:
768                         process_secondary_fired_packet(data, header_info, 0);
769                         break;          
770
771                 case SECONDARY_FIRED_PLR:
772                         process_secondary_fired_packet(data, header_info, 1);
773                         break;
774
775                 case COUNTERMEASURE_FIRED:
776                         process_countermeasure_fired_packet( data, header_info );
777                         break;          
778
779                 case FIRE_TURRET_WEAPON:
780                         process_turret_fired_packet( data, header_info );
781                         break;
782
783                 case GAME_UPDATE:
784                         process_netgame_update_packet( data, header_info );
785                         break;
786
787                 case UPDATE_DESCRIPT:
788                         process_netgame_descript_packet( data, header_info );
789                         break;
790
791                 case NETPLAYER_UPDATE:
792                         process_netplayer_update_packet( data, header_info );
793                         break;
794
795                 case ACCEPT :
796                         process_accept_packet(data, header_info);
797                         break;                          
798
799                 case OBJECT_UPDATE:
800                         multi_oo_process_update(data, header_info);
801                         break;
802
803                 case SHIP_KILL:
804                         process_ship_kill_packet( data, header_info );
805                         break;
806
807                 case WING_CREATE:
808                         process_wing_create_packet( data, header_info );
809                         break;
810                         
811                 case SHIP_CREATE:
812                         process_ship_create_packet( data, header_info );
813                         break;
814
815                 case SHIP_DEPART:
816                         process_ship_depart_packet( data, header_info );
817                         break;
818
819                 case MISSION_LOG_ENTRY:
820                         process_mission_log_packet( data, header_info );
821                         break;          
822
823                 case PING:
824                         process_ping_packet(data, header_info);
825                         break;
826
827                 case PONG:
828                         process_pong_packet(data, header_info);
829                         break;          
830
831                 case XFER_PACKET:
832                         SDL_assert(header_info->id >= 0);
833                         int np_index;
834                         PSNET_SOCKET_RELIABLE sock;
835                         sock = INVALID_SOCKET;
836
837                         // if I'm the server of the game, find out who this came from                   
838                         if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
839                                 np_index = find_player_id(header_info->id);
840                                 if(np_index >= 0){
841                                         sock = Net_players[np_index].reliable_socket;
842                                 }
843                         }
844                         // otherwise always use my own socket
845                         else if(Net_player != NULL){
846                                 sock = Net_player->reliable_socket;
847                         }
848                         
849                         header_info->bytes_processed = multi_xfer_process_packet(data + HEADER_LENGTH, sock) + HEADER_LENGTH;
850                         break;
851
852                 case MISSION_REQUEST:
853                         process_mission_request_packet(data,header_info);
854                         break;
855
856                 case MISSION_ITEM:
857                         process_mission_item_packet(data,header_info);
858                         break;          
859
860                 case MULTI_PAUSE_REQUEST:
861                         process_multi_pause_packet(data, header_info);
862                         break;          
863
864                 case INGAME_NAK:
865                         process_ingame_nak(data, header_info);
866                         break;
867
868                 case SHIPS_INGAME_PACKET:
869                         process_ingame_ships_packet(data, header_info);
870                         break;
871
872                 case WINGS_INGAME_PACKET:
873                         process_ingame_wings_packet(data, header_info);
874                         break;
875
876                 case MISSION_END:
877                         process_endgame_packet(data, header_info);
878                         break;
879                 
880                 case OBSERVER_UPDATE:
881                         process_observer_update_packet(data, header_info);
882                         break;
883
884                 case NETPLAYER_SLOTS_P:
885                         process_netplayer_slot_packet(data, header_info);
886                         break;
887
888                 case SHIP_STATUS_CHANGE:
889                         process_ship_status_packet(data, header_info);
890                         break;
891
892                 case PLAYER_ORDER_PACKET:
893                         process_player_order_packet(data, header_info);
894                         break;
895
896                 case INGAME_SHIP_UPDATE:
897                         process_ingame_ship_update_packet(data, header_info);
898                         break;
899
900                 case INGAME_SHIP_REQUEST:
901                         process_ingame_ship_request_packet(data, header_info);
902                         break;
903                 
904                 case FILE_SIG_INFO:
905                         process_file_sig_packet(data, header_info);
906                         break;
907
908                 case RESPAWN_NOTICE:
909                         multi_respawn_process_packet(data,header_info);                 
910                         break;
911
912                 case SUBSYSTEM_DESTROYED:
913                         process_subsystem_destroyed_packet( data, header_info );
914                         break;
915
916                 case LOAD_MISSION_NOW :
917                         process_netplayer_load_packet(data, header_info);
918                         break;
919
920                 case FILE_SIG_REQUEST :
921                         process_file_sig_request(data, header_info);
922                         break;
923
924                 case JUMP_INTO_GAME:
925                         process_jump_into_mission_packet(data, header_info);
926                         break;          
927
928                 case CLIENT_REPAIR_INFO:
929                         process_repair_info_packet(data,header_info);
930                         break;
931
932                 case MISSION_SYNC_DATA:
933                         process_mission_sync_packet(data,header_info);
934                         break;
935
936                 case STORE_MISSION_STATS:
937                         process_store_stats_packet(data, header_info);
938                         break;
939
940                 case DEBRIS_UPDATE:
941                         process_debris_update_packet(data, header_info);
942                         break;          
943
944                 case SHIP_WSTATE_CHANGE:
945                         process_ship_weapon_change( data, header_info );
946                         break;
947
948                 case WSS_UPDATE_PACKET:
949                         process_wss_update_packet(data, header_info);
950                         break;
951
952                 case WSS_REQUEST_PACKET:
953                         process_wss_request_packet( data, header_info );
954                         break;  
955
956                 case FIRING_INFO:
957                         process_firing_info_packet( data, header_info );
958                         break;          
959
960                 case CARGO_REVEALED:
961                         process_cargo_revealed_packet( data, header_info);
962                         break;          
963
964                 case SUBSYS_CARGO_REVEALED:
965                         process_subsystem_cargo_revealed_packet( data, header_info);
966                         break;          
967
968                 case MISSION_GOAL_INFO:
969                         process_mission_goal_info_packet(data, header_info);
970                         break;
971
972                 case KICK_PLAYER:
973                         process_player_kick_packet(data, header_info);
974                         break;
975
976                 case PLAYER_SETTINGS:
977                         process_player_settings_packet(data, header_info);
978                         break;
979
980                 case DENY:
981                         process_deny_packet(data, header_info);
982                         break;
983
984                 case POST_SYNC_DATA:
985                         process_post_sync_data_packet(data, header_info);
986                         break;
987
988                 case WSS_SLOTS_DATA:
989                         process_wss_slots_data_packet(data,header_info);
990                         break;
991
992                 case SHIELD_EXPLOSION:
993                         process_shield_explosion_packet( data, header_info );
994                         break;
995
996                 case PLAYER_STATS:
997                         process_player_stats_block_packet(data, header_info);
998                         break;
999
1000                 case SLOT_UPDATE:
1001                         process_pslot_update_packet(data,header_info);
1002                         break;
1003
1004                 case AI_INFO_UPDATE:
1005                         process_ai_info_update_packet( data, header_info );
1006                         break;          
1007
1008                 case CAMPAIGN_UPDATE :
1009                         multi_campaign_process_update(data,header_info);
1010                         break;
1011
1012                 case CAMPAIGN_UPDATE_INGAME:
1013                         multi_campaign_process_ingame_start(data,header_info);
1014                         break;
1015
1016                 case VOICE_PACKET :
1017                         multi_voice_process_packet(data,header_info);
1018                         break;
1019
1020                 case TEAM_UPDATE :
1021                         multi_team_process_packet(data,header_info);
1022                         break;
1023
1024                 case ASTEROID_INFO:
1025                         process_asteroid_info(data, header_info);
1026                         break;          
1027
1028                 case HOST_RESTR_QUERY:
1029                         process_host_restr_packet(data, header_info);
1030                         break;
1031
1032                 case OPTIONS_UPDATE:
1033                         multi_options_process_packet(data,header_info);
1034                         break;
1035
1036                 case SQUADMSG_PLAYER:
1037                         multi_msg_process_squadmsg_packet(data,header_info);
1038                         break;
1039
1040                 case NETGAME_END_ERROR:
1041                         process_netgame_end_error_packet(data,header_info);
1042                         break;
1043
1044                 case COUNTERMEASURE_SUCCESS:
1045                         process_countermeasure_success_packet( data, header_info );
1046                         break;
1047
1048                 case CLIENT_UPDATE:
1049                         process_client_update_packet(data, header_info);
1050                         break;
1051
1052                 case COUNTDOWN:
1053                         process_countdown_packet(data, header_info);
1054                         break;
1055
1056                 case DEBRIEF_INFO:
1057                         process_debrief_info( data, header_info );
1058                         break;
1059
1060                 case ACCEPT_PLAYER_DATA:
1061                         process_accept_player_data( data, header_info );
1062                         break;                          
1063
1064                 case HOMING_WEAPON_UPDATE:
1065                         process_homing_weapon_info( data, header_info );
1066                         break;          
1067
1068                 case EMP_EFFECT:
1069                         process_emp_effect(data, header_info);
1070                         break;
1071
1072                 case REINFORCEMENT_AVAIL:
1073                         process_reinforcement_avail( data, header_info );
1074                         break;
1075
1076                 case CHANGE_IFF:
1077                         process_change_iff_packet(data, header_info);
1078                         break;
1079
1080                 case PRIMARY_FIRED_NEW:
1081                         process_NEW_primary_fired_packet(data, header_info);
1082                         break;
1083
1084                 case COUNTERMEASURE_NEW:
1085                         process_NEW_countermeasure_fired_packet(data, header_info);
1086                         break;
1087
1088                 case BEAM_FIRED:
1089                         process_beam_fired_packet(data, header_info);
1090                         break;          
1091                         
1092                 case SW_STD_QUERY:
1093                         process_sw_query_packet(data, header_info);
1094                         break;
1095
1096                 case EVENT_UPDATE:
1097                         process_event_update_packet(data, header_info);
1098                         break;
1099
1100                 case OBJECT_UPDATE_NEW:                 
1101                         multi_oo_process_update(data, header_info);
1102                         break;
1103
1104                 case WEAPON_DET:
1105                         process_weapon_detonate_packet(data, header_info);
1106                         break;
1107
1108                 case FLAK_FIRED:
1109                         process_flak_fired_packet(data, header_info);
1110                         break;
1111
1112                 case NETPLAYER_PAIN:
1113                         process_player_pain_packet(data, header_info);
1114                         break;
1115
1116                 case LIGHTNING_PACKET:
1117                         process_lightning_packet(data, header_info);
1118                         break;
1119
1120                 case BYTES_SENT:
1121                         process_bytes_recvd_packet(data, header_info);
1122                         break;
1123
1124                 case TRANSFER_HOST:
1125                         process_host_captain_change_packet(data, header_info);
1126                         break;
1127
1128                 case SELF_DESTRUCT:
1129                         process_self_destruct_packet(data, header_info);
1130                         break;
1131
1132                 default:
1133                         nprintf(("Network", "Received packet with unknown type %d\n", data[0] ));
1134                         header_info->bytes_processed = 10000;
1135                         break;
1136
1137         } // end switch
1138 }
1139
1140
1141
1142 // Takes a bunch of messages, check them for validity,
1143 // and pass them to multi_process_data. 
1144 //  --------------------^
1145 // this should be process_packet() I think, or with the new code
1146 // process_tracker_packet() as defined in MultiTracker.[h,cpp]
1147 void multi_process_bigdata(ubyte *data, int len, net_addr_t *from_addr, int reliable)
1148 {
1149         int type, bytes_processed;
1150         int player_num;
1151         header header_info;
1152         ubyte *buf;     
1153
1154         // the only packets we will process from an unknown player are GAME_QUERY, GAME_INFO, JOIN, PING, PONG, ACCEPT, and GAME_ACTIVE packets
1155         player_num = find_player(from_addr);            
1156
1157         // find the player who sent the message and mark the last_heard time for this player
1158         // check to see if netplayer is null (it may be in cases such as getting lists of games from the tracker)
1159         if(player_num >= 0){
1160                 Net_players[player_num].last_heard_time = timer_get_fixed_seconds();
1161         }
1162
1163         // store fields that were passed along in the message
1164         // store header information that was captured from the network-layer header
1165         memcpy(header_info.addr, from_addr->addr, IP_ADDRESS_LENGTH);
1166         header_info.port = from_addr->port;     
1167         if(player_num >= 0){
1168                 header_info.id = Net_players[player_num].player_id;
1169         } else {
1170                 header_info.id = -1;
1171         }   
1172
1173         bytes_processed = 0;
1174         while( (bytes_processed >= 0) && (bytes_processed < len) )  {
1175
1176       buf = &(data[bytes_processed]);
1177
1178       type = buf[0];
1179
1180                 // if its coming from an unknown source, there are only certain packets we will actually process
1181                 if((player_num == -1) && !multi_is_valid_unknown_packet((ubyte)type)){
1182                         return ;
1183                 }               
1184
1185                 if ( (type<0) || (type > MAX_TYPE_ID )) {
1186                         nprintf( ("Network", "multi_process_bigdata: Invalid packet type %d!\n", type ));
1187                         return;
1188                 }               
1189
1190                 // perform any special processing checks here           
1191                 process_packet_normal(buf,&header_info);
1192                  
1193                 // MWA -- magic number was removed from header on 8/4/97.  Replaced with bytes_processed
1194                 // variable which gets stuffed whenever a packet is processed.
1195                 bytes_processed += header_info.bytes_processed;
1196         }
1197
1198         // if this is not reliable data and we have a valid player
1199         if(Net_player != NULL){
1200                 if(!MULTIPLAYER_MASTER && !reliable && (Game_mode & GM_IN_MISSION)){
1201                         Net_player->cl_bytes_recvd += len;
1202                 }
1203         }
1204 }
1205
1206 // process all reliable socket details
1207 void multi_process_reliable_details()
1208 {
1209         int idx;
1210         int sock_status;
1211
1212         // run reliable sockets
1213 #ifdef PSNET2
1214         psnet_rel_work();
1215 #endif
1216         
1217         // server operations
1218         if ( MULTIPLAYER_MASTER ){
1219                 // listen for new reliable socket connections
1220                 multi_check_listen();           
1221
1222                 // check for any broken sockets and delete any players
1223                 for(idx=0; idx<MAX_PLAYERS; idx++){
1224                         // players who _should_ be validly connected
1225                         if((idx != MY_NET_PLAYER_NUM) && MULTI_CONNECTED(Net_players[idx])){                            
1226                                 // if this guy's socket is broken or disconnected, kill him
1227                                 sock_status = psnet_rel_get_status(Net_players[idx].reliable_socket);
1228                                 if((sock_status == RNF_UNUSED) || (sock_status == RNF_BROKEN) || (sock_status == RNF_DISCONNECTED)){
1229                                         ml_string("Shutting down rel socket because of disconnect!");
1230                                         delete_player(idx);
1231                                 }
1232
1233                                 // if we're still waiting for this guy to connect on his reliable socket and he's timed out, boot him
1234                                 if(Net_players[idx].s_info.reliable_connect_time != -1){
1235                                         // if he's connected
1236                                         if(Net_players[idx].reliable_socket != INVALID_SOCKET){
1237                                                 Net_players[idx].s_info.reliable_connect_time = -1;
1238                                         } 
1239                                         // if he's timed out
1240                                         else if(((time(NULL) - Net_players[idx].s_info.reliable_connect_time) > MULTI_RELIABLE_CONNECT_WAIT) && (Net_players[idx].reliable_socket == INVALID_SOCKET)){
1241                                                 ml_string("Player timed out while connecting on reliable socket!");
1242                                                 delete_player(idx);
1243                                         }
1244                                 }                       
1245                         }
1246                 }
1247         }       
1248         // clients should detect broken sockets
1249         else {
1250                 extern unsigned int Serverconn;
1251                 if(Serverconn != 0xffffffff){
1252                         int status = psnet_rel_get_status(Serverconn);
1253                         if(status == RNF_BROKEN){
1254                                 mprintf(("CLIENT SOCKET DISCONNECTED"));
1255
1256                                 // quit the game
1257                                 if(!multi_endgame_ending()){
1258                                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);
1259                                 }
1260                         }
1261                 }
1262         }
1263 }
1264
1265 // multi_process_incoming reads incoming data off the unreliable and reliable ports and sends
1266 // the data to process_big_data
1267 void multi_process_incoming()
1268 {
1269         int size;
1270         ubyte *data, *savep;
1271         net_addr_t from_addr;   
1272
1273         SDL_assert( Multi_read_count < NUM_REENTRANT_LEVELS );
1274         savep = net_buffer[Multi_read_count];
1275
1276         Multi_read_count++;
1277
1278         data = savep;
1279
1280         // get the other net players data
1281         while( (size = psnet_get(data, &from_addr))>0 ) {
1282                 // ingame joiners will ignore UDP packets until they are have picked a ship and are in the mission
1283                 if( (Net_player->flags & NETINFO_FLAG_INGAME_JOIN) && (Net_player->state != NETPLAYER_STATE_INGAME_SHIP_SELECT) ){
1284                         //nprintf(("Network","Tossing UDP like a good little ingame joiner...\n"));
1285                 } 
1286                 // otherwise process incoming data normally
1287                 else {
1288                         multi_process_bigdata(data, size, &from_addr, 0);
1289                 }
1290         } // end while
1291
1292         // read reliable sockets for data
1293         data = savep;
1294         int idx;
1295
1296         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1297                 for (idx=0;idx<MAX_PLAYERS;idx++) {
1298                         if((Net_players[idx].flags & NETINFO_FLAG_CONNECTED) && (Net_player != NULL) && (Net_player->player_id != Net_players[idx].player_id)){
1299                                 while( (size = psnet_rel_get(Net_players[idx].reliable_socket, data, MAX_NET_BUFFER)) > 0){
1300                                         multi_process_bigdata(data, size, &Net_players[idx].p_info.addr, 1);
1301                                 }
1302                         }
1303                 }
1304         } else {
1305                 // if I'm not the master of the game, read reliable data from my connection with the server
1306                 if((Net_player->reliable_socket != INVALID_SOCKET) && (Net_player->reliable_socket != 0)){
1307                         while( (size = psnet_rel_get(Net_player->reliable_socket,data, MAX_NET_BUFFER)) > 0){                           
1308                                 multi_process_bigdata(data, size, &Netgame.server_addr, 1);
1309                         }
1310                 }
1311         }
1312                 
1313         Multi_read_count--;
1314 }
1315
1316 // -------------------------------------------------------------------------------------------------
1317 //      multi_do_frame() is called once per game loop do update all the multiplayer objects, and send
1318 // the player data to all the other net players.
1319 //
1320 //
1321
1322 int eye_tog = 1;
1323 DCF(eye_tog, "")
1324 {
1325         eye_tog = !eye_tog;
1326         if(eye_tog){
1327                 dc_printf("proper eye stuff on\n");
1328         } else {
1329                 dc_printf("proper eye stuff off\n");
1330         }
1331 }
1332
1333 void multi_do_frame()
1334 {       
1335         PSNET_TOP_LAYER_PROCESS();
1336
1337         // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1338         // function calls
1339         if((Net_player != NULL) && eye_tog){
1340                 player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1341         }
1342
1343         // send all buffered packets from the previous frame
1344         multi_io_send_buffered_packets();
1345
1346         // datarate tracking
1347         multi_rate_process();
1348
1349         // always process any pending endgame details
1350         multi_endgame_process();                
1351
1352         // process all reliable socket details, including :
1353         // 1.) Listening for new pending reliable connections (server)
1354         // 2.) Checking for broken sockets (server/client)
1355         // 3.) Checking for clients who haven't fully connected
1356         multi_process_reliable_details();       
1357
1358         // get the other net players data
1359         multi_process_incoming();               
1360
1361         // process object update datarate stuff (for clients and server both)
1362         multi_oo_rate_process();
1363
1364         // clients should check when last time they heard from sever was -- if too long, then
1365         // pause the simulation so wait for it to possibly come back
1366         if ( (MULTIPLAYER_CLIENT) && (Net_player->flags & NETINFO_FLAG_CONNECTED) ){
1367                 multi_client_check_server();
1368         }
1369
1370         // everybody pings all the time 
1371         if((Next_ping_time < 0) || ((time(NULL) - Next_ping_time) > PING_SEND_TIME) ){
1372                 if( (Net_player->flags & NETINFO_FLAG_AM_MASTER) ){
1373                         send_netplayer_update_packet();
1374                 }
1375                 
1376                 // ping everyone
1377                 multi_ping_send_all();
1378                 Next_ping_time = time(NULL);
1379         }       
1380         
1381         // if I am the master, and we are not yet actually playing the mission, send off netgame
1382         // status to all other players in the game.  If I am not the master of the game, and we
1383         // are not in the game, then send out my netplayer status to the host
1384         if ( (Net_player->flags & NETINFO_FLAG_CONNECTED) && !(Game_mode & GM_IN_MISSION)){     
1385                 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {                     
1386                         if ( (Netgame_send_time < 0) || ((time(NULL) - Netgame_send_time) > NETGAME_SEND_TIME) ) {
1387                                 send_netgame_update_packet();                           
1388                                 
1389                                 Netgame_send_time = time(NULL);
1390                         }               
1391                 } else {
1392                         if ( (State_send_time < 0) || ((time(NULL) - State_send_time) > STATE_SEND_TIME) ){
1393                                 // observers shouldn't send an update state packet
1394                                 if ( !(Net_player->flags & NETINFO_FLAG_OBSERVER) ){
1395                                         send_netplayer_update_packet();
1396                                 }                               
1397                                 
1398                                 State_send_time = time(NULL);
1399                         }
1400                 }
1401         }
1402         else if ( (Net_player->flags & NETINFO_FLAG_CONNECTED) && (Game_mode & GM_IN_MISSION) ) {       
1403                 // if I am connected and am in the mission, do things that need to be done on a regular basis
1404                 if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
1405                         if ( (Gameinfo_send_time < 0) || ((time(NULL) - Gameinfo_send_time) > GAMEINFO_SEND_TIME)){
1406                                 send_game_info_packet();
1407                                 
1408                                 Gameinfo_send_time = time(NULL);
1409                         }
1410                         
1411                         // for any potential respawns
1412                         multi_respawn_handle_invul_players();
1413                         multi_respawn_check_ai();
1414
1415                         // for any potential ingame joiners
1416                         multi_handle_ingame_joiners();
1417                 } else {
1418                         // the clients need to do some processing of stuff as well                      
1419                 }
1420         }
1421
1422         // check to see if we're waiting on confirmation for a restricted ingame join
1423         if(Multi_restr_query_timestamp != -1){
1424                 // if it has elapsed, unset the ingame join flag
1425                 if(timestamp_elapsed(Multi_restr_query_timestamp)){
1426                         Multi_restr_query_timestamp = -1;
1427                         Netgame.flags &= ~(NG_FLAG_INGAME_JOINING);             
1428                 }       
1429         }
1430
1431         // while in the mission, send my PlayerControls to the host so that he can process
1432         // my movement
1433         if ( Game_mode & GM_IN_MISSION ) {
1434                 // tickers
1435                 extern void oo_update_time();
1436                 oo_update_time();
1437
1438
1439                 if ( !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){                                    
1440                         if(Net_player->flags & NETINFO_FLAG_OBSERVER){
1441                                 // if the rate limiting system says its ok
1442                                 if(multi_oo_cirate_can_send()){
1443                                         // send my observer position/object update
1444                                         send_observer_update_packet();
1445                                 }
1446                         } else if ( !(Player_ship->flags & SF_DEPARTING ) ){                            
1447                                 // if the rate limiting system says its ok
1448                                 if(multi_oo_cirate_can_send()){
1449                                         // use the new method
1450                                         multi_oo_send_control_info();
1451                                 }                               
1452                         }
1453
1454                         // bytes received info
1455                         if( (Next_bytes_time < 0) || ((time(NULL) - Next_bytes_time) > BYTES_SENT_TIME) ){
1456                                 if(Net_player != NULL){
1457                                         send_bytes_recvd_packet(Net_player);
1458
1459                                         // reset bytes recvd
1460                                         Net_player->cl_bytes_recvd = 0;
1461                                 }
1462
1463                                 // reset timestamp
1464                                 Next_bytes_time = time(NULL);                           
1465                         }
1466                 } else {                        
1467                         // sending new objects from here is dependent on having objects only created after
1468                         // the game is done moving the objects.  I think that I can enforce this.                               
1469                         multi_oo_process();                     
1470
1471                         // evaluate whether the time limit has been reached or max kills has been reached
1472                         // Commented out by Sandeep 4/12/98, was causing problems with testing.
1473                         if( ((f2fl(Netgame.options.mission_time_limit) > 0.0f) && (Missiontime > Netgame.options.mission_time_limit)) ||
1474                                  multi_kill_limit_reached() ) {
1475
1476                                 // make sure we don't do this more than once
1477                                 if(Netgame.game_state == NETGAME_STATE_IN_MISSION){                             
1478                                         multi_handle_end_mission_request();                                                                     
1479                                 }
1480                         }                       
1481                 }                       
1482         }
1483
1484         // periodically send a client update packet to all clients
1485         if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1486                 int idx;
1487                 for(idx=0;idx<MAX_PLAYERS;idx++){
1488                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){
1489                                 if((Multi_client_update_times[idx] < 0) || timestamp_elapsed_safe(Multi_client_update_times[idx], 1000)){
1490                                         
1491                                         send_client_update_packet(&Net_players[idx]);
1492                                         
1493                                         Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1494                                 }
1495                         }
1496                 }
1497         }       
1498
1499         // process any kicked player details
1500         multi_kick_process();
1501
1502         // do any file xfer details
1503         multi_xfer_do();
1504
1505         // process any player data details (wav files, pilot pics, etc)
1506         multi_data_do();
1507
1508         // do any voice details
1509         multi_voice_process();
1510
1511         // process any player messaging details
1512         multi_msg_process();            
1513
1514         // process any tracker messages
1515         multi_fs_tracker_process();
1516
1517         // if on the standalone, do any gui stuff
1518         if(Game_mode & GM_STANDALONE_SERVER){
1519                 std_do_gui_frame();
1520         }       
1521
1522         // dogfight nonstandalone players should recalc the escort list every frame
1523         if(!(Game_mode & GM_STANDALONE_SERVER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && MULTI_IN_MISSION){
1524                 hud_setup_escort_list(0);
1525         }
1526 }
1527
1528 // -------------------------------------------------------------------------------------------------
1529 //      multi_pause_do_frame() is called once per game loop do update all the multiplayer objects, and send
1530 // the player data to all the other net players when the multiplayer game is paused. It only will do 
1531 // checking for a few specialized packets (MULTI_UNPAUSE, etc)
1532 //
1533
1534 void multi_pause_do_frame()
1535 {
1536         PSNET_TOP_LAYER_PROCESS();
1537
1538         // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1539         // function calls
1540         // if((Net_player != NULL) && eye_tog){
1541                 // player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1542         // }
1543
1544         // send all buffered packets from the previous frame
1545         multi_io_send_buffered_packets();
1546
1547         // always process any pending endgame details
1548         multi_endgame_process();                
1549
1550         // process all reliable socket details, including :
1551         // 1.) Listening for new pending reliable connections (server)
1552         // 2.) Checking for broken sockets (server/client)
1553         // 3.) Checking for clients who haven't fully connected
1554         multi_process_reliable_details();       
1555
1556         // these timestamps and handlers shoul be evaluated in the pause state
1557         if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
1558                 if ( (Gameinfo_send_time < 0) || ((time(NULL) - Gameinfo_send_time) > GAMEINFO_SEND_TIME) ){
1559                         send_game_info_packet();
1560                         
1561                         Gameinfo_send_time = time(NULL);
1562                 }                               
1563         }
1564
1565         // everybody pings all the time
1566         if((Next_ping_time < 0) || ((time(NULL) - Next_ping_time) > PING_SEND_TIME) ){
1567                 multi_ping_send_all();
1568                 
1569                 Next_ping_time = time(NULL);
1570         }
1571
1572         // periodically send a client update packet to all clients
1573         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1574                 int idx;
1575
1576                 for(idx=0;idx<MAX_PLAYERS;idx++){
1577                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx])){                     
1578                                 if((Multi_client_update_times[idx] < 0) || timestamp_elapsed_safe(Multi_client_update_times[idx], 1000)){
1579                                         
1580                                         send_client_update_packet(&Net_players[idx]);
1581                                         
1582                                         Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1583                                 }
1584                         }                               
1585                 }
1586
1587                 // for any potential ingame joiners
1588                 multi_handle_ingame_joiners();
1589         }       
1590
1591         // do any file xfer details
1592         multi_xfer_do();
1593
1594         // process any player data details (wav files, pilot pics, etc)
1595         multi_data_do();
1596
1597         // get the other net players data
1598         multi_process_incoming();       
1599
1600         // do any voice details
1601         multi_voice_process();
1602
1603         // process any player messaging details
1604         multi_msg_process();
1605
1606         // process any kicked player details
1607         multi_kick_process();
1608
1609         // process any pending endgame details
1610         multi_endgame_process();
1611
1612         // process object update stuff (for clients and server both)
1613         if(MULTIPLAYER_MASTER){
1614                 multi_oo_process();
1615         }
1616
1617         // if on the standalone, do any gui stuff
1618         if(Game_mode & GM_STANDALONE_SERVER){
1619                 std_do_gui_frame();
1620         }
1621 }
1622
1623
1624 // --------------------------------------------------------------------------------
1625 // standalone_main_init()  the standalone equivalent of the main menu
1626 //
1627
1628 extern int sock_inited;
1629 float frame_time = (float)1.0/(float)30.0;
1630
1631 void standalone_main_init()
1632 {
1633    std_debug_set_standalone_state_string("Main Init");   
1634
1635         Game_mode = (GM_STANDALONE_SERVER | GM_MULTIPLAYER);    
1636
1637         // NETLOG
1638         ml_string(NOX("Standalone server initializing"));
1639
1640         // read in config file
1641         // multi_options_read_config();   
1642
1643         // if we failed to startup on our desired protocol, fail        
1644         if ( !Tcp_active ) {
1645                 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", XSTR("You have selected TCP/IP for multiplayer Freespace, but the TCP/IP protocol was not detected on your machine.", 362), NULL);
1646                 exit(1);
1647         }
1648
1649         // set the protocol
1650         Multi_options_g.protocol = NET_TCP;
1651         psnet_use_protocol(Multi_options_g.protocol);   
1652
1653         // clear out the Netgame structure and start filling in the values
1654         // NOTE : these values are not incredibly important since they will be overwritten by the host when he joins
1655         memset( &Netgame, 0, sizeof(Netgame) ); 
1656         Netgame.game_state = NETGAME_STATE_FORMING;             // game is currently starting up
1657         Netgame.security = 0;
1658         Netgame.server_addr = Psnet_my_addr;
1659                 
1660         // reinitialize all systems     
1661         multi_level_init();     
1662
1663         // intialize endgame stuff
1664         multi_endgame_init();
1665
1666         // clear the file xfer system
1667         multi_xfer_reset();
1668         multi_xfer_force_dir(CF_TYPE_MULTI_CACHE);
1669
1670         // reset timer
1671         timestamp_reset();
1672
1673         // setup the netplayer for the standalone
1674         Net_player = &Net_players[0];   
1675         Net_player->tracker_player_id = -1;
1676         Net_player->flags |= (NETINFO_FLAG_AM_MASTER | NETINFO_FLAG_CONNECTED | NETINFO_FLAG_DO_NETWORKING | NETINFO_FLAG_MISSION_OK);
1677         Net_player->state = NETPLAYER_STATE_WAITING;
1678         Net_player->player = Player;
1679         SDL_strlcpy(Player->callsign, "server", SDL_arraysize(Player->callsign));
1680         Net_player->p_info.addr = Psnet_my_addr;
1681         Net_player->s_info.xfer_handle = -1;    
1682         Net_player->player_id = multi_get_new_id();     
1683         Netgame.server = Net_player; 
1684
1685         // maybe flag the game as having a hacked ships.tbl
1686         if(!Game_ships_tbl_valid){
1687                 Netgame.flags |= NG_FLAG_HACKED_SHIPS_TBL;
1688         }
1689         // maybe flag the game as having a hacked weapons.tbl
1690         if(!Game_weapons_tbl_valid){
1691                 Netgame.flags |= NG_FLAG_HACKED_WEAPONS_TBL;
1692         }
1693
1694         // hacked data
1695         if(game_hacked_data()){
1696                 Net_player->flags |= NETINFO_FLAG_HAXOR;
1697         }
1698
1699         // setup debug flags
1700         Netgame.debug_flags = 0;
1701         /*
1702         if(!Cmdline_server_firing){
1703                 Netgame.debug_flags |= NETD_FLAG_CLIENT_FIRING;
1704         }
1705         if(!Cmdline_client_dodamage){
1706                 Netgame.debug_flags |= NETD_FLAG_CLIENT_NODAMAGE;
1707         }
1708         */
1709
1710         // setup the default game name for the standalone
1711         std_connect_set_gamename(NULL);
1712
1713         // set netgame default options
1714         multi_options_set_netgame_defaults(&Netgame.options);
1715
1716         // set local netplayer default options
1717         multi_options_set_local_defaults(&Net_player->p_info.options);
1718
1719         // set our object update level from the standalone default      
1720         Net_player->p_info.options.obj_update_level = Multi_options_g.std_datarate;
1721         switch(Net_player->p_info.options.obj_update_level){
1722         case OBJ_UPDATE_LOW:
1723                 nprintf(("Network","STANDALONE USING LOW UPDATES\n"));
1724                 break;
1725         case OBJ_UPDATE_MEDIUM:
1726                 nprintf(("Network","STANDALONE USING MEDIUM UPDATES\n"));
1727                 break;
1728         case OBJ_UPDATE_HIGH:
1729                 nprintf(("Network","STANDALONE USING HIGH UPDATE\n"));
1730                 break;
1731         case OBJ_UPDATE_LAN:
1732                 nprintf(("Network","STANDALONE USING LAN UPDATE\n"));
1733                 break;
1734         }
1735         
1736         // clear out various things
1737         psnet_flush();
1738         game_flush();
1739         ship_init();
1740
1741         // login to game tracker
1742         std_tracker_login();
1743
1744         std_debug_set_standalone_state_string("Main Do");
1745         std_set_standalone_fps((float)0);
1746         std_multi_set_standalone_missiontime((float)0);
1747
1748         // load my missions and campaigns
1749         multi_create_list_load_missions();
1750         multi_create_list_load_campaigns();
1751
1752         SDL_zero(The_mission);
1753
1754         // if this is a tracker game, validate missions
1755         if(MULTI_IS_TRACKER_GAME){
1756                 multi_update_valid_missions();
1757         }
1758 }
1759
1760
1761 // --------------------------------------------------------------------------------
1762 // standalone_main_do()
1763 //
1764
1765 // DESCRIPTION : the standalone server will wait in this state until the host of the game 
1766 //               is "Waiting". That is, his state==NETPLAYER_STATE_WAITING, and he has finished
1767 //               doing everything and wants to play the game. Once this happens, we will jump
1768 //               into GS_STATE_MULTI_SERVER_WAIT
1769
1770 void standalone_main_do()
1771 {
1772         // kind of a do-nothing spin state.
1773         // The standalone will eventually move into the GS_STATE_MULTI_MISSION_SYNC state when a host connects and
1774         // attempts to start a game
1775 }
1776
1777 // --------------------------------------------------------------------------------
1778 // standalone_main_close()
1779 //
1780
1781 void standalone_main_close()
1782 {
1783         std_debug_set_standalone_state_string("Main Close");
1784
1785         // disconnect game from tracker
1786         multi_fs_tracker_logout();
1787
1788 }
1789
1790 void multi_standalone_reset_all()
1791 {       
1792         int idx;
1793
1794         // NETLOG
1795         ml_string(NOX("Standalone resetting"));
1796         
1797         // shut all game stuff down
1798         game_level_close();
1799
1800         // reinitialize the gui
1801         std_reset_standalone_gui();     
1802
1803         // close down all sockets
1804         for(idx=0;idx<MAX_PLAYERS;idx++){
1805
1806                 // 6/25/98 -- MWA -- call delete_player here to remove the player.  This closes down the socket
1807                 // and marks the player as not connected anymore.  It is probably cleaner to do this.
1808                 if ( &Net_players[idx] != Net_player ) {
1809                         delete_player( idx );
1810                 }               
1811         }
1812                 
1813         // make sure we go to the proper state. 
1814         if(gameseq_get_state() == GS_STATE_STANDALONE_MAIN){
1815                 standalone_main_init();
1816         }
1817         gameseq_post_event(GS_EVENT_STANDALONE_MAIN);   
1818 }
1819
1820 // --------------------------------------------------------------------------------
1821 // multi_server_wait_init()  do stuff like setting the status bits correctly
1822 //
1823
1824 void multi_standalone_wait_init()
1825 {       
1826         std_debug_set_standalone_state_string("Wait Do");
1827         std_multi_add_goals();   // fill in the goals for the mission into the tree view
1828         multi_reset_timestamps();
1829
1830         // create the bogus standalone object
1831         multi_create_standalone_object();
1832 }
1833
1834
1835 // --------------------------------------------------------------------------------
1836 // multi_server_wait_do_frame() wait for everyone to log in or the host to send commands
1837 // 
1838
1839 // DESCRIPTION : we will be in this state once the host of the game is waiting for everyone
1840 //               to be finished and ready to go, at which point, we will will tell everyone
1841 //               to enter the game, and we will start simulating ourselves. Note that most of
1842 //               this code is lifted from multi_wait_do_frame()
1843 void multi_standalone_wait_do()
1844 {
1845 }
1846
1847 // --------------------------------------------------------------------------------
1848 // multi_server_wait_close() cleanup
1849 //
1850
1851 void multi_standalone_wait_close()
1852 {
1853         std_debug_set_standalone_state_string("Wait Close / Game Play");
1854         
1855         // all players should reset sequencing
1856         int idx;
1857         for(idx=0;idx<MAX_PLAYERS;idx++){
1858                 if(Net_player->flags & NETINFO_FLAG_CONNECTED){
1859                         Net_players[idx].client_cinfo_seq = 0;
1860                         Net_players[idx].client_server_seq = 0; 
1861                 }
1862         }
1863 }
1864
1865
1866 // this is an artificial state which will push the standalone into the main state without it having to go through 
1867 // the init function (which would disconnect everyone and generally just screw things up)
1868 // it will also eventually do tracker stats update
1869 extern int Multi_debrief_server_framecount;
1870 void multi_standalone_postgame_init()   
1871 {
1872         std_debug_set_standalone_state_string("Postgame / Send Stats");
1873
1874         // NETLOG
1875         ml_string(NOX("Standlone entering postgame"));
1876
1877         mission_goal_fail_incomplete();
1878
1879         // handle campaign stuff
1880         if ( Game_mode & GM_CAMPAIGN_MODE ) {
1881                 // MUST store goals and events first - may be used to evaluate next mission
1882                 // store goals and events
1883                 mission_campaign_store_goals_and_events();
1884
1885                 // evaluate next mission
1886                 mission_campaign_eval_next_mission();
1887         }       
1888
1889         // always set my state to be "DEBRIEF_ACCEPT"
1890         Net_player->state = NETPLAYER_STATE_DEBRIEF_ACCEPT;     
1891
1892         // mark stats as not being stored yet
1893         Netgame.flags &= ~(NG_FLAG_STORED_MT_STATS);
1894
1895         Multi_debrief_server_framecount = 0;
1896
1897         // reset network timestamps
1898         multi_reset_timestamps();
1899 }
1900
1901 void multi_standalone_postgame_do()
1902 {
1903         // wait until everyone is in the debriefing
1904         if((Netgame.game_state != NETGAME_STATE_DEBRIEF) && multi_netplayer_state_check(NETPLAYER_STATE_DEBRIEF, 1)){           
1905                 Netgame.game_state = NETGAME_STATE_DEBRIEF;
1906                 send_netgame_update_packet();
1907                 debrief_multi_server_stuff();
1908         }
1909         
1910         // process server debriefing details
1911         if(Netgame.game_state == NETGAME_STATE_DEBRIEF){
1912                 multi_debrief_server_process();
1913         }
1914 }
1915
1916 void multi_standalone_postgame_close()
1917 {
1918         // maybe store stats on tracker
1919         if ( MULTI_IS_TRACKER_GAME && !(Netgame.flags & NG_FLAG_STORED_MT_STATS) ) {
1920                 if (multi_debrief_stats_accept_code() != 0) {
1921                         int stats_saved = multi_fs_std_tracker_store_stats();
1922
1923                         if (stats_saved) {
1924                                 Netgame.flags |= NG_FLAG_STORED_MT_STATS;
1925                                 send_netgame_update_packet();
1926                         } else {
1927                                 send_store_stats_packet(0);
1928                         }
1929
1930 #ifndef MAKE_FS1
1931                         if (Netgame.type_flags & NG_TYPE_SW) {
1932                                 multi_sw_report(stats_saved);
1933                         }
1934 #endif
1935                 }
1936         }
1937 }
1938
1939 void multi_reset_timestamps()
1940 {
1941         int i;
1942
1943         for ( i = 0 ; i < MAX_PLAYERS; i++ ){
1944                 Multi_client_update_times[i] = -1;
1945         }
1946         Netgame_send_time = -1;
1947         Gameinfo_send_time = -1;        
1948         Next_ping_time = -1;
1949         State_send_time = -1;
1950         Next_bytes_time = -1;
1951
1952         chatbox_reset_timestamps();
1953
1954         // do for all players so that ingame joiners work properly.
1955         for (i = 0; i < MAX_PLAYERS; i++ ) {
1956                 Players[i].update_dumbfire_time = timestamp(0);
1957                 Players[i].update_lock_time = timestamp(0);
1958
1959                 Net_players[i].s_info.voice_token_timestamp = -1;
1960         }
1961
1962         // reset standalone gui timestamps (these are not game critical, so there is not much danger)
1963         std_reset_timestamps();
1964
1965         // initialize all object update timestamps
1966         multi_oo_gameplay_init();
1967 }
1968
1969 // netgame debug flags for debug console stuff
1970 DCF(netd, "change/list netgame debug flags")
1971 {
1972         dc_get_arg(ARG_INT);
1973         
1974         // if we got an integer, and we're the server, change flags
1975         if((Dc_arg_type & ARG_INT) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Dc_arg_int <= 7)){
1976                 Netgame.debug_flags ^= (1<<Dc_arg_int);
1977         }
1978
1979         // display network flags
1980         dc_printf("BITS\n");
1981         // dc_printf("1 - Client side firing (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING ? 1 : 0);
1982         // dc_printf("2 - Client nodamage (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE ? 1 : 0);
1983 }
1984
1985 // display any multiplayer/networking information here
1986 void multi_display_netinfo()
1987 {
1988         int sx = gr_screen.max_w - 200;
1989         int sy = 20;
1990         int idx;
1991
1992         // not multiplayer
1993         if(!(Game_mode & GM_MULTIPLAYER)){
1994                 return;
1995         }
1996
1997         gr_set_color_fast(&Color_normal);
1998
1999         // server or client
2000         if(MULTIPLAYER_MASTER){
2001                 gr_string(sx, sy, "SERVER"); sy += 10;
2002
2003                 for(idx=0; idx<MAX_PLAYERS; idx++){
2004                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx]) && (Net_players[idx].player != NULL)){
2005                                 if(Net_players[idx].sv_last_pl < 0){
2006                                         gr_printf(sx, sy, "%s : %d, %d pl", Net_players[idx].player->callsign, Net_players[idx].sv_bytes_sent, 0); sy += 10;
2007                                 } else {
2008                                         gr_printf(sx, sy, "%s : %d, %d pl", Net_players[idx].player->callsign, Net_players[idx].sv_bytes_sent, Net_players[idx].sv_last_pl); sy += 10;
2009                                 }
2010                         }
2011                 }
2012         } else {
2013                 gr_string(sx, sy, "CLIENT"); sy += 10;
2014
2015                 // display PL
2016                 if(Net_player != NULL){
2017                         if(Net_player->cl_last_pl < 0){
2018                                 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, 0);// sy += 10;
2019                         } else {
2020                                 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, Net_player->cl_last_pl);// sy += 10;
2021                         }
2022                 }
2023         }
2024 }