2 * $Logfile: /Freespace2/code/Network/multi_data.cpp $
8 * Revision 1.3 2002/05/26 20:22:48 theoddone33
9 * Most of network/ works
11 * Revision 1.2 2002/05/07 03:16:47 theoddone33
12 * The Great Newline Fix
14 * Revision 1.1.1.1 2002/05/03 03:28:10 root
18 * 8 6/16/99 4:06p Dave
19 * New pilot info popup. Added new draw-bitmap-as-poly function.
21 * 7 1/21/99 2:06p Dave
22 * Final checkin for multiplayer testing.
24 * 6 1/14/99 6:06p Dave
25 * 100% full squad logo support for single player and multiplayer.
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.
31 * 4 12/14/98 4:01p Dave
32 * Got multi_data stuff working well with new xfer stuff.
34 * 3 12/14/98 12:13p Dave
35 * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
38 * 2 10/07/98 10:53a Dave
41 * 1 10/07/98 10:50a Dave
43 * 19 6/13/98 3:18p Hoffoss
44 * NOX()ed out a bunch of strings that shouldn't be translated.
46 * 18 5/21/98 3:45a Sandeep
47 * Make sure file xfer sender side uses correct directory type.
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.
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
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.
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.
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
73 * 12 4/14/98 12:19p Dave
74 * Revised the pause system yet again. Seperated into its own module.
76 * 11 4/08/98 2:51p Dave
77 * Fixed pilot image xfer once again. Solidify team selection process in
78 * pre-briefing multiplayer.
80 * 10 4/04/98 4:22p Dave
81 * First rev of UDP reliable sockets is done. Seems to work well if not
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.
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.
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.
98 * 6 3/21/98 7:14p Dave
99 * Fixed up standalone player slot switching. Made training missions not
100 * count towards player stats.
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.
106 * 4 3/11/98 2:04p Dave
107 * Removed optimized build warnings.
109 * 3 2/20/98 4:43p Dave
110 * Finished support for multiplayer player data files. Split off
111 * multiplayer campaign functionality.
113 * 2 2/19/98 6:44p Dave
114 * Finished server getting data from players. Now need to rebroadcast the
117 * 1 2/19/98 6:21p Dave
118 * Player data file xfer module.
126 #include "multi_data.h"
127 #include "freespace.h"
128 #include "multi_xfer.h"
130 #include "multimsgs.h"
131 #include "multiutil.h"
134 // -------------------------------------------------------------------------
135 // MULTI DATA DEFINES/VARS
138 #define MAX_MULTI_DATA 40
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
148 np_data Multi_data[MAX_MULTI_DATA];
150 time_t Multi_data_time = 0;
153 // -------------------------------------------------------------------------
154 // MULTI DATA FORWARD DECLARATIONS
157 // is the given filename for a "multi data" file (pcx, wav, etc)
158 int multi_data_is_data(char *filename);
160 // get a free np_data slot
161 int multi_data_get_free();
163 // server side - add a new file
164 int multi_data_add_new(char *filename, int player_index);
166 // maybe try and reload player squad logo bitmaps
167 void multi_data_maybe_reload();
170 // -------------------------------------------------------------------------
171 // MULTI DATA FUNCTIONS
174 // reset the data xfer system
175 void multi_data_reset()
179 // clear out all used bits
180 for(idx=0; idx<MAX_MULTI_DATA; idx++){
181 Multi_data[idx].used = 0;
185 // handle a player join (clear out lists of files, etc)
186 void multi_data_handle_join(int player_index)
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;
196 // handle a player drop (essentially the same as multi_data_handle_join)
197 void multi_data_handle_drop(int player_index)
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;
209 // do all sync related data stuff (server-side only)
214 // only do this once a second
215 if((time(NULL) - Multi_data_time) < 1){
219 // maybe try and reload player squad logo bitmaps
220 multi_data_maybe_reload();
223 Multi_data_time = time(NULL);
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"));
240 Multi_data[idx].status[p_idx] = 1;
249 // handle an incoming xfer request from the xfer system
250 void multi_data_handle_incoming(int handle)
252 int player_index = -1;
253 PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;
256 // get the player who is sending us this file
257 sock = multi_xfer_get_sock(handle);
258 player_index = find_player_socket(sock);
260 // get the filename of the file
261 fname = multi_xfer_get_filename(handle);
263 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
266 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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"));
275 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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"));
285 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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);
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"));
300 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
304 // attempt to add the file
305 if(!multi_data_add_new(fname, player_index)){
307 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
310 // force the file to go into the multi cache directory
311 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
313 // mark it as autodestroy
314 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
317 // if i'm a client, this is an incoming file from the server
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"));
324 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
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);
331 // force the file to go into the multi cache directory
332 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
334 // begin receiving the file
335 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
339 // send all my files as necessary
340 void multi_data_send_my_junk()
346 // pilot pic --------------------------------------------------------------
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);
355 // verify image dimensions
359 bm_get_info(bmap,&w,&h);
361 // release the bitmap
365 // if the dimensions are invalid, kill the filename
366 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
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);
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);
384 // otherwise clients should just queue up a send
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);
392 // squad logo --------------------------------------------------------------
394 // verify that my pilot pic is valid
396 if(strlen(Net_player->player->squad_filename)){
397 bmap = bm_load(Net_player->player->squad_filename);
403 // verify image dimensions
406 bm_get_info(bmap,&w,&h);
408 // release the bitmap
412 // if the dimensions are invalid, kill the filename
413 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
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);
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);
431 // otherwise clients should just queue up a send
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);
440 // -------------------------------------------------------------------------
441 // MULTI DATA FORWARD DECLARATIONS
444 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
445 int multi_data_is_data(char *filename)
449 Assert(filename != NULL);
451 // some kind of error
452 if(filename == NULL){
456 // convert to lowercase
457 len = strlen(filename);
458 for(idx=0;idx<len;idx++){
459 filename[idx] = (char)tolower(filename[idx]);
462 // check to see if the extension is .pcx
463 if(strstr(filename, NOX(".pcx"))){
471 // get a free np_data slot
472 int multi_data_get_free()
477 for(idx=0; idx<MAX_MULTI_DATA; idx++){
478 if(!Multi_data[idx].used){
487 // server side - add a new file. return 1 on success
488 int multi_data_add_new(char *filename, int player_index)
492 // try and get a free slot
493 slot = multi_data_get_free();
495 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
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"));
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
516 // maybe try and reload player squad logo bitmaps
517 void multi_data_maybe_reload()
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);
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);