2 * $Logfile: /Freespace2/code/Network/multi_data.cpp $
8 * Revision 1.1 2002/05/03 03:28:10 root
12 * 8 6/16/99 4:06p Dave
13 * New pilot info popup. Added new draw-bitmap-as-poly function.
15 * 7 1/21/99 2:06p Dave
16 * Final checkin for multiplayer testing.
18 * 6 1/14/99 6:06p Dave
19 * 100% full squad logo support for single player and multiplayer.
21 * 5 12/18/98 12:31p Johnson
22 * Fixed a bug where the server would not properly redistribute a data
23 * file that he already had to other players.
25 * 4 12/14/98 4:01p Dave
26 * Got multi_data stuff working well with new xfer stuff.
28 * 3 12/14/98 12:13p Dave
29 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
32 * 2 10/07/98 10:53a Dave
35 * 1 10/07/98 10:50a Dave
37 * 19 6/13/98 3:18p Hoffoss
38 * NOX()ed out a bunch of strings that shouldn't be translated.
40 * 18 5/21/98 3:45a Sandeep
41 * Make sure file xfer sender side uses correct directory type.
43 * 17 5/17/98 6:32p Dave
44 * Make sure clients/servers aren't kicked out of the debriefing when team
45 * captains leave a game. Fixed chatbox off-by-one error. Fixed image
46 * xfer/pilot info popup stuff.
48 * 16 5/13/98 6:54p Dave
49 * More sophistication to PXO interface. Changed respawn checking so
50 * there's no window for desynchronization between the server and the
53 * 15 4/30/98 4:53p John
54 * Restructured and cleaned up cfile code. Added capability to read off
55 * of CD-ROM drive and out of multiple pack files.
57 * 14 4/21/98 4:44p Dave
58 * Implement Vasudan ships in multiplayer. Added a debug function to bash
59 * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
60 * problem in options screen.
62 * 13 4/16/98 1:55p Dave
63 * Removed unneeded Assert when processing chat packets. Fixed standalone
64 * sequencing bugs. Laid groundwork for join screen server status
67 * 12 4/14/98 12:19p Dave
68 * Revised the pause system yet again. Seperated into its own module.
70 * 11 4/08/98 2:51p Dave
71 * Fixed pilot image xfer once again. Solidify team selection process in
72 * pre-briefing multiplayer.
74 * 10 4/04/98 4:22p Dave
75 * First rev of UDP reliable sockets is done. Seems to work well if not
78 * 9 3/30/98 6:27p Dave
79 * Put in a more official set of multiplayer options, including a system
80 * for distributing netplayer and netgame settings.
82 * 8 3/26/98 6:01p Dave
83 * Put in file checksumming routine in cfile. Made pilot pic xferring more
84 * robust. Cut header size of voice data packets in half. Put in
85 * restricted game host query system.
87 * 7 3/23/98 5:42p Dave
88 * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
89 * that it can support multiplayer sends/received between client and
90 * server simultaneously.
92 * 6 3/21/98 7:14p Dave
93 * Fixed up standalone player slot switching. Made training missions not
94 * count towards player stats.
96 * 5 3/15/98 4:17p Dave
97 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
98 * of network orientation matrices.
100 * 4 3/11/98 2:04p Dave
101 * Removed optimized build warnings.
103 * 3 2/20/98 4:43p Dave
104 * Finished support for multiplayer player data files. Split off
105 * multiplayer campaign functionality.
107 * 2 2/19/98 6:44p Dave
108 * Finished server getting data from players. Now need to rebroadcast the
111 * 1 2/19/98 6:21p Dave
112 * Player data file xfer module.
119 #include "multi_data.h"
120 #include "freespace.h"
121 #include "multi_xfer.h"
123 #include "multimsgs.h"
124 #include "multiutil.h"
127 // -------------------------------------------------------------------------
128 // MULTI DATA DEFINES/VARS
131 #define MAX_MULTI_DATA 40
133 // player data struct
134 typedef struct np_data {
135 char filename[MAX_FILENAME_LEN+1]; // filename
136 ubyte status[MAX_PLAYERS]; // status for all players (0 == don't have it, 1 == have or sending, 2 == i sent it originally)
137 ushort player_id; // id of the player who sent the file
138 ubyte used; // in use or not
141 np_data Multi_data[MAX_MULTI_DATA];
143 time_t Multi_data_time = 0;
146 // -------------------------------------------------------------------------
147 // MULTI DATA FORWARD DECLARATIONS
150 // is the given filename for a "multi data" file (pcx, wav, etc)
151 int multi_data_is_data(char *filename);
153 // get a free np_data slot
154 int multi_data_get_free();
156 // server side - add a new file
157 int multi_data_add_new(char *filename, int player_index);
159 // maybe try and reload player squad logo bitmaps
160 void multi_data_maybe_reload();
163 // -------------------------------------------------------------------------
164 // MULTI DATA FUNCTIONS
167 // reset the data xfer system
168 void multi_data_reset()
172 // clear out all used bits
173 for(idx=0; idx<MAX_MULTI_DATA; idx++){
174 Multi_data[idx].used = 0;
178 // handle a player join (clear out lists of files, etc)
179 void multi_data_handle_join(int player_index)
183 // clear out his status for all files
184 for(idx=0;idx<MAX_MULTI_DATA;idx++){
185 Multi_data[idx].status[player_index] = 0;
189 // handle a player drop (essentially the same as multi_data_handle_join)
190 void multi_data_handle_drop(int player_index)
194 // mark all files he sent as being unused
195 for(idx=0;idx<MAX_MULTI_DATA;idx++){
196 if(Multi_data[idx].player_id == Net_players[player_index].player_id){
197 Multi_data[idx].used = 0;
202 // do all sync related data stuff (server-side only)
207 // only do this once a second
208 if((time(NULL) - Multi_data_time) < 1){
212 // maybe try and reload player squad logo bitmaps
213 multi_data_maybe_reload();
216 Multi_data_time = time(NULL);
219 if(Net_player && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
220 // for all valid files
221 for(idx=0; idx<MAX_MULTI_DATA; idx++){
222 // a valid file that isn't currently xferring (ie, anything we've got completely on our hard drive)
223 if(Multi_data[idx].used && (multi_xfer_lookup(Multi_data[idx].filename) < 0)){
224 // send it to all players who need it
225 for(p_idx=0; p_idx<MAX_PLAYERS; p_idx++){
226 // if he doesn't have it
227 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)){
228 // queue up the file to send to him, or at least try to
229 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){
230 nprintf(("Network", "Failed to send data file! Trying again later...\n"));
233 Multi_data[idx].status[p_idx] = 1;
242 // handle an incoming xfer request from the xfer system
243 void multi_data_handle_incoming(int handle)
245 int player_index = -1;
246 PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
249 // get the player who is sending us this file
250 sock = multi_xfer_get_sock(handle);
251 player_index = find_player_socket(sock);
253 // get the filename of the file
254 fname = multi_xfer_get_filename(handle);
256 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
259 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
263 // if this is not a valid data file
264 if(!multi_data_is_data(fname)){
265 nprintf(("Network", "Not accepting xfer request because its not a valid data file!\n"));
268 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
272 // if we already have a copy of this file, abort the xfer
273 // Does file exist in \multidata?
274 if( cf_exist(fname, CF_TYPE_MULTI_CACHE) ){
275 nprintf(("Network", "Not accepting file xfer because a duplicate exists!\n"));
278 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
280 // if we're the server, we still need to add it to the list though
281 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_index >= 0)){
282 multi_data_add_new(fname, player_index);
287 // if I'm the server of the game, do stuff a little differently
288 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
289 if(player_index == -1){
290 nprintf(("Network", "Could not find player for incoming player data stream!\n"));
293 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
297 // attempt to add the file
298 if(!multi_data_add_new(fname, player_index)){
300 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
303 // force the file to go into the multi cache directory
304 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
306 // mark it as autodestroy
307 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
310 // if i'm a client, this is an incoming file from the server
312 // if i'm not accepting pilot pics, abort
313 if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX)){
314 nprintf(("Network", "Client not accepting files because we don't want 'em!\n"));
317 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
321 // set the xfer handle to autodestroy itself since we don't really want to have to manage all incoming pics
322 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
324 // force the file to go into the multi cache directory
325 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
327 // begin receiving the file
328 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
332 // send all my files as necessary
333 void multi_data_send_my_junk()
339 // pilot pic --------------------------------------------------------------
341 // verify that my pilot pic is valid
342 if(strlen(Net_player->player->image_filename)){
343 bmap = bm_load(Net_player->player->image_filename);
348 // verify image dimensions
352 bm_get_info(bmap,&w,&h);
354 // release the bitmap
358 // if the dimensions are invalid, kill the filename
359 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
368 with_ext = cf_add_ext(Net_player->player->image_filename, NOX(".pcx"));
369 if(with_ext != NULL){
370 strcpy(Net_player->player->image_filename, with_ext);
373 // host should put his own pic file in the list now
374 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->image_filename) > 0)){
375 multi_data_add_new(Net_player->player->image_filename, MY_NET_PLAYER_NUM);
377 // otherwise clients should just queue up a send
379 // add a file extension if necessary
380 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
385 // squad logo --------------------------------------------------------------
387 // verify that my pilot pic is valid
389 if(strlen(Net_player->player->squad_filename)){
390 bmap = bm_load(Net_player->player->squad_filename);
396 // verify image dimensions
399 bm_get_info(bmap,&w,&h);
401 // release the bitmap
405 // if the dimensions are invalid, kill the filename
406 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
415 with_ext = cf_add_ext(Net_player->player->squad_filename, NOX(".pcx"));
416 if(with_ext != NULL){
417 strcpy(Net_player->player->squad_filename,with_ext);
420 // host should put his own pic file in the list now
421 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->squad_filename) > 0)){
422 multi_data_add_new(Net_player->player->squad_filename, MY_NET_PLAYER_NUM);
424 // otherwise clients should just queue up a send
426 // add a file extension if necessary
427 multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
433 // -------------------------------------------------------------------------
434 // MULTI DATA FORWARD DECLARATIONS
437 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
438 int multi_data_is_data(char *filename)
442 Assert(filename != NULL);
444 // some kind of error
445 if(filename == NULL){
449 // convert to lowercase
450 len = strlen(filename);
451 for(idx=0;idx<len;idx++){
452 filename[idx] = (char)tolower(filename[idx]);
455 // check to see if the extension is .pcx
456 if(strstr(filename, NOX(".pcx"))){
464 // get a free np_data slot
465 int multi_data_get_free()
470 for(idx=0; idx<MAX_MULTI_DATA; idx++){
471 if(!Multi_data[idx].used){
480 // server side - add a new file. return 1 on success
481 int multi_data_add_new(char *filename, int player_index)
485 // try and get a free slot
486 slot = multi_data_get_free();
488 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
492 // if the netgame isn't flagged as accepting data files
493 if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
494 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));
499 memset(&Multi_data[slot], 0, sizeof(np_data)); // clear the slot out
500 strcpy(Multi_data[slot].filename, filename); // copy the filename
501 Multi_data[slot].used = 1; // set it as being in use
502 Multi_data[slot].player_id = Net_players[player_index].player_id; // player id of who's sending the file
503 Multi_data[slot].status[player_index] = 2; // mark his status appropriately
509 // maybe try and reload player squad logo bitmaps
510 void multi_data_maybe_reload()
514 // go through all connected and try to reload their images if necessary
515 for(idx=0; idx<MAX_PLAYERS; idx++){
516 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].player->squad_filename) && (Net_players[idx].player->insignia_texture == -1)){
517 Net_players[idx].player->insignia_texture = bm_load_duplicate(Net_players[idx].player->squad_filename);
519 // if the bitmap loaded properly, lock it as a transparent texture
520 if(Net_players[idx].player->insignia_texture != -1){
521 bm_lock(Net_players[idx].player->insignia_texture, 16, BMP_TEX_XPARENT);
522 bm_unlock(Net_players[idx].player->insignia_texture);