2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Network/Multi.cpp $
15 * C file that contains high-level multiplayer functions
18 * Revision 1.5 2002/06/09 04:41:23 relnev
19 * added copyright header
21 * Revision 1.4 2002/05/27 00:40:47 theoddone33
22 * Fix net_addr vs net_addr_t
24 * Revision 1.3 2002/05/26 20:22:48 theoddone33
25 * Most of network/ works
27 * Revision 1.2 2002/05/07 03:16:47 theoddone33
28 * The Great Newline Fix
30 * Revision 1.1.1.1 2002/05/03 03:28:10 root
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
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
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.
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.
51 * 43 8/19/99 10:59a Dave
52 * Packet loss detection.
54 * 42 8/16/99 4:05p Dave
55 * Big honking checkin.
57 * 41 8/06/99 12:34a Dave
58 * Be more careful about resetting timestamps.
60 * 40 8/04/99 2:24a Dave
61 * Fixed escort gauge ordering for dogfight.
63 * 39 7/26/99 5:50p Dave
64 * Revised ingame join. Better? We'll see....
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.
70 * 37 7/06/99 4:24p Dave
71 * Mid-level checkin. Starting on some potentially cool multiplayer
74 * 36 7/03/99 5:50p Dave
75 * Make rotated bitmaps draw properly in padlock views.
77 * 35 6/21/99 7:24p Dave
78 * netplayer pain packet. Added type E unmoving beams.
80 * 34 6/07/99 9:51p Dave
81 * Consolidated all multiplayer ports into one.
83 * 33 6/04/99 9:52a Dave
84 * Fixed some rendering problems.
86 * 32 5/22/99 6:05p Dave
87 * Fixed a few localization # problems.
89 * 31 5/22/99 5:35p Dave
90 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
92 * 30 5/14/99 1:59p Andsager
93 * Multiplayer message for subsystem cargo revealed.
95 * 29 4/29/99 2:29p Dave
96 * Made flak work much better in multiplayer.
98 * 28 4/28/99 11:13p Dave
99 * Temporary checkin of artillery code.
101 * 27 4/25/99 7:43p Dave
102 * Misc small bug fixes. Made sun draw properly.
104 * 26 4/25/99 3:02p Dave
105 * Build defines for the E3 build.
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.
111 * 24 4/09/99 2:21p Dave
112 * Multiplayer beta stuff. CD checking.
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.
118 * 23 3/11/99 5:53p Dave
119 * More network optimization. Spliced in Dell OEM planet bitmap crap.
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.
125 * 21 3/09/99 6:24p Dave
126 * More work on object update revamping. Identified several sources of
127 * unnecessary bandwidth.
129 * 20 3/08/99 7:03p Dave
130 * First run of new object update system. Looks very promising.
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)
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.
140 * 17 2/23/99 2:29p Dave
141 * First run of oldschool dogfight mode.
143 * 16 2/19/99 2:55p Dave
144 * Temporary checking to report the winner of a squad war match.
146 * 15 2/17/99 2:10p Dave
147 * First full run of squad war. All freespace and tracker side stuff
150 * 14 2/12/99 6:16p Dave
151 * Pre-mission Squad War code is 95% done.
153 * 13 2/11/99 3:08p Dave
154 * PXO refresh button. Very preliminary squad war support.
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 :(
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.
165 * 10 12/14/98 12:13p Dave
166 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
169 * 9 12/03/98 5:22p Dave
170 * Ported over Freespace 1 multiplayer ships.tbl and weapons.tbl
173 * 8 11/19/98 4:19p Dave
174 * Put IPX sockets back in psnet. Consolidated all multiplayer config
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.
181 * 6 11/17/98 11:12a Dave
182 * Removed player identification by address. Now assign explicit id #'s.
184 * 5 11/12/98 12:13a Dave
185 * Tidied code up for multiplayer test. Put in network support for flak
193 #include <winsock2.h>
198 #include "multiutil.h"
199 #include "multimsgs.h"
201 #include "linklist.h"
207 #include "missionload.h"
208 #include "missionparse.h"
209 #include "missionshipchoice.h"
210 #include "gamesequence.h"
211 #include "freespace.h"
216 #include "stand_server.h"
217 #include "multi_xfer.h"
220 #include "multilag.h"
221 #include "multiutil.h"
222 #include "multi_ingame.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"
249 // ----------------------------------------------------------------------------------------
250 // Basic module scope 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
267 #define CULL_ZOMBIE_TIME 1000 // zombies are checked for at this interval (in milliseconds)
269 // object update stuff
270 #define SEND_POS_INTERVAL 30 // min time in milliseconds between sending position updates
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
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
283 #define DISCONNECT_TIMEOUT (F1_0 * 10) // 10 seconds to timeout someone who cannot connnect
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
288 // update times for clients ships based on object update level
289 #define MULTI_CLIENT_UPDATE_TIME 333
291 int Multi_display_netinfo = 1;
293 // ----------------------------------------------------------------------------------------
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
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
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
315 // low level networking vars
316 const int HEADER_LENGTH = 1; // 1 byte (packet type)
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
327 // permanent server list
328 server_item* Game_server_head; // list of permanent game servers to be querying
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
338 // how often each player gets updated
339 int Multi_client_update_times[MAX_PLAYERS]; // client update packet timestamp
341 // local network buffer data
342 static ubyte net_buffer[NUM_REENTRANT_LEVELS][MAX_NET_BUFFER];
343 static ubyte Multi_read_count;
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;
350 SDL_COMPILE_TIME_ASSERT(addr, sizeof(Multi_restr_addr.addr) == IP_ADDRESS_LENGTH);
352 static fix Multi_server_wait_start; // variable to hold start time when waiting to reestablish with server
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];
361 // current file checksum
362 ushort Multi_current_file_checksum = 0;
363 int Multi_current_file_length = -1;
366 // -------------------------------------------------------------------------------------------------
367 // multi_init() is called only once, at game start-up. Get player address + port, initialize the
368 // network players list.
375 const char *ptr = NULL;
377 // read in config file
378 multi_options_read_config();
380 SDL_assert( Net_player == NULL );
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;
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;
399 // get our connection speed
400 Multi_connection_speed = multi_get_connection_speed();
402 // initialize other stuff
405 // load up common multiplayer icons
406 multi_load_common_icons();
409 // attempt to load up master tracker registry info (login and password)
410 Multi_tracker_id = -1;
412 // pxo login and password
413 ptr = os_config_read_string("PXO", "Login", NULL);
416 SDL_strlcpy(Multi_tracker_login, ptr, SDL_arraysize(Multi_tracker_login));
418 nprintf(("Network", "Error reading in PXO login data\n"));
419 SDL_zero(Multi_tracker_login);
422 ptr = os_config_read_string("PXO", "Password", NULL);
425 SDL_strlcpy(Multi_tracker_passwd, ptr, SDL_arraysize(Multi_tracker_passwd));
427 nprintf(("Network", "Error reading PXO password\n"));
428 SDL_zero(Multi_tracker_passwd);
432 ptr = os_config_read_string("PXO", "SquadName", NULL);
435 SDL_strlcpy(Multi_tracker_squad_name, ptr, SDL_arraysize(Multi_tracker_squad_name));
437 nprintf(("Network", "Error reading in PXO squad name\n"));
438 SDL_zero(Multi_tracker_squad_name);
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()
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;
452 // server-client critical stuff
453 Multi_button_info_ok = 0;
454 Multi_button_info_id = 0;
457 Ingame_join_net_signature = -1;
460 Netgame.game_state = NETGAME_STATE_FORMING;
466 Multi_mission_loaded = 0; // client side
468 // restricted game stuff
469 Multi_restr_query_timestamp = -1;
472 Multi_server_check_count = 0;
474 // reentrant variable
475 Multi_read_count = 0;
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)
482 // current file checksum
483 Multi_current_file_checksum = 0;
484 Multi_current_file_length = -1;
486 Active_game_head = NULL;
487 Game_server_head = NULL;
489 // only the server should ever care about this
493 // -------------------------------------------------------------------------------------------------
494 // multi_level_init() is called whenever the player starts a multiplayer game
498 void multi_level_init()
503 ml_string(NOX("multi_level_init()"));
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);
510 memset(&Net_players[idx],0,sizeof(net_player));
511 Net_players[idx].reliable_socket = INVALID_SOCKET;
513 Net_players[idx].s_info.xfer_handle = -1;
514 Net_players[idx].p_info.team = 0;
517 // initialize the Players array
518 for(idx=0;idx<MAX_PLAYERS;idx++){
519 if(Player == &Players[idx]){
522 memset(&Players[idx],0,sizeof(player));
527 // initialize the fake lag/loss system
532 // initialize the kick system
535 // initialize all file xfer stuff
536 multi_xfer_init(multi_file_xfer_notify);
538 // close the chatbox (if one exists)
541 // reset the data xfer system
544 // initialize the voice system
547 // intialize the pause system
550 // initialize endgame stuff
551 multi_endgame_init();
553 // initialize respawning
554 multi_respawn_init();
556 // initialize all netgame timestamps
557 multi_reset_timestamps();
559 // flush psnet sockets
563 // multi_check_listen() calls low level psnet routine to see if we have a connection from a client we
565 void multi_check_listen()
569 PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
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
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;
581 if ( !psnet_same(&Psnet_my_addr, &(Netgame.server_addr)) ){
582 Netgame.server_addr = Psnet_my_addr;
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;
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 );
596 // send a netgame update so the new client has all the necessary settings
597 send_netgame_update_packet();
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();
605 ml_printf(NOX("Accepted TCP connection from %s"), Net_players[i].player == NULL ? NOX("Unknown") : Net_players[i].player->callsign);
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);
618 // returns true is server hasn't been heard from in N seconds. false otherwise
619 int multi_client_server_dead()
621 fix this_time, last_time, max;
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 )
632 this_time -= last_time;
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;
638 max = MULTI_SERVER_MAX_TIMEOUT_LARGE;
641 if ( this_time > max){
648 void multi_process_incoming(); // prototype for function later in this module
650 // function to process network data in hopes of getting info back from server
651 int multi_client_wait_on_server()
655 is_dead = multi_client_server_dead();
657 // if the server is back alive, tell our popup
659 return MULTI_SERVER_ALIVE;
662 // on release version -- keep popup active for 60 seconds, then bail
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();
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;
680 // function called by multiplayer clients to stop simulating when they have not heard from the server
682 void multi_client_check_server()
686 SDL_assert( MULTIPLAYER_CLIENT );
688 // this function can get called while in the popup code below. So we include this check as a
690 if ( Multi_server_check_count )
693 // make sure we have a valid server
694 if(Netgame.server == NULL){
698 Multi_server_check_count++;
699 if(multi_client_server_dead()){
700 Netgame.flags |= NG_FLAG_SERVER_LOST;
702 Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
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) );
711 if ( !rval || (rval == MULTI_SERVER_GONE) ) {
712 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);
714 Netgame.flags &= ~(NG_FLAG_SERVER_LOST);
718 Multi_server_check_count--;
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.
727 void process_packet_normal(ubyte* data, header *header_info)
732 process_join_packet(data, header_info);
736 process_game_chat_packet( data, header_info );
739 case NOTIFY_NEW_PLAYER:
740 process_new_player_packet(data, header_info);
744 process_hud_message(data, header_info);
747 case MISSION_MESSAGE:
748 process_mission_message_packet( data, header_info );
752 process_leave_game_packet(data, header_info);
756 process_game_query(data, header_info);
760 process_game_active_packet(data, header_info);
764 process_game_info_packet( data, header_info );
767 case SECONDARY_FIRED_AI:
768 process_secondary_fired_packet(data, header_info, 0);
771 case SECONDARY_FIRED_PLR:
772 process_secondary_fired_packet(data, header_info, 1);
775 case COUNTERMEASURE_FIRED:
776 process_countermeasure_fired_packet( data, header_info );
779 case FIRE_TURRET_WEAPON:
780 process_turret_fired_packet( data, header_info );
784 process_netgame_update_packet( data, header_info );
787 case UPDATE_DESCRIPT:
788 process_netgame_descript_packet( data, header_info );
791 case NETPLAYER_UPDATE:
792 process_netplayer_update_packet( data, header_info );
796 process_accept_packet(data, header_info);
800 multi_oo_process_update(data, header_info);
804 process_ship_kill_packet( data, header_info );
808 process_wing_create_packet( data, header_info );
812 process_ship_create_packet( data, header_info );
816 process_ship_depart_packet( data, header_info );
819 case MISSION_LOG_ENTRY:
820 process_mission_log_packet( data, header_info );
824 process_ping_packet(data, header_info);
828 process_pong_packet(data, header_info);
832 SDL_assert(header_info->id >= 0);
834 PSNET_SOCKET_RELIABLE sock;
835 sock = INVALID_SOCKET;
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);
841 sock = Net_players[np_index].reliable_socket;
844 // otherwise always use my own socket
845 else if(Net_player != NULL){
846 sock = Net_player->reliable_socket;
849 header_info->bytes_processed = multi_xfer_process_packet(data + HEADER_LENGTH, sock) + HEADER_LENGTH;
852 case MISSION_REQUEST:
853 process_mission_request_packet(data,header_info);
857 process_mission_item_packet(data,header_info);
860 case MULTI_PAUSE_REQUEST:
861 process_multi_pause_packet(data, header_info);
865 process_ingame_nak(data, header_info);
868 case SHIPS_INGAME_PACKET:
869 process_ingame_ships_packet(data, header_info);
872 case WINGS_INGAME_PACKET:
873 process_ingame_wings_packet(data, header_info);
877 process_endgame_packet(data, header_info);
880 case OBSERVER_UPDATE:
881 process_observer_update_packet(data, header_info);
884 case NETPLAYER_SLOTS_P:
885 process_netplayer_slot_packet(data, header_info);
888 case SHIP_STATUS_CHANGE:
889 process_ship_status_packet(data, header_info);
892 case PLAYER_ORDER_PACKET:
893 process_player_order_packet(data, header_info);
896 case INGAME_SHIP_UPDATE:
897 process_ingame_ship_update_packet(data, header_info);
900 case INGAME_SHIP_REQUEST:
901 process_ingame_ship_request_packet(data, header_info);
905 process_file_sig_packet(data, header_info);
909 multi_respawn_process_packet(data,header_info);
912 case SUBSYSTEM_DESTROYED:
913 process_subsystem_destroyed_packet( data, header_info );
916 case LOAD_MISSION_NOW :
917 process_netplayer_load_packet(data, header_info);
920 case FILE_SIG_REQUEST :
921 process_file_sig_request(data, header_info);
925 process_jump_into_mission_packet(data, header_info);
928 case CLIENT_REPAIR_INFO:
929 process_repair_info_packet(data,header_info);
932 case MISSION_SYNC_DATA:
933 process_mission_sync_packet(data,header_info);
936 case STORE_MISSION_STATS:
937 process_store_stats_packet(data, header_info);
941 process_debris_update_packet(data, header_info);
944 case SHIP_WSTATE_CHANGE:
945 process_ship_weapon_change( data, header_info );
948 case WSS_UPDATE_PACKET:
949 process_wss_update_packet(data, header_info);
952 case WSS_REQUEST_PACKET:
953 process_wss_request_packet( data, header_info );
957 process_firing_info_packet( data, header_info );
961 process_cargo_revealed_packet( data, header_info);
964 case SUBSYS_CARGO_REVEALED:
965 process_subsystem_cargo_revealed_packet( data, header_info);
968 case MISSION_GOAL_INFO:
969 process_mission_goal_info_packet(data, header_info);
973 process_player_kick_packet(data, header_info);
976 case PLAYER_SETTINGS:
977 process_player_settings_packet(data, header_info);
981 process_deny_packet(data, header_info);
985 process_post_sync_data_packet(data, header_info);
989 process_wss_slots_data_packet(data,header_info);
992 case SHIELD_EXPLOSION:
993 process_shield_explosion_packet( data, header_info );
997 process_player_stats_block_packet(data, header_info);
1001 process_pslot_update_packet(data,header_info);
1004 case AI_INFO_UPDATE:
1005 process_ai_info_update_packet( data, header_info );
1008 case CAMPAIGN_UPDATE :
1009 multi_campaign_process_update(data,header_info);
1012 case CAMPAIGN_UPDATE_INGAME:
1013 multi_campaign_process_ingame_start(data,header_info);
1017 multi_voice_process_packet(data,header_info);
1021 multi_team_process_packet(data,header_info);
1025 process_asteroid_info(data, header_info);
1028 case HOST_RESTR_QUERY:
1029 process_host_restr_packet(data, header_info);
1032 case OPTIONS_UPDATE:
1033 multi_options_process_packet(data,header_info);
1036 case SQUADMSG_PLAYER:
1037 multi_msg_process_squadmsg_packet(data,header_info);
1040 case NETGAME_END_ERROR:
1041 process_netgame_end_error_packet(data,header_info);
1044 case COUNTERMEASURE_SUCCESS:
1045 process_countermeasure_success_packet( data, header_info );
1049 process_client_update_packet(data, header_info);
1053 process_countdown_packet(data, header_info);
1057 process_debrief_info( data, header_info );
1060 case ACCEPT_PLAYER_DATA:
1061 process_accept_player_data( data, header_info );
1064 case HOMING_WEAPON_UPDATE:
1065 process_homing_weapon_info( data, header_info );
1069 process_emp_effect(data, header_info);
1072 case REINFORCEMENT_AVAIL:
1073 process_reinforcement_avail( data, header_info );
1077 process_change_iff_packet(data, header_info);
1080 case PRIMARY_FIRED_NEW:
1081 process_NEW_primary_fired_packet(data, header_info);
1084 case COUNTERMEASURE_NEW:
1085 process_NEW_countermeasure_fired_packet(data, header_info);
1089 process_beam_fired_packet(data, header_info);
1093 process_sw_query_packet(data, header_info);
1097 process_event_update_packet(data, header_info);
1100 case OBJECT_UPDATE_NEW:
1101 multi_oo_process_update(data, header_info);
1105 process_weapon_detonate_packet(data, header_info);
1109 process_flak_fired_packet(data, header_info);
1112 case NETPLAYER_PAIN:
1113 process_player_pain_packet(data, header_info);
1116 case LIGHTNING_PACKET:
1117 process_lightning_packet(data, header_info);
1121 process_bytes_recvd_packet(data, header_info);
1125 process_host_captain_change_packet(data, header_info);
1129 process_self_destruct_packet(data, header_info);
1133 nprintf(("Network", "Received packet with unknown type %d\n", data[0] ));
1134 header_info->bytes_processed = 10000;
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)
1149 int type, bytes_processed;
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);
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();
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;
1170 header_info.id = -1;
1173 bytes_processed = 0;
1174 while( (bytes_processed >= 0) && (bytes_processed < len) ) {
1176 buf = &(data[bytes_processed]);
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)){
1185 if ( (type<0) || (type > MAX_TYPE_ID )) {
1186 nprintf( ("Network", "multi_process_bigdata: Invalid packet type %d!\n", type ));
1190 // perform any special processing checks here
1191 process_packet_normal(buf,&header_info);
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;
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;
1206 // process all reliable socket details
1207 void multi_process_reliable_details()
1212 // run reliable sockets
1217 // server operations
1218 if ( MULTIPLAYER_MASTER ){
1219 // listen for new reliable socket connections
1220 multi_check_listen();
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!");
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;
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!");
1248 // clients should detect broken sockets
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"));
1257 if(!multi_endgame_ending()){
1258 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_CONTACT_LOST);
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()
1270 ubyte *data, *savep;
1271 net_addr_t from_addr;
1273 SDL_assert( Multi_read_count < NUM_REENTRANT_LEVELS );
1274 savep = net_buffer[Multi_read_count];
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"));
1286 // otherwise process incoming data normally
1288 multi_process_bigdata(data, size, &from_addr, 0);
1292 // read reliable sockets for data
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);
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);
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.
1327 dc_printf("proper eye stuff on\n");
1329 dc_printf("proper eye stuff off\n");
1333 void multi_do_frame()
1335 PSNET_TOP_LAYER_PROCESS();
1337 // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1339 if((Net_player != NULL) && eye_tog){
1340 player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1343 // send all buffered packets from the previous frame
1344 multi_io_send_buffered_packets();
1346 // datarate tracking
1347 multi_rate_process();
1349 // always process any pending endgame details
1350 multi_endgame_process();
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();
1358 // get the other net players data
1359 multi_process_incoming();
1361 // process object update datarate stuff (for clients and server both)
1362 multi_oo_rate_process();
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();
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();
1377 multi_ping_send_all();
1378 Next_ping_time = time(NULL);
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();
1389 Netgame_send_time = time(NULL);
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();
1398 State_send_time = time(NULL);
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();
1408 Gameinfo_send_time = time(NULL);
1411 // for any potential respawns
1412 multi_respawn_handle_invul_players();
1413 multi_respawn_check_ai();
1415 // for any potential ingame joiners
1416 multi_handle_ingame_joiners();
1418 // the clients need to do some processing of stuff as well
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);
1431 // while in the mission, send my PlayerControls to the host so that he can process
1433 if ( Game_mode & GM_IN_MISSION ) {
1435 extern void oo_update_time();
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();
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();
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);
1459 // reset bytes recvd
1460 Net_player->cl_bytes_recvd = 0;
1464 Next_bytes_time = time(NULL);
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.
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() ) {
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();
1484 // periodically send a client update packet to all clients
1485 if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
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)){
1491 send_client_update_packet(&Net_players[idx]);
1493 Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1499 // process any kicked player details
1500 multi_kick_process();
1502 // do any file xfer details
1505 // process any player data details (wav files, pilot pics, etc)
1508 // do any voice details
1509 multi_voice_process();
1511 // process any player messaging details
1512 multi_msg_process();
1514 // process any tracker messages
1515 multi_fs_tracker_process();
1517 // if on the standalone, do any gui stuff
1518 if(Game_mode & GM_STANDALONE_SERVER){
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);
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)
1534 void multi_pause_do_frame()
1536 PSNET_TOP_LAYER_PROCESS();
1538 // always set the local player eye position/orientation here so we know its valid throughout all multiplayer
1540 // if((Net_player != NULL) && eye_tog){
1541 // player_get_eye(&Net_player->s_info.eye_pos, &Net_player->s_info.eye_orient);
1544 // send all buffered packets from the previous frame
1545 multi_io_send_buffered_packets();
1547 // always process any pending endgame details
1548 multi_endgame_process();
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();
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();
1561 Gameinfo_send_time = time(NULL);
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();
1569 Next_ping_time = time(NULL);
1572 // periodically send a client update packet to all clients
1573 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
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)){
1580 send_client_update_packet(&Net_players[idx]);
1582 Multi_client_update_times[idx] = timestamp(MULTI_CLIENT_UPDATE_TIME);
1587 // for any potential ingame joiners
1588 multi_handle_ingame_joiners();
1591 // do any file xfer details
1594 // process any player data details (wav files, pilot pics, etc)
1597 // get the other net players data
1598 multi_process_incoming();
1600 // do any voice details
1601 multi_voice_process();
1603 // process any player messaging details
1604 multi_msg_process();
1606 // process any kicked player details
1607 multi_kick_process();
1609 // process any pending endgame details
1610 multi_endgame_process();
1612 // process object update stuff (for clients and server both)
1613 if(MULTIPLAYER_MASTER){
1617 // if on the standalone, do any gui stuff
1618 if(Game_mode & GM_STANDALONE_SERVER){
1624 // --------------------------------------------------------------------------------
1625 // standalone_main_init() the standalone equivalent of the main menu
1628 extern int sock_inited;
1629 float frame_time = (float)1.0/(float)30.0;
1631 void standalone_main_init()
1633 std_debug_set_standalone_state_string("Main Init");
1635 Game_mode = (GM_STANDALONE_SERVER | GM_MULTIPLAYER);
1638 ml_string(NOX("Standalone server initializing"));
1640 // read in config file
1641 // multi_options_read_config();
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);
1650 Multi_options_g.protocol = NET_TCP;
1651 psnet_use_protocol(Multi_options_g.protocol);
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;
1660 // reinitialize all systems
1663 // intialize endgame stuff
1664 multi_endgame_init();
1666 // clear the file xfer system
1668 multi_xfer_force_dir(CF_TYPE_MULTI_CACHE);
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;
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;
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;
1695 if(game_hacked_data()){
1696 Net_player->flags |= NETINFO_FLAG_HAXOR;
1699 // setup debug flags
1700 Netgame.debug_flags = 0;
1702 if(!Cmdline_server_firing){
1703 Netgame.debug_flags |= NETD_FLAG_CLIENT_FIRING;
1705 if(!Cmdline_client_dodamage){
1706 Netgame.debug_flags |= NETD_FLAG_CLIENT_NODAMAGE;
1710 // setup the default game name for the standalone
1711 std_connect_set_gamename(NULL);
1713 // set netgame default options
1714 multi_options_set_netgame_defaults(&Netgame.options);
1716 // set local netplayer default options
1717 multi_options_set_local_defaults(&Net_player->p_info.options);
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"));
1725 case OBJ_UPDATE_MEDIUM:
1726 nprintf(("Network","STANDALONE USING MEDIUM UPDATES\n"));
1728 case OBJ_UPDATE_HIGH:
1729 nprintf(("Network","STANDALONE USING HIGH UPDATE\n"));
1731 case OBJ_UPDATE_LAN:
1732 nprintf(("Network","STANDALONE USING LAN UPDATE\n"));
1736 // clear out various things
1741 // login to game tracker
1742 std_tracker_login();
1744 std_debug_set_standalone_state_string("Main Do");
1745 std_set_standalone_fps((float)0);
1746 std_multi_set_standalone_missiontime((float)0);
1748 // load my missions and campaigns
1749 multi_create_list_load_missions();
1750 multi_create_list_load_campaigns();
1752 SDL_zero(The_mission);
1754 // if this is a tracker game, validate missions
1755 if(MULTI_IS_TRACKER_GAME){
1756 multi_update_valid_missions();
1761 // --------------------------------------------------------------------------------
1762 // standalone_main_do()
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
1770 void standalone_main_do()
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
1777 // --------------------------------------------------------------------------------
1778 // standalone_main_close()
1781 void standalone_main_close()
1783 std_debug_set_standalone_state_string("Main Close");
1785 // disconnect game from tracker
1786 multi_fs_tracker_logout();
1790 void multi_standalone_reset_all()
1795 ml_string(NOX("Standalone resetting"));
1797 // shut all game stuff down
1800 // reinitialize the gui
1801 std_reset_standalone_gui();
1803 // close down all sockets
1804 for(idx=0;idx<MAX_PLAYERS;idx++){
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 );
1813 // make sure we go to the proper state.
1814 if(gameseq_get_state() == GS_STATE_STANDALONE_MAIN){
1815 standalone_main_init();
1817 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
1820 // --------------------------------------------------------------------------------
1821 // multi_server_wait_init() do stuff like setting the status bits correctly
1824 void multi_standalone_wait_init()
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();
1830 // create the bogus standalone object
1831 multi_create_standalone_object();
1835 // --------------------------------------------------------------------------------
1836 // multi_server_wait_do_frame() wait for everyone to log in or the host to send commands
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()
1847 // --------------------------------------------------------------------------------
1848 // multi_server_wait_close() cleanup
1851 void multi_standalone_wait_close()
1853 std_debug_set_standalone_state_string("Wait Close / Game Play");
1855 // all players should reset sequencing
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;
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()
1872 std_debug_set_standalone_state_string("Postgame / Send Stats");
1875 ml_string(NOX("Standlone entering postgame"));
1877 mission_goal_fail_incomplete();
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();
1885 // evaluate next mission
1886 mission_campaign_eval_next_mission();
1889 // always set my state to be "DEBRIEF_ACCEPT"
1890 Net_player->state = NETPLAYER_STATE_DEBRIEF_ACCEPT;
1892 // mark stats as not being stored yet
1893 Netgame.flags &= ~(NG_FLAG_STORED_MT_STATS);
1895 Multi_debrief_server_framecount = 0;
1897 // reset network timestamps
1898 multi_reset_timestamps();
1901 void multi_standalone_postgame_do()
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();
1910 // process server debriefing details
1911 if(Netgame.game_state == NETGAME_STATE_DEBRIEF){
1912 multi_debrief_server_process();
1916 void multi_standalone_postgame_close()
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();
1924 multi_debrief_stats_accept();
1926 Netgame.flags |= NG_FLAG_STORED_MT_STATS;
1927 send_netgame_update_packet();
1929 multi_debrief_stats_toss();
1933 if (Netgame.type_flags & NG_TYPE_SW) {
1934 multi_sw_report(stats_saved);
1941 void multi_reset_timestamps()
1945 for ( i = 0 ; i < MAX_PLAYERS; i++ ){
1946 Multi_client_update_times[i] = -1;
1948 Netgame_send_time = -1;
1949 Gameinfo_send_time = -1;
1950 Next_ping_time = -1;
1951 State_send_time = -1;
1952 Next_bytes_time = -1;
1954 chatbox_reset_timestamps();
1956 // do for all players so that ingame joiners work properly.
1957 for (i = 0; i < MAX_PLAYERS; i++ ) {
1958 Players[i].update_dumbfire_time = timestamp(0);
1959 Players[i].update_lock_time = timestamp(0);
1961 Net_players[i].s_info.voice_token_timestamp = -1;
1964 // reset standalone gui timestamps (these are not game critical, so there is not much danger)
1965 std_reset_timestamps();
1967 // initialize all object update timestamps
1968 multi_oo_gameplay_init();
1971 // netgame debug flags for debug console stuff
1972 DCF(netd, "change/list netgame debug flags")
1974 dc_get_arg(ARG_INT);
1976 // if we got an integer, and we're the server, change flags
1977 if((Dc_arg_type & ARG_INT) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Dc_arg_int <= 7)){
1978 Netgame.debug_flags ^= (1<<Dc_arg_int);
1981 // display network flags
1982 dc_printf("BITS\n");
1983 // dc_printf("1 - Client side firing (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_FIRING ? 1 : 0);
1984 // dc_printf("2 - Client nodamage (%d)\n", Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE ? 1 : 0);
1987 // display any multiplayer/networking information here
1988 void multi_display_netinfo()
1990 int sx = gr_screen.max_w - 200;
1995 if(!(Game_mode & GM_MULTIPLAYER)){
1999 gr_set_color_fast(&Color_normal);
2002 if(MULTIPLAYER_MASTER){
2003 gr_string(sx, sy, "SERVER"); sy += 10;
2005 for(idx=0; idx<MAX_PLAYERS; idx++){
2006 if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != &Net_players[idx]) && (Net_players[idx].player != NULL)){
2007 if(Net_players[idx].sv_last_pl < 0){
2008 gr_printf(sx, sy, "%s : %d, %d pl", Net_players[idx].player->callsign, Net_players[idx].sv_bytes_sent, 0); sy += 10;
2010 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;
2015 gr_string(sx, sy, "CLIENT"); sy += 10;
2018 if(Net_player != NULL){
2019 if(Net_player->cl_last_pl < 0){
2020 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, 0);// sy += 10;
2022 gr_printf(sx, sy, "PL : %d %d pl\n", Net_player->cl_bytes_recvd, Net_player->cl_last_pl);// sy += 10;