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_data.cpp $
16 * Revision 1.4 2002/06/09 04:41:23 relnev
17 * added copyright header
19 * Revision 1.3 2002/05/26 20:22:48 theoddone33
20 * Most of network/ works
22 * Revision 1.2 2002/05/07 03:16:47 theoddone33
23 * The Great Newline Fix
25 * Revision 1.1.1.1 2002/05/03 03:28:10 root
29 * 8 6/16/99 4:06p Dave
30 * New pilot info popup. Added new draw-bitmap-as-poly function.
32 * 7 1/21/99 2:06p Dave
33 * Final checkin for multiplayer testing.
35 * 6 1/14/99 6:06p Dave
36 * 100% full squad logo support for single player and multiplayer.
38 * 5 12/18/98 12:31p Johnson
39 * Fixed a bug where the server would not properly redistribute a data
40 * file that he already had to other players.
42 * 4 12/14/98 4:01p Dave
43 * Got multi_data stuff working well with new xfer stuff.
45 * 3 12/14/98 12:13p Dave
46 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
49 * 2 10/07/98 10:53a Dave
52 * 1 10/07/98 10:50a Dave
54 * 19 6/13/98 3:18p Hoffoss
55 * NOX()ed out a bunch of strings that shouldn't be translated.
57 * 18 5/21/98 3:45a Sandeep
58 * Make sure file xfer sender side uses correct directory type.
60 * 17 5/17/98 6:32p Dave
61 * Make sure clients/servers aren't kicked out of the debriefing when team
62 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
63 * xfer/pilot info popup stuff.
65 * 16 5/13/98 6:54p Dave
66 * More sophistication to PXO interface. Changed respawn checking so
67 * there's no window for desynchronization between the server and the
70 * 15 4/30/98 4:53p John
71 * Restructured and cleaned up cfile code. Added capability to read off
72 * of CD-ROM drive and out of multiple pack files.
74 * 14 4/21/98 4:44p Dave
75 * Implement Vasudan ships in multiplayer. Added a debug function to bash
76 * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
77 * problem in options screen.
79 * 13 4/16/98 1:55p Dave
80 * Removed unneeded SDL_assert when processing chat packets. Fixed standalone
81 * sequencing bugs. Laid groundwork for join screen server status
84 * 12 4/14/98 12:19p Dave
85 * Revised the pause system yet again. Seperated into its own module.
87 * 11 4/08/98 2:51p Dave
88 * Fixed pilot image xfer once again. Solidify team selection process in
89 * pre-briefing multiplayer.
91 * 10 4/04/98 4:22p Dave
92 * First rev of UDP reliable sockets is done. Seems to work well if not
95 * 9 3/30/98 6:27p Dave
96 * Put in a more official set of multiplayer options, including a system
97 * for distributing netplayer and netgame settings.
99 * 8 3/26/98 6:01p Dave
100 * Put in file checksumming routine in cfile. Made pilot pic xferring more
101 * robust. Cut header size of voice data packets in half. Put in
102 * restricted game host query system.
104 * 7 3/23/98 5:42p Dave
105 * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
106 * that it can support multiplayer sends/received between client and
107 * server simultaneously.
109 * 6 3/21/98 7:14p Dave
110 * Fixed up standalone player slot switching. Made training missions not
111 * count towards player stats.
113 * 5 3/15/98 4:17p Dave
114 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
115 * of network orientation matrices.
117 * 4 3/11/98 2:04p Dave
118 * Removed optimized build warnings.
120 * 3 2/20/98 4:43p Dave
121 * Finished support for multiplayer player data files. Split off
122 * multiplayer campaign functionality.
124 * 2 2/19/98 6:44p Dave
125 * Finished server getting data from players. Now need to rebroadcast the
128 * 1 2/19/98 6:21p Dave
129 * Player data file xfer module.
137 #include "multi_data.h"
138 #include "freespace.h"
139 #include "multi_xfer.h"
141 #include "multimsgs.h"
142 #include "multiutil.h"
145 // -------------------------------------------------------------------------
146 // MULTI DATA DEFINES/VARS
149 #define MAX_MULTI_DATA 40
151 // player data struct
152 typedef struct np_data {
153 char filename[MAX_FILENAME_LEN+1]; // filename
154 ubyte status[MAX_PLAYERS]; // status for all players (0 == don't have it, 1 == have or sending, 2 == i sent it originally)
155 ushort player_id; // id of the player who sent the file
156 ubyte used; // in use or not
159 np_data Multi_data[MAX_MULTI_DATA];
161 time_t Multi_data_time = 0;
164 // -------------------------------------------------------------------------
165 // MULTI DATA FORWARD DECLARATIONS
168 // is the given filename for a "multi data" file (pcx, wav, etc)
169 int multi_data_is_data(char *filename);
171 // get a free np_data slot
172 int multi_data_get_free();
174 // server side - add a new file
175 int multi_data_add_new(char *filename, int player_index);
177 // maybe try and reload player squad logo bitmaps
178 void multi_data_maybe_reload();
181 // -------------------------------------------------------------------------
182 // MULTI DATA FUNCTIONS
185 // reset the data xfer system
186 void multi_data_reset()
190 // clear out all used bits
191 for(idx=0; idx<MAX_MULTI_DATA; idx++){
192 Multi_data[idx].used = 0;
196 // handle a player join (clear out lists of files, etc)
197 void multi_data_handle_join(int player_index)
201 // clear out his status for all files
202 for(idx=0;idx<MAX_MULTI_DATA;idx++){
203 Multi_data[idx].status[player_index] = 0;
207 // handle a player drop (essentially the same as multi_data_handle_join)
208 void multi_data_handle_drop(int player_index)
212 // mark all files he sent as being unused
213 for(idx=0;idx<MAX_MULTI_DATA;idx++){
214 if(Multi_data[idx].player_id == Net_players[player_index].player_id){
215 Multi_data[idx].used = 0;
220 // do all sync related data stuff (server-side only)
225 // only do this once a second
226 if((time(NULL) - Multi_data_time) < 1){
230 // maybe try and reload player squad logo bitmaps
231 multi_data_maybe_reload();
234 Multi_data_time = time(NULL);
237 if(Net_player && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
238 // for all valid files
239 for(idx=0; idx<MAX_MULTI_DATA; idx++){
240 // a valid file that isn't currently xferring (ie, anything we've got completely on our hard drive)
241 if(Multi_data[idx].used && (multi_xfer_lookup(Multi_data[idx].filename) < 0)){
242 // send it to all players who need it
243 for(p_idx=0; p_idx<MAX_PLAYERS; p_idx++){
244 // if he doesn't have it
245 if((Net_player != &Net_players[p_idx]) && MULTI_CONNECTED(Net_players[p_idx]) && (Net_players[p_idx].reliable_socket != INVALID_SOCKET) && (Multi_data[idx].status[p_idx] == 0)){
246 // queue up the file to send to him, or at least try to
247 if(multi_xfer_send_file(Net_players[p_idx].reliable_socket, Multi_data[idx].filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE) < 0){
248 nprintf(("Network", "Failed to send data file! Trying again later...\n"));
251 Multi_data[idx].status[p_idx] = 1;
260 // handle an incoming xfer request from the xfer system
261 void multi_data_handle_incoming(int handle)
263 int player_index = -1;
264 PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
267 // get the player who is sending us this file
268 sock = multi_xfer_get_sock(handle);
269 player_index = find_player_socket(sock);
271 // get the filename of the file
272 fname = multi_xfer_get_filename(handle);
274 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
277 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
281 // if this is not a valid data file
282 if(!multi_data_is_data(fname)){
283 nprintf(("Network", "Not accepting xfer request because its not a valid data file!\n"));
286 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
290 // if we already have a copy of this file, abort the xfer
291 // Does file exist in \multidata?
292 if( cf_exist(fname, CF_TYPE_MULTI_CACHE) ){
293 nprintf(("Network", "Not accepting file xfer because a duplicate exists!\n"));
296 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
298 // if we're the server, we still need to add it to the list though
299 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_index >= 0)){
300 multi_data_add_new(fname, player_index);
305 // if I'm the server of the game, do stuff a little differently
306 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
307 if(player_index == -1){
308 nprintf(("Network", "Could not find player for incoming player data stream!\n"));
311 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
315 // attempt to add the file
316 if(!multi_data_add_new(fname, player_index)){
318 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
321 // force the file to go into the multi cache directory
322 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
324 // mark it as autodestroy
325 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
328 // if i'm a client, this is an incoming file from the server
330 // if i'm not accepting pilot pics, abort
331 if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX)){
332 nprintf(("Network", "Client not accepting files because we don't want 'em!\n"));
335 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
339 // set the xfer handle to autodestroy itself since we don't really want to have to manage all incoming pics
340 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
342 // force the file to go into the multi cache directory
343 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
345 // begin receiving the file
346 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
350 // send all my files as necessary
351 void multi_data_send_my_junk()
357 // pilot pic --------------------------------------------------------------
359 // verify that my pilot pic is valid
360 if(strlen(Net_player->player->image_filename)){
361 bmap = bm_load(Net_player->player->image_filename);
366 // verify image dimensions
370 bm_get_info(bmap,&w,&h);
372 // release the bitmap
376 // if the dimensions are invalid, kill the filename
377 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
386 with_ext = cf_add_ext(Net_player->player->image_filename, NOX(".pcx"));
387 if(with_ext != NULL){
388 strcpy(Net_player->player->image_filename, with_ext);
391 // host should put his own pic file in the list now
392 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->image_filename) > 0)){
393 multi_data_add_new(Net_player->player->image_filename, MY_NET_PLAYER_NUM);
395 // otherwise clients should just queue up a send
397 // add a file extension if necessary
398 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
403 // squad logo --------------------------------------------------------------
405 // verify that my pilot pic is valid
407 if(strlen(Net_player->player->squad_filename)){
408 bmap = bm_load(Net_player->player->squad_filename);
414 // verify image dimensions
417 bm_get_info(bmap,&w,&h);
419 // release the bitmap
423 // if the dimensions are invalid, kill the filename
424 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
433 with_ext = cf_add_ext(Net_player->player->squad_filename, NOX(".pcx"));
434 if(with_ext != NULL){
435 strcpy(Net_player->player->squad_filename,with_ext);
438 // host should put his own pic file in the list now
439 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->squad_filename) > 0)){
440 multi_data_add_new(Net_player->player->squad_filename, MY_NET_PLAYER_NUM);
442 // otherwise clients should just queue up a send
444 // add a file extension if necessary
445 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
451 // -------------------------------------------------------------------------
452 // MULTI DATA FORWARD DECLARATIONS
455 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
456 int multi_data_is_data(char *filename)
460 SDL_assert(filename != NULL);
462 // some kind of error
463 if(filename == NULL){
467 // convert to lowercase
468 len = strlen(filename);
469 for(idx=0;idx<len;idx++){
470 filename[idx] = (char)tolower(filename[idx]);
473 // check to see if the extension is .pcx
474 if(strstr(filename, NOX(".pcx"))){
482 // get a free np_data slot
483 int multi_data_get_free()
488 for(idx=0; idx<MAX_MULTI_DATA; idx++){
489 if(!Multi_data[idx].used){
498 // server side - add a new file. return 1 on success
499 int multi_data_add_new(char *filename, int player_index)
503 // try and get a free slot
504 slot = multi_data_get_free();
506 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
510 // if the netgame isn't flagged as accepting data files
511 if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
512 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));
517 memset(&Multi_data[slot], 0, sizeof(np_data)); // clear the slot out
518 strcpy(Multi_data[slot].filename, filename); // copy the filename
519 Multi_data[slot].used = 1; // set it as being in use
520 Multi_data[slot].player_id = Net_players[player_index].player_id; // player id of who's sending the file
521 Multi_data[slot].status[player_index] = 2; // mark his status appropriately
527 // maybe try and reload player squad logo bitmaps
528 void multi_data_maybe_reload()
532 // go through all connected and try to reload their images if necessary
533 for(idx=0; idx<MAX_PLAYERS; idx++){
534 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].player->squad_filename) && (Net_players[idx].player->insignia_texture == -1)){
535 Net_players[idx].player->insignia_texture = bm_load_duplicate(Net_players[idx].player->squad_filename);
537 // if the bitmap loaded properly, lock it as a transparent texture
538 if(Net_players[idx].player->insignia_texture != -1){
539 bm_lock(Net_players[idx].player->insignia_texture, 16, BMP_TEX_XPARENT);
540 bm_unlock(Net_players[idx].player->insignia_texture);