]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_data.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / network / multi_data.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_data.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.2  2002/05/07 03:16:47  theoddone33
9  * The Great Newline Fix
10  *
11  * Revision 1.1.1.1  2002/05/03 03:28:10  root
12  * Initial import.
13  * 
14  * 
15  * 8     6/16/99 4:06p Dave
16  * New pilot info popup. Added new draw-bitmap-as-poly function.
17  * 
18  * 7     1/21/99 2:06p Dave
19  * Final checkin for multiplayer testing.
20  * 
21  * 6     1/14/99 6:06p Dave
22  * 100% full squad logo support for single player and multiplayer.
23  * 
24  * 5     12/18/98 12:31p Johnson
25  * Fixed a bug where the server would not properly redistribute a data
26  * file that he already had to other players.
27  * 
28  * 4     12/14/98 4:01p Dave
29  * Got multi_data stuff working well with new xfer stuff. 
30  * 
31  * 3     12/14/98 12:13p Dave
32  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
33  * Need to test now.
34  * 
35  * 2     10/07/98 10:53a Dave
36  * Initial checkin.
37  * 
38  * 1     10/07/98 10:50a Dave
39  * 
40  * 19    6/13/98 3:18p Hoffoss
41  * NOX()ed out a bunch of strings that shouldn't be translated.
42  * 
43  * 18    5/21/98 3:45a Sandeep
44  * Make sure file xfer sender side uses correct directory type.
45  * 
46  * 17    5/17/98 6:32p Dave
47  * Make sure clients/servers aren't kicked out of the debriefing when team
48  * captains leave a game. Fixed chatbox off-by-one error. Fixed image
49  * xfer/pilot info popup stuff.
50  * 
51  * 16    5/13/98 6:54p Dave
52  * More sophistication to PXO interface. Changed respawn checking so
53  * there's no window for desynchronization between the server and the
54  * clients.
55  * 
56  * 15    4/30/98 4:53p John
57  * Restructured and cleaned up cfile code.  Added capability to read off
58  * of CD-ROM drive and out of multiple pack files.
59  * 
60  * 14    4/21/98 4:44p Dave
61  * Implement Vasudan ships in multiplayer. Added a debug function to bash
62  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
63  * problem in options screen. 
64  * 
65  * 13    4/16/98 1:55p Dave
66  * Removed unneeded Assert when processing chat packets. Fixed standalone
67  * sequencing bugs. Laid groundwork for join screen server status
68  * icons/text.
69  * 
70  * 12    4/14/98 12:19p Dave
71  * Revised the pause system yet again. Seperated into its own module.
72  * 
73  * 11    4/08/98 2:51p Dave
74  * Fixed pilot image xfer once again. Solidify team selection process in
75  * pre-briefing multiplayer.
76  * 
77  * 10    4/04/98 4:22p Dave
78  * First rev of UDP reliable sockets is done. Seems to work well if not
79  * overly burdened.
80  * 
81  * 9     3/30/98 6:27p Dave
82  * Put in a more official set of multiplayer options, including a system
83  * for distributing netplayer and netgame settings.
84  * 
85  * 8     3/26/98 6:01p Dave
86  * Put in file checksumming routine in cfile. Made pilot pic xferring more
87  * robust. Cut header size of voice data packets in half. Put in
88  * restricted game host query system.
89  * 
90  * 7     3/23/98 5:42p Dave
91  * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
92  * that it can support multiplayer sends/received between client and
93  * server simultaneously.
94  * 
95  * 6     3/21/98 7:14p Dave
96  * Fixed up standalone player slot switching. Made training missions not
97  * count towards player stats.
98  * 
99  * 5     3/15/98 4:17p Dave
100  * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
101  * of network orientation matrices.
102  * 
103  * 4     3/11/98 2:04p Dave
104  * Removed optimized build warnings.
105  * 
106  * 3     2/20/98 4:43p Dave
107  * Finished support for multiplayer player data files. Split off
108  * multiplayer campaign functionality.
109  * 
110  * 2     2/19/98 6:44p Dave
111  * Finished server getting data from players. Now need to rebroadcast the
112  * data.
113  * 
114  * 1     2/19/98 6:21p Dave
115  * Player data file xfer module.
116  * 
117  * $NoKeywords: $
118  */
119
120 #include "bmpman.h"
121 #include "psnet.h"
122 #include "multi_data.h"
123 #include "freespace.h"
124 #include "multi_xfer.h"
125 #include "multi.h"
126 #include "multimsgs.h"
127 #include "multiutil.h"
128 #include "player.h"
129
130 // -------------------------------------------------------------------------
131 // MULTI DATA DEFINES/VARS
132 //
133
134 #define MAX_MULTI_DATA                                  40
135
136 // player data struct
137 typedef struct np_data {
138         char filename[MAX_FILENAME_LEN+1];                      // filename
139         ubyte status[MAX_PLAYERS];                                              // status for all players (0 == don't have it, 1 == have or sending, 2 == i sent it originally)
140         ushort player_id;                                                                       // id of the player who sent the file
141         ubyte used;                                                                                     // in use or not
142 } np_data;
143
144 np_data Multi_data[MAX_MULTI_DATA];
145
146 time_t Multi_data_time = 0;
147
148
149 // -------------------------------------------------------------------------
150 // MULTI DATA FORWARD DECLARATIONS
151 //
152
153 // is the given filename for a "multi data" file (pcx, wav, etc)
154 int multi_data_is_data(char *filename);
155
156 // get a free np_data slot
157 int multi_data_get_free();
158
159 // server side - add a new file
160 int multi_data_add_new(char *filename, int player_index);
161
162 // maybe try and reload player squad logo bitmaps
163 void multi_data_maybe_reload();
164
165
166 // -------------------------------------------------------------------------
167 // MULTI DATA FUNCTIONS
168 //
169
170 // reset the data xfer system
171 void multi_data_reset()
172 {               
173         int idx;
174
175         // clear out all used bits
176         for(idx=0; idx<MAX_MULTI_DATA; idx++){
177                 Multi_data[idx].used = 0;
178         }
179 }
180
181 // handle a player join (clear out lists of files, etc)
182 void multi_data_handle_join(int player_index)
183 {
184         int idx;
185         
186         // clear out his status for all files           
187         for(idx=0;idx<MAX_MULTI_DATA;idx++){
188                 Multi_data[idx].status[player_index] = 0;
189         }
190 }
191
192 // handle a player drop (essentially the same as multi_data_handle_join)
193 void multi_data_handle_drop(int player_index)
194 {
195         int idx;
196                 
197         // mark all files he sent as being unused
198         for(idx=0;idx<MAX_MULTI_DATA;idx++){
199                 if(Multi_data[idx].player_id == Net_players[player_index].player_id){
200                         Multi_data[idx].used = 0;
201                 }
202         }
203 }
204
205 // do all sync related data stuff (server-side only)
206 void multi_data_do()
207 {               
208         int idx, p_idx;
209
210         // only do this once a second
211         if((time(NULL) - Multi_data_time) < 1){         
212                 return;
213         }
214
215         // maybe try and reload player squad logo bitmaps
216         multi_data_maybe_reload();
217
218         // reset the time
219         Multi_data_time = time(NULL);
220
221         // if I'm the server
222         if(Net_player && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
223                 // for all valid files
224                 for(idx=0; idx<MAX_MULTI_DATA; idx++){
225                         // a valid file that isn't currently xferring (ie, anything we've got completely on our hard drive)
226                         if(Multi_data[idx].used && (multi_xfer_lookup(Multi_data[idx].filename) < 0)){
227                                 // send it to all players who need it
228                                 for(p_idx=0; p_idx<MAX_PLAYERS; p_idx++){
229                                         // if he doesn't have it
230                                         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)){                                               
231                                                 // queue up the file to send to him, or at least try to
232                                                 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){
233                                                         nprintf(("Network", "Failed to send data file! Trying again later...\n"));
234                                                 } else {
235                                                         // mark his status
236                                                         Multi_data[idx].status[p_idx] = 1;
237                                                 }
238                                         }
239                                 }
240                         }
241                 }
242         }
243 }
244
245 // handle an incoming xfer request from the xfer system
246 void multi_data_handle_incoming(int handle)
247 {       
248         int player_index = -1;
249         PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;    
250         char *fname;            
251
252         // get the player who is sending us this file   
253         sock = multi_xfer_get_sock(handle);
254         player_index = find_player_socket(sock);
255
256         // get the filename of the file
257         fname = multi_xfer_get_filename(handle);
258         if(fname == NULL){
259                 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
260
261                 // kill the stream
262                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
263                 return;
264         }
265
266         // if this is not a valid data file
267         if(!multi_data_is_data(fname)){
268                 nprintf(("Network", "Not accepting xfer request because its not a valid data file!\n"));
269                 
270                 // kill the stream              
271                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
272                 return;
273         }       
274
275         // if we already have a copy of this file, abort the xfer               
276         // Does file exist in \multidata?
277         if( cf_exist(fname, CF_TYPE_MULTI_CACHE) ){                     
278                 nprintf(("Network", "Not accepting file xfer because a duplicate exists!\n"));                  
279         
280                 // kill the stream              
281                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
282
283                 // if we're the server, we still need to add it to the list though
284                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_index >= 0)){
285                         multi_data_add_new(fname, player_index);
286                 }
287                 return;
288         }       
289         
290         // if I'm the server of the game, do stuff a little differently
291         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
292                 if(player_index == -1){
293                         nprintf(("Network", "Could not find player for incoming player data stream!\n"));
294
295                         // kill the stream
296                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
297                         return;
298                 }       
299
300                 // attempt to add the file
301                 if(!multi_data_add_new(fname, player_index)){
302                         // kill the stream
303                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
304                         return;
305                 } else {
306                         // force the file to go into the multi cache directory
307                         multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
308                         
309                         // mark it as autodestroy                       
310                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
311                 }
312         }
313         // if i'm a client, this is an incoming file from the server
314         else {
315                 // if i'm not accepting pilot pics, abort
316                 if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX)){
317                         nprintf(("Network", "Client not accepting files because we don't want 'em!\n"));
318
319                         // kill the stream              
320                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
321                         return;
322                 }
323
324                 // set the xfer handle to autodestroy itself since we don't really want to have to manage all incoming pics
325                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
326                 
327                 // force the file to go into the multi cache directory
328                 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
329
330                 // begin receiving the file
331                 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
332         }               
333 }
334
335 // send all my files as necessary
336 void multi_data_send_my_junk()
337 {               
338         char *with_ext; 
339         int bmap, w, h;
340         int ok_to_send = 1;
341
342         // pilot pic --------------------------------------------------------------
343
344         // verify that my pilot pic is valid
345         if(strlen(Net_player->player->image_filename)){
346                 bmap = bm_load(Net_player->player->image_filename);
347                 if(bmap == -1){                 
348                         ok_to_send = 0;
349                 }
350
351                 // verify image dimensions
352                 if(ok_to_send){
353                         w = -1;
354                         h = -1;
355                         bm_get_info(bmap,&w,&h);
356
357                         // release the bitmap
358                         bm_release(bmap);
359                         bmap = -1;
360
361                         // if the dimensions are invalid, kill the filename
362                         if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
363                                 ok_to_send = 0;
364                         }
365                 }
366         } else {                
367                 ok_to_send = 0;
368         }
369
370         if(ok_to_send){
371                 with_ext = cf_add_ext(Net_player->player->image_filename, NOX(".pcx"));
372                 if(with_ext != NULL){
373                         strcpy(Net_player->player->image_filename, with_ext);
374                 }
375
376                 // host should put his own pic file in the list now
377                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->image_filename) > 0)){
378                         multi_data_add_new(Net_player->player->image_filename, MY_NET_PLAYER_NUM);
379                 }
380                 // otherwise clients should just queue up a send
381                 else {
382                         // add a file extension if necessary                    
383                         multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
384                 }               
385         }
386
387
388         // squad logo --------------------------------------------------------------
389
390         // verify that my pilot pic is valid
391         ok_to_send = 1;
392         if(strlen(Net_player->player->squad_filename)){
393                 bmap = bm_load(Net_player->player->squad_filename);
394                 if(bmap == -1){                 
395                         ok_to_send = 0;
396                 }
397
398                 if(ok_to_send){
399                         // verify image dimensions
400                         w = -1;
401                         h = -1;
402                         bm_get_info(bmap,&w,&h);
403
404                         // release the bitmap
405                         bm_release(bmap);
406                         bmap = -1;
407
408                         // if the dimensions are invalid, kill the filename
409                         if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
410                                 ok_to_send = 0;
411                         }
412                 }
413         } else {                
414                 ok_to_send = 0;
415         }
416
417         if(ok_to_send){
418                 with_ext = cf_add_ext(Net_player->player->squad_filename, NOX(".pcx"));
419                 if(with_ext != NULL){
420                         strcpy(Net_player->player->squad_filename,with_ext);
421                 }
422
423                 // host should put his own pic file in the list now
424                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->squad_filename) > 0)){
425                         multi_data_add_new(Net_player->player->squad_filename, MY_NET_PLAYER_NUM);
426                 }
427                 // otherwise clients should just queue up a send
428                 else {
429                         // add a file extension if necessary                    
430                         multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
431                 }               
432         }
433 }
434
435
436 // -------------------------------------------------------------------------
437 // MULTI DATA FORWARD DECLARATIONS
438 //
439
440 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
441 int multi_data_is_data(char *filename)
442 {               
443         int len,idx;
444
445         Assert(filename != NULL);
446
447         // some kind of error
448         if(filename == NULL){
449                 return 0;
450         }
451
452         // convert to lowercase
453         len = strlen(filename);
454         for(idx=0;idx<len;idx++){
455                 filename[idx] = (char)tolower(filename[idx]);
456         }
457
458         // check to see if the extension is .pcx
459         if(strstr(filename, NOX(".pcx"))){
460                 return 1;
461         }
462
463         // not a data file
464         return 0;
465 }
466
467 // get a free np_data slot
468 int multi_data_get_free()
469 {
470         int idx;
471
472         // find a free slot
473         for(idx=0; idx<MAX_MULTI_DATA; idx++){
474                 if(!Multi_data[idx].used){
475                         return idx;
476                 }
477         }
478
479         // couldn't find one
480         return -1;
481 }
482
483 // server side - add a new file. return 1 on success
484 int multi_data_add_new(char *filename, int player_index)
485 {       
486         int slot;
487                 
488         // try and get a free slot
489         slot = multi_data_get_free();
490         if(slot < 0){
491                 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));              
492                 return 0;
493         }
494
495         // if the netgame isn't flagged as accepting data files
496         if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
497                 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));    
498                 return 0;
499         }                       
500
501         // assign the data
502         memset(&Multi_data[slot], 0, sizeof(np_data));                                                          // clear the slot out
503         strcpy(Multi_data[slot].filename, filename);                                                                    // copy the filename
504         Multi_data[slot].used = 1;                                                                                                                      // set it as being in use
505         Multi_data[slot].player_id = Net_players[player_index].player_id;               // player id of who's sending the file
506         Multi_data[slot].status[player_index] = 2;                                                                      // mark his status appropriately
507
508         // success
509         return 1;
510 }
511
512 // maybe try and reload player squad logo bitmaps
513 void multi_data_maybe_reload()
514 {
515         int idx;
516
517         // go through all connected and try to reload their images if necessary
518         for(idx=0; idx<MAX_PLAYERS; idx++){
519                 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].player->squad_filename) && (Net_players[idx].player->insignia_texture == -1)){
520                         Net_players[idx].player->insignia_texture = bm_load_duplicate(Net_players[idx].player->squad_filename);
521
522                         // if the bitmap loaded properly, lock it as a transparent texture
523                         if(Net_players[idx].player->insignia_texture != -1){
524                                 bm_lock(Net_players[idx].player->insignia_texture, 16, BMP_TEX_XPARENT);
525                                 bm_unlock(Net_players[idx].player->insignia_texture);
526                         }
527                 }
528         }       
529 }