1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12
13 #include <ctime>
14 #include <cctype>
15
16 #include "network/multi.h"
17 #include "network/multi_data.h"
18 #include "network/multi_xfer.h"
19 #include "network/multiutil.h"
20 #include "playerman/player.h"
21 #include "cfile/cfile.h"
22 #include "globalincs/systemvars.h"
23
24
25
26 // -------------------------------------------------------------------------
27 // MULTI DATA DEFINES/VARS
28 //
29
30 #define MAX_MULTI_DATA 40
31
32 // player data struct
33 typedef struct np_data {
34 ushort player_id; // id of the player who sent the file
35 char filename[MAX_FILENAME_LEN+1]; // filename
36 ubyte status[MAX_PLAYERS]; // status for all players (0 == don't have it, 1 == have or sending, 2 == i sent it originally)
37 ubyte used; // in use or not
38 } np_data;
39
40 np_data Multi_data[MAX_MULTI_DATA];
41
42 // this doesn't travel off platform to don't _fs_time_t it
43 time_t Multi_data_time = 0;
44
45
46 // -------------------------------------------------------------------------
47 // MULTI DATA FORWARD DECLARATIONS
48 //
49
50 // is the given filename for a "multi data" file (pcx, wav, etc)
51 int multi_data_is_data(char *filename);
52
53 // get a free np_data slot
54 int multi_data_get_free();
55
56 // server side - add a new file
57 int multi_data_add_new(char *filename, int player_index);
58
59 // maybe try and reload player squad logo bitmaps
60 void multi_data_maybe_reload();
61
62
63 // -------------------------------------------------------------------------
64 // MULTI DATA FUNCTIONS
65 //
66
67 // reset the data xfer system
multi_data_reset()68 void multi_data_reset()
69 {
70 int idx;
71
72 // clear out all used bits
73 for(idx=0; idx<MAX_MULTI_DATA; idx++){
74 Multi_data[idx].used = 0;
75 }
76 }
77
78 // handle a player join (clear out lists of files, etc)
multi_data_handle_join(int player_index)79 void multi_data_handle_join(int player_index)
80 {
81 int idx;
82
83 // clear out his status for all files
84 for(idx=0;idx<MAX_MULTI_DATA;idx++){
85 Multi_data[idx].status[player_index] = 0;
86 }
87 }
88
89 // handle a player drop (essentially the same as multi_data_handle_join)
multi_data_handle_drop(int player_index)90 void multi_data_handle_drop(int player_index)
91 {
92 int idx;
93
94 // mark all files he sent as being unused
95 for(idx=0;idx<MAX_MULTI_DATA;idx++){
96 if(Multi_data[idx].player_id == Net_players[player_index].player_id){
97 Multi_data[idx].used = 0;
98 }
99 }
100 }
101
102 // do all sync related data stuff (server-side only)
multi_data_do()103 void multi_data_do()
104 {
105 int idx, p_idx;
106
107 // only do this once a second
108 if((time(NULL) - Multi_data_time) < 1){
109 return;
110 }
111
112 // maybe try and reload player squad logo bitmaps
113 multi_data_maybe_reload();
114
115 // reset the time
116 Multi_data_time = time(NULL);
117
118 // if I'm the server
119 if(Net_player && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
120 // for all valid files
121 for(idx=0; idx<MAX_MULTI_DATA; idx++){
122 // a valid file that isn't currently xferring (ie, anything we've got completely on our hard drive)
123 if(Multi_data[idx].used && (multi_xfer_lookup(Multi_data[idx].filename) < 0)){
124 // send it to all players who need it
125 for(p_idx=0; p_idx<MAX_PLAYERS; p_idx++){
126 // if he doesn't have it
127 if ( (Net_player != &Net_players[p_idx]) && MULTI_CONNECTED(Net_players[p_idx]) && (Net_players[p_idx].reliable_socket != PSNET_INVALID_SOCKET) && (Multi_data[idx].status[p_idx] == 0) ) {
128 // queue up the file to send to him, or at least try to
129 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){
130 nprintf(("Network", "Failed to send data file! Trying again later...\n"));
131 } else {
132 // mark his status
133 Multi_data[idx].status[p_idx] = 1;
134 }
135 }
136 }
137 }
138 }
139 }
140 }
141
142 // handle an incoming xfer request from the xfer system
multi_data_handle_incoming(int handle)143 void multi_data_handle_incoming(int handle)
144 {
145 int player_index = -1;
146 PSNET_SOCKET_RELIABLE sock;
147 char *fname;
148
149 // get the player who is sending us this file
150 sock = multi_xfer_get_sock(handle);
151 player_index = find_player_socket(sock);
152
153 // get the filename of the file
154 fname = multi_xfer_get_filename(handle);
155 if(fname == NULL){
156 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
157
158 // kill the stream
159 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
160 return;
161 }
162
163 // if this is not a valid data file
164 if(!multi_data_is_data(fname)){
165 nprintf(("Network", "Not accepting xfer request because its not a valid data file!\n"));
166
167 // kill the stream
168 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
169 return;
170 }
171
172 // if we already have a copy of this file, abort the xfer
173 // Does file exist in \multidata?
174 if (cf_exists(fname, CF_TYPE_MULTI_CACHE)) {
175 nprintf(("Network", "Not accepting file xfer because a duplicate exists!\n"));
176
177 // kill the stream
178 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
179
180 // if we're the server, we still need to add it to the list though
181 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_index >= 0)){
182 multi_data_add_new(fname, player_index);
183 }
184 return;
185 }
186
187 // if I'm the server of the game, do stuff a little differently
188 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
189 if(player_index == -1){
190 nprintf(("Network", "Could not find player for incoming player data stream!\n"));
191
192 // kill the stream
193 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
194 return;
195 }
196
197 // attempt to add the file
198 if(!multi_data_add_new(fname, player_index)){
199 // kill the stream
200 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
201 return;
202 } else {
203 // force the file to go into the multi cache directory
204 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
205
206 // mark it as autodestroy
207 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
208 }
209 }
210 // if i'm a client, this is an incoming file from the server
211 else {
212 // if i'm not accepting pilot pics, abort
213 if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX)){
214 nprintf(("Network", "Client not accepting files because we don't want 'em!\n"));
215
216 // kill the stream
217 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
218 return;
219 }
220
221 // set the xfer handle to autodestroy itself since we don't really want to have to manage all incoming pics
222 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
223
224 // force the file to go into the multi cache directory
225 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
226
227 // begin receiving the file
228 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
229 }
230 }
231
232 // send all my files as necessary
multi_data_send_my_junk()233 void multi_data_send_my_junk()
234 {
235 char *with_ext;
236 int bmap, w, h;
237 int ok_to_send = 1;
238
239 // pilot pic --------------------------------------------------------------
240
241 // verify that my pilot pic is valid
242 if(strlen(Net_player->m_player->image_filename)){
243 bmap = bm_load(Net_player->m_player->image_filename);
244 if(bmap == -1){
245 ok_to_send = 0;
246 }
247
248 // verify image dimensions
249 if(ok_to_send){
250 w = -1;
251 h = -1;
252 bm_get_info(bmap,&w,&h);
253
254 // release the bitmap
255 bm_release(bmap);
256 bmap = -1;
257
258 // if the dimensions are invalid, kill the filename
259 if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
260 ok_to_send = 0;
261 }
262 }
263 } else {
264 ok_to_send = 0;
265 }
266
267 if(ok_to_send){
268 with_ext = cf_add_ext(Net_player->m_player->image_filename, NOX(".pcx"));
269 if(with_ext != NULL){
270 strcpy_s(Net_player->m_player->image_filename, with_ext);
271 }
272
273 // host should put his own pic file in the list now
274 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (Net_player->m_player->image_filename[0] != '\0')){
275 multi_data_add_new(Net_player->m_player->image_filename, MY_NET_PLAYER_NUM);
276 }
277 // otherwise clients should just queue up a send
278 else {
279 // add a file extension if necessary
280 multi_xfer_send_file(Net_player->reliable_socket, Net_player->m_player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
281 }
282 }
283
284
285 // squad logo --------------------------------------------------------------
286
287 // verify that my pilot pic is valid
288 ok_to_send = 1;
289 if(strlen(Net_player->m_player->m_squad_filename)){
290 bmap = bm_load(Net_player->m_player->m_squad_filename);
291 if(bmap == -1){
292 ok_to_send = 0;
293 }
294
295 if(ok_to_send){
296 // verify image dimensions
297 w = -1;
298 h = -1;
299 bm_get_info(bmap,&w,&h);
300
301 // release the bitmap
302 bm_release(bmap);
303 bmap = -1;
304
305 // if the dimensions are invalid, kill the filename
306 if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
307 ok_to_send = 0;
308 }
309 }
310 } else {
311 ok_to_send = 0;
312 }
313
314 if(ok_to_send){
315 with_ext = cf_add_ext(Net_player->m_player->m_squad_filename, NOX(".pcx"));
316 if(with_ext != NULL){
317 strcpy_s(Net_player->m_player->m_squad_filename,with_ext);
318 }
319
320 // host should put his own pic file in the list now
321 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (Net_player->m_player->m_squad_filename[0] != '\0')){
322 multi_data_add_new(Net_player->m_player->m_squad_filename, MY_NET_PLAYER_NUM);
323 }
324 // otherwise clients should just queue up a send
325 else {
326 // add a file extension if necessary
327 multi_xfer_send_file(Net_player->reliable_socket, Net_player->m_player->m_squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
328 }
329 }
330 }
331
332
333 // -------------------------------------------------------------------------
334 // MULTI DATA FORWARD DECLARATIONS
335 //
336
337 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
multi_data_is_data(char * filename)338 int multi_data_is_data(char *filename)
339 {
340 Assert(filename != NULL);
341
342 // some kind of error
343 if(filename == NULL){
344 return 0;
345 }
346
347 // convert to lowercase
348 SCP_tolower(filename);
349
350 // check to see if the extension is .pcx
351 if(strstr(filename, NOX(".pcx"))){
352 return 1;
353 }
354
355 // not a data file
356 return 0;
357 }
358
359 // get a free np_data slot
multi_data_get_free()360 int multi_data_get_free()
361 {
362 int idx;
363
364 // find a free slot
365 for(idx=0; idx<MAX_MULTI_DATA; idx++){
366 if(!Multi_data[idx].used){
367 return idx;
368 }
369 }
370
371 // couldn't find one
372 return -1;
373 }
374
375 // server side - add a new file. return 1 on success
multi_data_add_new(char * filename,int player_index)376 int multi_data_add_new(char *filename, int player_index)
377 {
378 int slot;
379
380 // try and get a free slot
381 slot = multi_data_get_free();
382 if(slot < 0){
383 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));
384 return 0;
385 }
386
387 // if the netgame isn't flagged as accepting data files
388 if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
389 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));
390 return 0;
391 }
392
393 // assign the data
394 memset(&Multi_data[slot], 0, sizeof(np_data)); // clear the slot out
395 strcpy_s(Multi_data[slot].filename, filename); // copy the filename
396 Multi_data[slot].used = 1; // set it as being in use
397 Multi_data[slot].player_id = Net_players[player_index].player_id; // player id of who's sending the file
398 Multi_data[slot].status[player_index] = 2; // mark his status appropriately
399
400 // success
401 return 1;
402 }
403
404 // maybe try and reload player squad logo bitmaps
multi_data_maybe_reload()405 void multi_data_maybe_reload()
406 {
407 int idx;
408
409 // go through all connected and try to reload their images if necessary
410 for(idx=0; idx<MAX_PLAYERS; idx++){
411 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].m_player->m_squad_filename) && (Net_players[idx].m_player->insignia_texture == -1)){
412 Net_players[idx].m_player->insignia_texture = bm_load_duplicate(Net_players[idx].m_player->m_squad_filename);
413
414 // if the bitmap loaded properly, lock it as a transparent texture
415 if(Net_players[idx].m_player->insignia_texture != -1){
416 bm_lock(Net_players[idx].m_player->insignia_texture, 16, BMP_TEX_XPARENT);
417 bm_unlock(Net_players[idx].m_player->insignia_texture);
418 }
419 }
420 }
421 }
422