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
375 // if the dimensions are invalid, kill the filename
376 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
385 with_ext = cf_add_ext(Net_player->player->image_filename, NOX(".pcx"));
386 if(with_ext != NULL){
387 SDL_strlcpy(Net_player->player->image_filename, with_ext, MAX_FILENAME_LEN);
390 // host should put his own pic file in the list now
391 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->image_filename) > 0)){
392 multi_data_add_new(Net_player->player->image_filename, MY_NET_PLAYER_NUM);
394 // otherwise clients should just queue up a send
396 // add a file extension if necessary
397 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
402 // squad logo --------------------------------------------------------------
404 // verify that my pilot pic is valid
406 if(strlen(Net_player->player->squad_filename)){
407 bmap = bm_load(Net_player->player->squad_filename);
413 // verify image dimensions
416 bm_get_info(bmap,&w,&h);
418 // release the bitmap
421 // if the dimensions are invalid, kill the filename
422 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
431 with_ext = cf_add_ext(Net_player->player->squad_filename, NOX(".pcx"));
432 if(with_ext != NULL){
433 SDL_strlcpy(Net_player->player->squad_filename, with_ext, MAX_FILENAME_LEN);
436 // host should put his own pic file in the list now
437 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->squad_filename) > 0)){
438 multi_data_add_new(Net_player->player->squad_filename, MY_NET_PLAYER_NUM);
440 // otherwise clients should just queue up a send
442 // add a file extension if necessary
443 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
449 // -------------------------------------------------------------------------
450 // MULTI DATA FORWARD DECLARATIONS
453 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
454 int multi_data_is_data(char *filename)
458 SDL_assert(filename != NULL);
460 // some kind of error
461 if(filename == NULL){
465 // convert to lowercase
466 len = strlen(filename);
467 for(idx=0;idx<len;idx++){
468 filename[idx] = (char)tolower(filename[idx]);
471 // check to see if the extension is .pcx
472 if(strstr(filename, NOX(".pcx"))){
480 // get a free np_data slot
481 int multi_data_get_free()
486 for(idx=0; idx<MAX_MULTI_DATA; idx++){
487 if(!Multi_data[idx].used){
496 // server side - add a new file. return 1 on success
497 int multi_data_add_new(char *filename, int player_index)
501 // try and get a free slot
502 slot = multi_data_get_free();
504 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
508 // if the netgame isn't flagged as accepting data files
509 if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
510 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));
515 memset(&Multi_data[slot], 0, sizeof(np_data)); // clear the slot out
516 SDL_strlcpy(Multi_data[slot].filename, filename, MAX_FILENAME_LEN); // copy the filename
517 Multi_data[slot].used = 1; // set it as being in use
518 Multi_data[slot].player_id = Net_players[player_index].player_id; // player id of who's sending the file
519 Multi_data[slot].status[player_index] = 2; // mark his status appropriately
525 // maybe try and reload player squad logo bitmaps
526 void multi_data_maybe_reload()
530 // go through all connected and try to reload their images if necessary
531 for(idx=0; idx<MAX_PLAYERS; idx++){
532 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].player->squad_filename) && (Net_players[idx].player->insignia_texture == -1)){
533 Net_players[idx].player->insignia_texture = bm_load_duplicate(Net_players[idx].player->squad_filename);
535 // if the bitmap loaded properly, lock it as a transparent texture
536 if(Net_players[idx].player->insignia_texture != -1){
537 bm_lock(Net_players[idx].player->insignia_texture, 16, BMP_TEX_XPARENT);
538 bm_unlock(Net_players[idx].player->insignia_texture);