2 * $Logfile: /Freespace2/code/Network/multi_data.cpp $
8 * Revision 1.2 2002/05/07 03:16:47 theoddone33
9 * The Great Newline Fix
11 * Revision 1.1.1.1 2002/05/03 03:28:10 root
15 * 8 6/16/99 4:06p Dave
16 * New pilot info popup. Added new draw-bitmap-as-poly function.
18 * 7 1/21/99 2:06p Dave
19 * Final checkin for multiplayer testing.
21 * 6 1/14/99 6:06p Dave
22 * 100% full squad logo support for single player and multiplayer.
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.
28 * 4 12/14/98 4:01p Dave
29 * Got multi_data stuff working well with new xfer stuff.
31 * 3 12/14/98 12:13p Dave
32 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
35 * 2 10/07/98 10:53a Dave
38 * 1 10/07/98 10:50a Dave
40 * 19 6/13/98 3:18p Hoffoss
41 * NOX()ed out a bunch of strings that shouldn't be translated.
43 * 18 5/21/98 3:45a Sandeep
44 * Make sure file xfer sender side uses correct directory type.
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.
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
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.
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.
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
70 * 12 4/14/98 12:19p Dave
71 * Revised the pause system yet again. Seperated into its own module.
73 * 11 4/08/98 2:51p Dave
74 * Fixed pilot image xfer once again. Solidify team selection process in
75 * pre-briefing multiplayer.
77 * 10 4/04/98 4:22p Dave
78 * First rev of UDP reliable sockets is done. Seems to work well if not
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.
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.
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.
95 * 6 3/21/98 7:14p Dave
96 * Fixed up standalone player slot switching. Made training missions not
97 * count towards player stats.
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.
103 * 4 3/11/98 2:04p Dave
104 * Removed optimized build warnings.
106 * 3 2/20/98 4:43p Dave
107 * Finished support for multiplayer player data files. Split off
108 * multiplayer campaign functionality.
110 * 2 2/19/98 6:44p Dave
111 * Finished server getting data from players. Now need to rebroadcast the
114 * 1 2/19/98 6:21p Dave
115 * Player data file xfer module.
122 #include "multi_data.h"
123 #include "freespace.h"
124 #include "multi_xfer.h"
126 #include "multimsgs.h"
127 #include "multiutil.h"
130 // -------------------------------------------------------------------------
131 // MULTI DATA DEFINES/VARS
134 #define MAX_MULTI_DATA 40
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
144 np_data Multi_data[MAX_MULTI_DATA];
146 time_t Multi_data_time = 0;
149 // -------------------------------------------------------------------------
150 // MULTI DATA FORWARD DECLARATIONS
153 // is the given filename for a "multi data" file (pcx, wav, etc)
154 int multi_data_is_data(char *filename);
156 // get a free np_data slot
157 int multi_data_get_free();
159 // server side - add a new file
160 int multi_data_add_new(char *filename, int player_index);
162 // maybe try and reload player squad logo bitmaps
163 void multi_data_maybe_reload();
166 // -------------------------------------------------------------------------
167 // MULTI DATA FUNCTIONS
170 // reset the data xfer system
171 void multi_data_reset()
175 // clear out all used bits
176 for(idx=0; idx<MAX_MULTI_DATA; idx++){
177 Multi_data[idx].used = 0;
181 // handle a player join (clear out lists of files, etc)
182 void multi_data_handle_join(int player_index)
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;
192 // handle a player drop (essentially the same as multi_data_handle_join)
193 void multi_data_handle_drop(int player_index)
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;
205 // do all sync related data stuff (server-side only)
210 // only do this once a second
211 if((time(NULL) - Multi_data_time) < 1){
215 // maybe try and reload player squad logo bitmaps
216 multi_data_maybe_reload();
219 Multi_data_time = time(NULL);
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"));
236 Multi_data[idx].status[p_idx] = 1;
245 // handle an incoming xfer request from the xfer system
246 void multi_data_handle_incoming(int handle)
248 int player_index = -1;
249 PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
252 // get the player who is sending us this file
253 sock = multi_xfer_get_sock(handle);
254 player_index = find_player_socket(sock);
256 // get the filename of the file
257 fname = multi_xfer_get_filename(handle);
259 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
262 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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"));
271 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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"));
281 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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);
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"));
296 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
300 // attempt to add the file
301 if(!multi_data_add_new(fname, player_index)){
303 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
306 // force the file to go into the multi cache directory
307 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
309 // mark it as autodestroy
310 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
313 // if i'm a client, this is an incoming file from the server
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"));
320 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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);
327 // force the file to go into the multi cache directory
328 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
330 // begin receiving the file
331 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
335 // send all my files as necessary
336 void multi_data_send_my_junk()
342 // pilot pic --------------------------------------------------------------
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);
351 // verify image dimensions
355 bm_get_info(bmap,&w,&h);
357 // release the bitmap
361 // if the dimensions are invalid, kill the filename
362 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
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);
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);
380 // otherwise clients should just queue up a send
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);
388 // squad logo --------------------------------------------------------------
390 // verify that my pilot pic is valid
392 if(strlen(Net_player->player->squad_filename)){
393 bmap = bm_load(Net_player->player->squad_filename);
399 // verify image dimensions
402 bm_get_info(bmap,&w,&h);
404 // release the bitmap
408 // if the dimensions are invalid, kill the filename
409 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
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);
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);
427 // otherwise clients should just queue up a send
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);
436 // -------------------------------------------------------------------------
437 // MULTI DATA FORWARD DECLARATIONS
440 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
441 int multi_data_is_data(char *filename)
445 Assert(filename != NULL);
447 // some kind of error
448 if(filename == NULL){
452 // convert to lowercase
453 len = strlen(filename);
454 for(idx=0;idx<len;idx++){
455 filename[idx] = (char)tolower(filename[idx]);
458 // check to see if the extension is .pcx
459 if(strstr(filename, NOX(".pcx"))){
467 // get a free np_data slot
468 int multi_data_get_free()
473 for(idx=0; idx<MAX_MULTI_DATA; idx++){
474 if(!Multi_data[idx].used){
483 // server side - add a new file. return 1 on success
484 int multi_data_add_new(char *filename, int player_index)
488 // try and get a free slot
489 slot = multi_data_get_free();
491 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
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"));
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
512 // maybe try and reload player squad logo bitmaps
513 void multi_data_maybe_reload()
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);
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);