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