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