1 //********************************************************************************************
2 //*
3 //* This file is part of Egoboo.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file network.c
21 /// @brief Egoboo networking implementation
22 /// @details Shuttles bits across the network, using Enet. Networked play doesn't
23 /// really work at the moment.
24
25 #include "network.h"
26
27 #include "file_common.h"
28 #include "log.h"
29 #include "input.h"
30 #include "char.inl"
31 #include "module_file.h"
32 #include "game.h"
33 #include "menu.h"
34
35 #include "egoboo_strutil.h"
36 #include "egoboo_vfs.h"
37 #include "egoboo_setup.h"
38 #include "egoboo.h"
39
40 #include "enet/enet.h"
41 #include "file_common.h"
42
43 #include <stdarg.h>
44 #include "egoboo_mem.h"
45
46 //--------------------------------------------------------------------------------------------
47 //--------------------------------------------------------------------------------------------
48 static int numfile = 0; // For network copy
49 static int numfilesent = 0; // For network copy
50 static int numfileexpected = 0; // For network copy
51 static int numplayerrespond = 0;
52
53 static net_instance_t gnet = { bfalse, bfalse, bfalse, bfalse, bfalse };
54
55 static bool_t net_instance_init( net_instance_t * pnet );
56
57 //--------------------------------------------------------------------------------------------
58 //--------------------------------------------------------------------------------------------
59 INSTANTIATE_STACK( ACCESS_TYPE_NONE, player_t, PlaStack, MAX_PLAYER );
60
61 int lag = 3; // Lag tolerance
62 Uint32 numplatimes = 0;
63
64 int local_numlpla; // number of players on the local machine
65
66 FILE * globalnetworkerr = NULL;
67
68 int networkservice;
69 int numservice = 0;
70 char netservicename[MAXSERVICE][NETNAMESIZE];
71 int numsession = 0;
72 char netsessionname[MAXSESSION][NETNAMESIZE];
73 int numplayer = 0;
74 char netplayername[MAXNETPLAYER][NETNAMESIZE];
75
76 int local_machine = 0; // 0 is host, 1 is 1st remote, 2 is 2nd...
77
78 int playersready = 0; // Number of players ready to start
79 int playersloaded = 0;
80
81 Uint32 sv_last_frame = ( Uint32 )~0;
82
83 net_instance_t * PNet = &gnet;
84
85 //--------------------------------------------------------------------------------------------
86 //--------------------------------------------------------------------------------------------
87
88 /// Networking constants
89 enum NetworkConstant
90 {
91 NET_UNRELIABLE_CHANNEL = 0,
92 NET_GUARANTEED_CHANNEL = 1,
93 NET_EGOBOO_NUM_CHANNELS,
94 NET_EGOBOO_PORT = 34626,
95 NET_MAX_FILE_NAME = 128,
96 NET_MAX_FILE_TRANSFERS = 1024 // Maximum files queued up at once
97 };
98
99 /// All the supported network messages
100 enum NetworkMessage
101 {
102 NET_TRANSFER_FILE = 10001, // Packet contains a file.
103 NET_TRANSFER_OK = 10002, // Acknowledgement packet for a file send
104 NET_CREATE_DIRECTORY = 10003, // Tell the peer to create the named directory
105 NET_DONE_SENDING_FILES = 10009, // Sent when there are no more files to send.
106 NET_NUM_FILES_TO_SEND = 10010 // Let the other person know how many files you're sending
107 };
108
109 /// Network information on connected players
110 typedef struct NetPlayerInfo
111 {
112 int playerSlot;
113 } NetPlayerInfo;
114
115 //--------------------------------------------------------------------------------------------
116 //--------------------------------------------------------------------------------------------
117
118 Uint32 nexttimestamp; // Expected timestamp
119
120 // ENet host & client identifiers
121 static ENetHost* net_myHost = NULL;
122 static ENetPeer* net_gameHost = NULL;
123 static ENetPeer* net_playerPeers[MAX_PLAYER];
124 static NetPlayerInfo net_playerInfo[MAXNETPLAYER];
125
126 static bool_t net_amHost = bfalse;
127
128 // Packet reading
129 static ENetPacket* net_readPacket = NULL;
130 static size_t net_readLocation = 0;
131
132 // Packet writing
133 static Uint32 packethead; // The write head
134 static Uint32 packetsize; // The size of the packet
135 static Uint8 packetbuffer[MAXSENDSIZE]; // The data packet
136
137 /// Data for network file transfers
138 typedef struct NetFileTransfer
139 {
140 char sourceName[NET_MAX_FILE_NAME];
141 char destName[NET_MAX_FILE_NAME];
142 ENetPeer *target;
143 } NetFileTransfer;
144
145 /// Network file transfer queue
146 static NetFileTransfer net_transferStates[NET_MAX_FILE_TRANSFERS];
147 static int net_numFileTransfers = 0; ///< Queue count
148 static int net_fileTransferHead = 0; ///< Queue start indicx
149 static int net_fileTransferTail = 0; ///< Queue end index
150 static int net_waitingForXferAck = 0; ///< Queue state
151
152 static Uint8 * transferBuffer = NULL;
153 static size_t transferSize = 0;
154
155 // Receiving files
156 static NetFileTransfer net_receiveState;
157
158 //--------------------------------------------------------------------------------------------
159 //--------------------------------------------------------------------------------------------
close_session()160 void close_session()
161 {
162 size_t i, numPeers;
163 ENetEvent event;
164
165 /// @details ZZ@> This function gets the computer out of a network game
166
167 if ( gnet.on )
168 {
169 if ( net_amHost )
170 {
171 // Disconnect the peers
172 numPeers = net_myHost->peerCount;
173
174 for ( i = 0; i < numPeers; i++ )
175 {
176 #if 1
177 enet_peer_disconnect( &net_myHost->peers[i], 0 );
178 #else
179 enet_peer_disconnect( &net_myHost->peers[i] );
180 #endif
181 }
182
183 // Allow up to 5 seconds for peers to drop
184 while ( enet_host_service( net_myHost, &event, 5000 ) )
185 {
186 switch ( event.type )
187 {
188 case ENET_EVENT_TYPE_RECEIVE:
189 enet_packet_destroy( event.packet );
190 break;
191
192 case ENET_EVENT_TYPE_DISCONNECT:
193 log_info( "close_session: Peer id %d disconnected gracefully.\n", event.peer->address.host );
194 numPeers--;
195 break;
196
197 default:
198 break;
199 }
200 }
201
202 // Forcefully disconnect any peers leftover
203 for ( i = 0; i < net_myHost->peerCount; i++ )
204 {
205 enet_peer_reset( &net_myHost->peers[i] );
206 }
207 }
208
209 log_info( "close_session: Disconnecting from network.\n" );
210 enet_host_destroy( net_myHost );
211 net_myHost = NULL;
212 net_gameHost = NULL;
213 }
214 }
215
216 //--------------------------------------------------------------------------------------------
net_startNewPacket()217 void net_startNewPacket()
218 {
219 /// @details ZZ@> This function starts building a network packet
220
221 packethead = 0;
222 packetsize = 0;
223 }
224
225 //--------------------------------------------------------------------------------------------
packet_addUnsignedByte(Uint8 uc)226 void packet_addUnsignedByte( Uint8 uc )
227 {
228 /// @details ZZ@> This function appends an Uint8 to the packet
229
230 Uint8* ucp;
231 ucp = ( Uint8* )( &packetbuffer[packethead] );
232 *ucp = uc;
233 packethead += 1;
234 packetsize += 1;
235 }
236
237 //--------------------------------------------------------------------------------------------
packet_addSignedByte(Sint8 sc)238 void packet_addSignedByte( Sint8 sc )
239 {
240 /// @details ZZ@> This function appends a Sint8 to the packet
241
242 signed char* scp;
243 scp = ( signed char* )( &packetbuffer[packethead] );
244 *scp = sc;
245 packethead += 1;
246 packetsize += 1;
247 }
248
249 //--------------------------------------------------------------------------------------------
packet_addUnsignedShort(Uint16 us)250 void packet_addUnsignedShort( Uint16 us )
251 {
252 /// @details ZZ@> This function appends an Uint16 to the packet
253
254 Uint16* usp;
255 usp = ( Uint16* )( &packetbuffer[packethead] );
256
257 *usp = ENET_HOST_TO_NET_16( us );
258 packethead += 2;
259 packetsize += 2;
260 }
261
262 //--------------------------------------------------------------------------------------------
packet_addSignedShort(Sint16 ss)263 void packet_addSignedShort( Sint16 ss )
264 {
265 /// @details ZZ@> This function appends a Sint16 to the packet
266
267 signed short* ssp;
268 ssp = ( signed short* )( &packetbuffer[packethead] );
269
270 *ssp = ENET_HOST_TO_NET_16( ss );
271
272 packethead += 2;
273 packetsize += 2;
274 }
275
276 //--------------------------------------------------------------------------------------------
packet_addUnsignedInt(Uint32 ui)277 void packet_addUnsignedInt( Uint32 ui )
278 {
279 /// @details ZZ@> This function appends an Uint32 to the packet
280
281 Uint32* uip;
282 uip = ( Uint32* )( &packetbuffer[packethead] );
283
284 *uip = ENET_HOST_TO_NET_32( ui );
285
286 packethead += 4;
287 packetsize += 4;
288 }
289
290 //--------------------------------------------------------------------------------------------
packet_addSignedInt(Sint32 si)291 void packet_addSignedInt( Sint32 si )
292 {
293 /// @details ZZ@> This function appends a Sint32 to the packet
294
295 signed int* sip;
296 sip = ( signed int* )( &packetbuffer[packethead] );
297
298 *sip = ENET_HOST_TO_NET_32( si );
299
300 packethead += 4;
301 packetsize += 4;
302 }
303
304 //--------------------------------------------------------------------------------------------
packet_addString(const char * string)305 void packet_addString( const char *string )
306 {
307 /// @details ZZ@> This function appends a null terminated string to the packet
308
309 char* cp;
310 char cTmp;
311 int cnt;
312
313 cnt = 0;
314 cTmp = 1;
315 cp = ( char* )( &packetbuffer[packethead] );
316
317 while ( CSTR_END != cTmp )
318 {
319 cTmp = string[cnt];
320 *cp = cTmp;
321 cp += 1;
322 packethead += 1;
323 packetsize += 1;
324 cnt++;
325 }
326 }
327
328 //--------------------------------------------------------------------------------------------
packet_startReading(ENetPacket * packet)329 void packet_startReading( ENetPacket *packet )
330 {
331 net_readPacket = packet;
332 net_readLocation = 0;
333 }
334
335 //--------------------------------------------------------------------------------------------
packet_doneReading()336 void packet_doneReading()
337 {
338 net_readPacket = NULL;
339 net_readLocation = 0;
340 }
341
342 //--------------------------------------------------------------------------------------------
packet_readString(char * buffer,int maxLen)343 void packet_readString( char *buffer, int maxLen )
344 {
345 /// @details ZZ@> This function reads a null terminated string from the packet
346
347 Uint8 uc;
348 Uint16 outindex;
349
350 outindex = 0;
351 uc = net_readPacket->data[net_readLocation];
352 net_readLocation++;
353
354 while ( uc != 0 && outindex < maxLen )
355 {
356 buffer[outindex] = uc;
357 outindex++;
358 uc = net_readPacket->data[net_readLocation];
359 net_readLocation++;
360 }
361
362 buffer[outindex] = 0;
363 }
364
365 //--------------------------------------------------------------------------------------------
packet_readUnsignedByte()366 Uint8 packet_readUnsignedByte()
367 {
368 /// @details ZZ@> This function reads an Uint8 from the packet
369
370 Uint8 uc;
371 uc = ( Uint8 )net_readPacket->data[net_readLocation];
372 net_readLocation++;
373 return uc;
374 }
375
376 //--------------------------------------------------------------------------------------------
packet_readSignedByte()377 Sint8 packet_readSignedByte()
378 {
379 /// @details ZZ@> This function reads a Sint8 from the packet
380
381 Sint8 sc;
382 sc = ( signed char )net_readPacket->data[net_readLocation];
383 net_readLocation++;
384 return sc;
385 }
386
387 //--------------------------------------------------------------------------------------------
packet_readUnsignedShort()388 Uint16 packet_readUnsignedShort()
389 {
390 /// @details ZZ@> This function reads an Uint16 from the packet
391
392 Uint16 us;
393 Uint16* usp;
394 usp = ( Uint16* )( &net_readPacket->data[net_readLocation] );
395
396 us = ENET_NET_TO_HOST_16( *usp );
397
398 net_readLocation += 2;
399 return us;
400 }
401
402 //--------------------------------------------------------------------------------------------
packet_readSignedShort()403 Sint16 packet_readSignedShort()
404 {
405 /// @details ZZ@> This function reads a Sint16 from the packet
406
407 Sint16 ss;
408 signed short* ssp;
409 ssp = ( signed short* )( &net_readPacket->data[net_readLocation] );
410
411 ss = ENET_NET_TO_HOST_16( *ssp );
412
413 net_readLocation += 2;
414 return ss;
415 }
416
417 //--------------------------------------------------------------------------------------------
packet_readUnsignedInt()418 Uint32 packet_readUnsignedInt()
419 {
420 /// @details ZZ@> This function reads an Uint32 from the packet
421
422 Uint32 ui;
423 Uint32* uip;
424 uip = ( Uint32* )( &net_readPacket->data[net_readLocation] );
425
426 ui = ENET_NET_TO_HOST_32( *uip );
427
428 net_readLocation += 4;
429 return ui;
430 }
431
432 //--------------------------------------------------------------------------------------------
packet_readSignedInt()433 Sint32 packet_readSignedInt()
434 {
435 /// @details ZZ@> This function reads a Sint32 from the packet
436
437 Sint32 si;
438 signed int* sip;
439 sip = ( signed int* )( &net_readPacket->data[net_readLocation] );
440
441 si = ENET_NET_TO_HOST_32( *sip );
442
443 net_readLocation += 4;
444 return si;
445 }
446
447 //--------------------------------------------------------------------------------------------
packet_remainingSize()448 size_t packet_remainingSize()
449 {
450 /// @details ZZ@> This function tells if there's still data left in the packet
451
452 return net_readPacket->dataLength - net_readLocation;
453 }
454
455 //--------------------------------------------------------------------------------------------
net_sendPacketToHost()456 void net_sendPacketToHost()
457 {
458 /// @details ZZ@> This function sends a packet to the host
459
460 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, 0 );
461 enet_peer_send( net_gameHost, NET_UNRELIABLE_CHANNEL, packet );
462 }
463
464 //--------------------------------------------------------------------------------------------
net_sendPacketToAllPlayers()465 void net_sendPacketToAllPlayers()
466 {
467 /// @details ZZ@> This function sends a packet to all the players
468
469 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, 0 );
470 enet_host_broadcast( net_myHost, NET_UNRELIABLE_CHANNEL, packet );
471 }
472
473 //--------------------------------------------------------------------------------------------
net_sendPacketToHostGuaranteed()474 void net_sendPacketToHostGuaranteed()
475 {
476 /// @details ZZ@> This function sends a packet to the host
477
478 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, ENET_PACKET_FLAG_RELIABLE );
479 enet_peer_send( net_gameHost, NET_UNRELIABLE_CHANNEL, packet );
480 }
481
482 //--------------------------------------------------------------------------------------------
net_sendPacketToAllPlayersGuaranteed()483 void net_sendPacketToAllPlayersGuaranteed()
484 {
485 /// @details ZZ@> This function sends a packet to all the players
486
487 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, ENET_PACKET_FLAG_RELIABLE );
488 enet_host_broadcast( net_myHost, NET_GUARANTEED_CHANNEL, packet );
489 }
490
491 //--------------------------------------------------------------------------------------------
net_sendPacketToOnePlayerGuaranteed(int player)492 void net_sendPacketToOnePlayerGuaranteed( int player )
493 {
494 /// @details ZZ@> This function sends a packet to one of the players
495
496 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, ENET_PACKET_FLAG_RELIABLE );
497 if ( player < numplayer )
498 {
499 enet_peer_send( &net_myHost->peers[player], NET_GUARANTEED_CHANNEL, packet );
500 }
501 }
502
503 //--------------------------------------------------------------------------------------------
net_sendPacketToPeer(ENetPeer * peer)504 void net_sendPacketToPeer( ENetPeer *peer )
505 {
506 /// @details JF@> This function sends a packet to a given peer
507
508 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, ENET_PACKET_FLAG_RELIABLE );
509 enet_peer_send( peer, NET_UNRELIABLE_CHANNEL, packet );
510 }
511
512 //--------------------------------------------------------------------------------------------
net_sendPacketToPeerGuaranteed(ENetPeer * peer)513 void net_sendPacketToPeerGuaranteed( ENetPeer *peer )
514 {
515 /// @details JF@> This funciton sends a packet to a given peer, with guaranteed delivery
516
517 ENetPacket *packet = enet_packet_create( packetbuffer, packetsize, 0 );
518 enet_peer_send( peer, NET_GUARANTEED_CHANNEL, packet );
519 }
520
521 //--------------------------------------------------------------------------------------------
net_copyFileToAllPlayers(const char * source,const char * dest)522 void net_copyFileToAllPlayers( const char *source, const char *dest )
523 {
524 /// @details JF@> This function queues up files to send to all the hosts.
525 /// @todo Deal with having to send to up to MAX_PLAYER players...
526
527 NetFileTransfer *state;
528 if ( net_numFileTransfers < NET_MAX_FILE_TRANSFERS )
529 {
530 // net_fileTransferTail should already be pointed at an open
531 // slot in the queue.
532 state = &( net_transferStates[net_fileTransferTail] );
533 EGOBOO_ASSERT( CSTR_END == state->sourceName[0] );
534
535 // Just do the first player for now
536 state->target = &net_myHost->peers[0];
537 strncpy( state->sourceName, source, NET_MAX_FILE_NAME );
538 strncpy( state->destName, dest, NET_MAX_FILE_NAME );
539
540 // advance the tail index
541 net_numFileTransfers++;
542 net_fileTransferTail++;
543 if ( net_fileTransferTail >= NET_MAX_FILE_TRANSFERS )
544 {
545 net_fileTransferTail = 0;
546 }
547 if ( net_fileTransferTail == net_fileTransferHead )
548 {
549 log_warning( "net_copyFileToAllPlayers: Warning! Queue tail caught up with the head!\n" );
550 }
551 }
552 }
553
554 //--------------------------------------------------------------------------------------------
net_copyFileToAllPlayersOld_vfs(const char * source,const char * dest)555 void net_copyFileToAllPlayersOld_vfs( const char *source, const char *dest )
556 {
557 /// @details ZZ@> This function copies a file on the host to every remote computer.
558 /// Packets are sent in chunks of COPYSIZE bytes. The max file size
559 /// that can be sent is 2 Megs ( TOTALSIZE ).
560
561 vfs_FILE* fileread;
562 int packetsize, packetstart;
563 int filesize;
564 int fileisdir;
565 char cTmp;
566
567 log_info( "net_copyFileToAllPlayers: %s, %s\n", source, dest );
568 if ( gnet.on && gnet.hostactive )
569 {
570 fileisdir = vfs_isDirectory( source );
571 if ( fileisdir )
572 {
573 net_startNewPacket();
574 packet_addUnsignedShort( TO_REMOTE_DIR );
575 packet_addString( dest );
576 net_sendPacketToAllPlayersGuaranteed();
577 }
578 else
579 {
580 fileread = vfs_openReadB( source );
581 if ( fileread )
582 {
583 filesize = vfs_fileLength( fileread );
584 vfs_seek( fileread, 0 );
585 if ( filesize > 0 && filesize < TOTALSIZE )
586 {
587 packetsize = 0;
588 packetstart = 0;
589 numfilesent++;
590
591 net_startNewPacket();
592 packet_addUnsignedShort( TO_REMOTE_FILE );
593 packet_addString( dest );
594 packet_addUnsignedInt( filesize );
595 packet_addUnsignedInt( packetstart );
596
597 while ( packetstart < filesize )
598 {
599 // This will probably work...
600 // vfs_read((packetbuffer + packethead), COPYSIZE, 1, fileread);
601
602 // But I'll leave it alone for now
603 vfs_scanf( fileread, "%c", &cTmp );
604
605 packet_addUnsignedByte( cTmp );
606 packetsize++;
607 packetstart++;
608 if ( packetsize >= COPYSIZE )
609 {
610 // Send off the packet
611 net_sendPacketToAllPlayersGuaranteed();
612 enet_host_flush( net_myHost );
613
614 // Start on the next 4K
615 packetsize = 0;
616 net_startNewPacket();
617 packet_addUnsignedShort( TO_REMOTE_FILE );
618 packet_addString( dest );
619 packet_addUnsignedInt( filesize );
620 packet_addUnsignedInt( packetstart );
621 }
622 }
623
624 // Send off the packet
625 net_sendPacketToAllPlayersGuaranteed();
626 }
627
628 vfs_close( fileread );
629 }
630 }
631 }
632 }
633
634 //--------------------------------------------------------------------------------------------
net_copyFileToHost(const char * source,const char * dest)635 void net_copyFileToHost( const char *source, const char *dest )
636 {
637 NetFileTransfer *state;
638
639 /// @details JF@> New function merely queues up a new file to be sent
640
641 // If this is the host, just copy the file locally
642 if ( gnet.hostactive )
643 {
644 // Simulate a network transfer
645 if ( vfs_isDirectory( source ) )
646 {
647 vfs_mkdir( dest );
648 }
649 else
650 {
651 vfs_copyFile( source, dest );
652 }
653
654 return;
655 }
656 if ( net_numFileTransfers < NET_MAX_FILE_TRANSFERS )
657 {
658 // net_fileTransferTail should already be pointed at an open
659 // slot in the queue.
660 state = &( net_transferStates[net_fileTransferTail] );
661 EGOBOO_ASSERT( CSTR_END == state->sourceName[0] );
662
663 state->target = net_gameHost;
664 strncpy( state->sourceName, source, NET_MAX_FILE_NAME );
665 strncpy( state->destName, dest, NET_MAX_FILE_NAME );
666
667 // advance the tail index
668 net_numFileTransfers++;
669 net_fileTransferTail++;
670 if ( net_fileTransferTail >= NET_MAX_FILE_TRANSFERS )
671 {
672 net_fileTransferTail = 0;
673 }
674 if ( net_fileTransferTail == net_fileTransferHead )
675 {
676 log_warning( "net_copyFileToHost: Warning! Queue tail caught up with the head!\n" );
677 }
678 }
679 }
680
681 //--------------------------------------------------------------------------------------------
net_copyFileToHostOld_vfs(const char * source,const char * dest)682 void net_copyFileToHostOld_vfs( const char *source, const char *dest )
683 {
684 /// @details ZZ@> This function copies a file on the remote to the host computer.
685 /// Packets are sent in chunks of COPYSIZE bytes. The max file size
686 /// that can be sent is 2 Megs ( TOTALSIZE ).
687
688 vfs_FILE* fileread;
689 int packetsize, packetstart;
690 int filesize;
691 int fileisdir;
692 char cTmp;
693
694 log_info( "net_copyFileToHost: " );
695 fileisdir = vfs_isDirectory( source );
696 if ( gnet.hostactive )
697 {
698 // Simulate a network transfer
699 if ( fileisdir )
700 {
701 log_info( "Creating local directory %s\n", dest );
702 vfs_mkdir( dest );
703 }
704 else
705 {
706 log_info( "Copying local file %s --> %s\n", source, dest );
707 vfs_copyFile( source, dest );
708 }
709 }
710 else
711 {
712 if ( fileisdir )
713 {
714 log_info( "Creating directory on host: %s\n", dest );
715 net_startNewPacket();
716 packet_addUnsignedShort( TO_HOST_DIR );
717 packet_addString( dest );
718 // net_sendPacketToAllPlayersGuaranteed();
719 net_sendPacketToHost();
720 }
721 else
722 {
723 log_info( "Copying local file to host file: %s --> %s\n", source, dest );
724 fileread = vfs_openReadB( source );
725 if ( fileread )
726 {
727 filesize = vfs_fileLength( fileread );
728 vfs_seek( fileread, 0 );
729 if ( filesize > 0 && filesize < TOTALSIZE )
730 {
731 numfilesent++;
732 packetsize = 0;
733 packetstart = 0;
734 net_startNewPacket();
735 packet_addUnsignedShort( TO_HOST_FILE );
736 packet_addString( dest );
737 packet_addUnsignedInt( filesize );
738 packet_addUnsignedInt( packetstart );
739
740 while ( packetstart < filesize )
741 {
742 vfs_scanf( fileread, "%c", &cTmp );
743 packet_addUnsignedByte( cTmp );
744 packetsize++;
745 packetstart++;
746 if ( packetsize >= COPYSIZE )
747 {
748 // Send off the packet
749 net_sendPacketToHostGuaranteed();
750 enet_host_flush( net_myHost );
751
752 // Start on the next 4K
753 packetsize = 0;
754 net_startNewPacket();
755 packet_addUnsignedShort( TO_HOST_FILE );
756 packet_addString( dest );
757 packet_addUnsignedInt( filesize );
758 packet_addUnsignedInt( packetstart );
759 }
760 }
761
762 // Send off the packet
763 net_sendPacketToHostGuaranteed();
764 }
765
766 vfs_close( fileread );
767 }
768 }
769 }
770 }
771
772 //--------------------------------------------------------------------------------------------
net_copyDirectoryToHost(const char * dirname,const char * todirname)773 void net_copyDirectoryToHost( const char *dirname, const char *todirname )
774 {
775 /// @details ZZ@> This function copies all files in a directory
776
777 vfs_search_context_t * ctxt;
778 const char *searchResult;
779
780 STRING fromname;
781 STRING toname;
782
783 log_info( "net_copyDirectoryToHost: %s, %s\n", dirname, todirname );
784
785 // Search for all files
786 ctxt = vfs_findFirst( dirname, NULL, VFS_SEARCH_FILE | VFS_SEARCH_BARE );
787 searchResult = vfs_search_context_get_current( ctxt );
788
789 if ( NULL != ctxt && VALID_CSTR( searchResult ) )
790 {
791 // Make the new directory
792 net_copyFileToHost( dirname, todirname );
793
794 // Copy each file
795 while ( VALID_CSTR( searchResult ) )
796 {
797 // If a file begins with a dot, assume it's something
798 // that we don't want to copy. This keeps repository
799 // directories, /., and /.. from being copied
800 // Also avoid copying directories in general.
801 snprintf( fromname, SDL_arraysize( fromname ), "%s/%s", dirname, searchResult );
802 if ( '.' == searchResult[0] || vfs_isDirectory( fromname ) )
803 {
804 ctxt = vfs_findNext( &ctxt );
805 searchResult = vfs_search_context_get_current( ctxt );
806 continue;
807 }
808
809 snprintf( fromname, SDL_arraysize( fromname ), "%s/%s", dirname, searchResult );
810 snprintf( toname, SDL_arraysize( toname ), "%s/%s", todirname, searchResult );
811
812 net_copyFileToHost( fromname, toname );
813
814 ctxt = vfs_findNext( &ctxt );
815 searchResult = vfs_search_context_get_current( ctxt );
816 }
817 }
818
819 vfs_findClose( &ctxt );
820 }
821
822 //--------------------------------------------------------------------------------------------
net_copyDirectoryToAllPlayers(const char * dirname,const char * todirname)823 void net_copyDirectoryToAllPlayers( const char *dirname, const char *todirname )
824 {
825 /// @details ZZ@> This function copies all files in a directory
826
827 vfs_search_context_t * ctxt;
828 const char *searchResult;
829
830 STRING fromname;
831 STRING toname;
832
833 log_info( "net_copyDirectoryToAllPlayers: %s, %s\n", dirname, todirname );
834
835 // Search for all files
836 ctxt = vfs_findFirst( dirname, NULL, VFS_SEARCH_FILE | VFS_SEARCH_BARE );
837 searchResult = vfs_search_context_get_current( ctxt );
838
839 if ( NULL != ctxt && VALID_CSTR( searchResult ) )
840 {
841 // Make the new directory
842 net_copyFileToAllPlayers( dirname, todirname );
843
844 // Copy each file
845 while ( VALID_CSTR( searchResult ) )
846 {
847 // If a file begins with a dot, assume it's something
848 // that we don't want to copy. This keeps repository
849 // directories, /., and /.. from being copied
850 if ( '.' == searchResult[0] )
851 {
852 ctxt = vfs_findNext( &ctxt );
853 searchResult = vfs_search_context_get_current( ctxt );
854
855 continue;
856 }
857
858 snprintf( fromname, SDL_arraysize( fromname ), "%s/%s", dirname, searchResult );
859 snprintf( toname, SDL_arraysize( toname ), "%s/%s", todirname, searchResult );
860 net_copyFileToAllPlayers( fromname, toname );
861
862 ctxt = vfs_findNext( &ctxt );
863 searchResult = vfs_search_context_get_current( ctxt );
864 }
865 }
866
867 vfs_findClose( &ctxt );
868 }
869
870 //--------------------------------------------------------------------------------------------
net_sayHello()871 void net_sayHello()
872 {
873 /// @details ZZ@> This function lets everyone know we're here
874
875 if ( !gnet.on )
876 {
877 gnet.waitingforplayers = bfalse;
878 }
879 else if ( gnet.hostactive )
880 {
881 log_info( "net_sayHello: Server saying hello.\n" );
882 playersloaded++;
883 if ( playersloaded >= numplayer )
884 {
885 gnet.waitingforplayers = bfalse;
886 }
887 }
888 else
889 {
890 log_info( "net_sayHello: Client saying hello.\n" );
891 net_startNewPacket();
892 packet_addUnsignedShort( TO_HOST_IM_LOADED );
893 net_sendPacketToHostGuaranteed();
894 }
895 }
896
897 //--------------------------------------------------------------------------------------------
cl_talkToHost()898 void cl_talkToHost()
899 {
900 /// @details ZZ@> This function sends the latch packets to the host machine
901
902 PLA_REF player;
903
904 // Let the players respawn
905 if ( SDLKEYDOWN( SDLK_SPACE )
906 && ( local_stats.allpladead || PMod->respawnanytime )
907 && PMod->respawnvalid
908 && cfg.difficulty < GAME_HARD
909 && !console_mode )
910 {
911 player = 0;
912
913 while ( player < MAX_PLAYER )
914 {
915 if ( PlaStack.lst[player].valid && PlaStack.lst[player].device.bits != INPUT_BITS_NONE )
916 {
917 SET_BIT( PlaStack.lst[player].local_latch.b, LATCHBUTTON_RESPAWN ); // Press the respawn button...
918 }
919
920 player++;
921 }
922 }
923
924 // Start talkin'
925 if ( gnet.on && !gnet.hostactive /*&& !PMod->rtscontrol*/ )
926 {
927 net_startNewPacket();
928 packet_addUnsignedShort( TO_HOST_LATCH ); // The message header
929
930 for ( player = 0; player < MAX_PLAYER; player++ )
931 {
932 // Find the local players
933 if ( PlaStack.lst[player].valid && PlaStack.lst[player].device.bits != INPUT_BITS_NONE )
934 {
935 packet_addUnsignedByte( REF_TO_INT( player ) ); // The player index
936 packet_addUnsignedInt( PlaStack.lst[player].local_latch.b ); // Player button states
937 packet_addSignedShort( PlaStack.lst[player].local_latch.x*SHORTLATCH ); // Player motion
938 packet_addSignedShort( PlaStack.lst[player].local_latch.y*SHORTLATCH ); // Player motion
939 }
940 }
941
942 // Send it to the host
943 net_sendPacketToHost();
944 }
945 }
946
947 //--------------------------------------------------------------------------------------------
sv_talkToRemotes()948 void sv_talkToRemotes()
949 {
950 /// @details ZZ@> This function sends the character data to all the remote machines
951
952 PLA_REF player;
953 int time;
954
955 // make sure there is only one update per frame;
956 if ( update_wld == sv_last_frame ) return;
957 sv_last_frame = update_wld;
958
959 if ( gnet.hostactive )
960 {
961 if ( gnet.on )
962 {
963 time = true_update + lag;
964
965 // Send a message to all players
966 net_startNewPacket();
967 packet_addUnsignedShort( TO_REMOTE_LATCH ); // The message header
968 packet_addUnsignedInt( time ); // The stamp
969
970 // Send all player latches...
971 for ( player = 0; player < MAX_PLAYER; player++ )
972 {
973 if ( !PlaStack.lst[player].valid ) continue;
974
975 packet_addUnsignedByte( REF_TO_INT( player ) ); // The player index
976 packet_addUnsignedInt( PlaStack.lst[player].local_latch.b ); // Player button states
977 packet_addSignedShort( PlaStack.lst[player].local_latch.x*SHORTLATCH ); // Player motion
978 packet_addSignedShort( PlaStack.lst[player].local_latch.y*SHORTLATCH ); // Player motion
979
980 player++;
981 }
982
983 // Send the packet
984 net_sendPacketToAllPlayers();
985 }
986 else
987 {
988 time = true_update + 1;
989 }
990
991 // update the local timed latches with the same info
992 numplatimes = 0;
993 for ( player = 0; player < MAX_PLAYER; player++ )
994 {
995 int index;
996 Uint32 cnt;
997 player_t * ppla;
998
999 if ( !PlaStack.lst[player].valid ) continue;
1000 ppla = PlaStack.lst + player;
1001
1002 index = ppla->tlatch_count;
1003 if ( index < MAXLAG )
1004 {
1005 time_latch_t * ptlatch = ppla->tlatch + index;
1006
1007 ptlatch->button = ppla->local_latch.b;
1008
1009 // reduce the resolution of the motion to match the network packets
1010 ptlatch->x = FLOOR( ppla->local_latch.x * SHORTLATCH ) / SHORTLATCH;
1011 ptlatch->y = FLOOR( ppla->local_latch.y * SHORTLATCH ) / SHORTLATCH;
1012
1013 ptlatch->time = true_update;
1014
1015 ppla->tlatch_count++;
1016 }
1017
1018 // determine the max amount of lag
1019 for ( cnt = 0; cnt < ppla->tlatch_count; cnt++ )
1020 {
1021 int loc_lag = update_wld - ppla->tlatch[index].time + 1;
1022
1023 if ( loc_lag > numplatimes )
1024 {
1025 numplatimes = loc_lag;
1026 }
1027 }
1028 }
1029 }
1030 }
1031
1032 //--------------------------------------------------------------------------------------------
pla_add_tlatch(const PLA_REF iplayer,Uint32 time,latch_t net_latch)1033 void pla_add_tlatch( const PLA_REF iplayer, Uint32 time, latch_t net_latch )
1034 {
1035 player_t * ppla;
1036
1037 if ( !VALID_PLA( iplayer ) ) return;
1038 ppla = PlaStack.lst + iplayer;
1039
1040 if ( ppla->tlatch_count >= MAXLAG ) return;
1041
1042 ppla->tlatch[ ppla->tlatch_count ].button = net_latch.b;
1043 ppla->tlatch[ ppla->tlatch_count ].x = net_latch.x;
1044 ppla->tlatch[ ppla->tlatch_count ].y = net_latch.y;
1045 ppla->tlatch[ ppla->tlatch_count ].time = time;
1046
1047 ppla->tlatch_count++;
1048 }
1049
1050 //--------------------------------------------------------------------------------------------
net_handlePacket(ENetEvent * event)1051 void net_handlePacket( ENetEvent *event )
1052 {
1053 Uint16 header;
1054 STRING filename; // also used for reading various strings
1055 int filesize, newfilesize, fileposition;
1056 char newfile;
1057 PLA_REF player;
1058 Uint32 stamp;
1059 int time;
1060 vfs_FILE *file;
1061 size_t fileSize;
1062
1063 log_info( "net_handlePacket: Received " );
1064
1065 packet_startReading( event->packet );
1066 header = packet_readUnsignedShort();
1067
1068 switch ( header )
1069 {
1070 case TO_ANY_TEXT:
1071 log_info( "TO_ANY_TEXT\n" );
1072 packet_readString( filename, 255 );
1073 debug_printf( filename );
1074 break;
1075
1076 case TO_HOST_MODULEOK:
1077 log_info( "TO_HOSTMODULEOK\n" );
1078 if ( gnet.hostactive )
1079 {
1080 playersready++;
1081 if ( playersready >= numplayer )
1082 {
1083 gnet.readytostart = btrue;
1084 }
1085 }
1086 break;
1087
1088 case TO_HOST_LATCH:
1089 log_info( "TO_HOST_LATCH\n" );
1090 if ( gnet.hostactive )
1091 {
1092 while ( packet_remainingSize() > 0 )
1093 {
1094 latch_t tmp_latch;
1095
1096 player = packet_readUnsignedByte();
1097 time = packet_readUnsignedInt();
1098
1099 tmp_latch.b = packet_readUnsignedInt();
1100 tmp_latch.x = packet_readSignedShort() / SHORTLATCH;
1101 tmp_latch.y = packet_readSignedShort() / SHORTLATCH;
1102
1103 pla_add_tlatch( player, time, tmp_latch );
1104 }
1105
1106 }
1107 break;
1108
1109 case TO_HOST_IM_LOADED:
1110 log_info( "TO_HOST_IMLOADED\n" );
1111 if ( gnet.hostactive )
1112 {
1113 playersloaded++;
1114 if ( playersloaded == numplayer )
1115 {
1116 // Let the games begin...
1117 gnet.waitingforplayers = bfalse;
1118 net_startNewPacket();
1119 packet_addUnsignedShort( TO_REMOTE_START );
1120 net_sendPacketToAllPlayersGuaranteed();
1121 }
1122 }
1123 break;
1124
1125 case TO_HOST_RTS:
1126 log_info( "TO_HOST_RTS\n" );
1127 if ( gnet.hostactive )
1128 {
1129 /*whichorder = get_empty_order();
1130 if(whichorder < MAXORDER)
1131 {
1132 // Add the order on the host machine
1133 cnt = 0;
1134 while(cnt < MAXSELECT)
1135 {
1136 who = packet_readUnsignedByte();
1137 orderwho[whichorder][cnt] = who;
1138 cnt++;
1139 }
1140 what = packet_readUnsignedInt();
1141 when = update_wld + orderlag;
1142 orderwhat[whichorder] = what;
1143 orderwhen[whichorder] = when;
1144
1145 // Send the order off to everyone else
1146 net_startNewPacket();
1147 packet_addUnsignedShort(TO_REMOTE_RTS);
1148 cnt = 0;
1149 while(cnt < MAXSELECT)
1150 {
1151 packet_addUnsignedByte(orderwho[whichorder][cnt]);
1152 cnt++;
1153 }
1154 packet_addUnsignedInt(what);
1155 packet_addUnsignedInt(when);
1156 net_sendPacketToAllPlayersGuaranteed();
1157 }*/
1158 }
1159 break;
1160
1161 case NET_TRANSFER_FILE:
1162 packet_readString( filename, 256 );
1163 fileSize = packet_readUnsignedInt();
1164
1165 log_info( "NET_TRANSFER_FILE: %s with size %d.\n", filename, fileSize );
1166
1167 // Try and save the file
1168 file = vfs_openWriteB( filename );
1169 if ( NULL != file )
1170 {
1171 vfs_write( net_readPacket->data + net_readLocation, 1, fileSize, file );
1172 vfs_close( file );
1173 }
1174 else
1175 {
1176 log_warning( "net_handlePacket: Couldn't write new file!\n" );
1177 }
1178
1179 // Acknowledge that we got this file
1180 net_startNewPacket();
1181 packet_addUnsignedShort( NET_TRANSFER_OK );
1182 net_sendPacketToPeer( event->peer );
1183
1184 // And note that we've gotten another one
1185 numfile++;
1186 break;
1187
1188 case NET_TRANSFER_OK:
1189 log_info( "NET_TRANSFER_OK. The last file sent was successful.\n" );
1190 net_waitingForXferAck = 0;
1191 net_numFileTransfers--;
1192
1193 break;
1194
1195 case NET_CREATE_DIRECTORY:
1196 packet_readString( filename, 256 );
1197 log_info( "NET_CREATE_DIRECTORY: %s\n", filename );
1198
1199 vfs_mkdir( filename );
1200
1201 // Acknowledge that we got this file
1202 net_startNewPacket();
1203 packet_addUnsignedShort( NET_TRANSFER_OK );
1204 net_sendPacketToPeer( event->peer );
1205
1206 numfile++; // The client considers directories it sends to be files, so ya.
1207 break;
1208
1209 case NET_DONE_SENDING_FILES:
1210 log_info( "NET_DONE_SENDING_FILES\n" );
1211 numplayerrespond++;
1212 break;
1213
1214 case NET_NUM_FILES_TO_SEND:
1215 log_info( "NET_NUM_FILES_TO_SEND\n" );
1216 numfileexpected = ( int )packet_readUnsignedShort();
1217 break;
1218
1219 case TO_HOST_FILE:
1220 log_info( "TO_HOST_FILE\n" );
1221 packet_readString( filename, 255 );
1222 newfilesize = packet_readUnsignedInt();
1223
1224 // Change the size of the file if need be
1225 newfile = 0;
1226 file = vfs_openReadB( filename );
1227 if ( file )
1228 {
1229 filesize = vfs_fileLength( file );
1230 vfs_close( file );
1231 if ( filesize != newfilesize )
1232 {
1233 // Destroy the old file
1234 newfile = 1;
1235 }
1236 }
1237 else
1238 {
1239 newfile = 1;
1240 }
1241 if ( newfile )
1242 {
1243 // file must be created. Write zeroes to the file to do it
1244 numfile++;
1245 file = vfs_openWriteB( filename );
1246 if ( file )
1247 {
1248 filesize = 0;
1249
1250 while ( filesize < newfilesize )
1251 {
1252 vfs_putc( 0, file );
1253 filesize++;
1254 }
1255
1256 vfs_close( file );
1257 }
1258 }
1259
1260 // Go to the position in the file and copy data
1261 fileposition = packet_readUnsignedInt();
1262 file = vfs_openReadB( filename );
1263 if ( file )
1264 {
1265 if ( 0 == vfs_seek( file, fileposition ) )
1266 {
1267 while ( packet_remainingSize() > 0 )
1268 {
1269 vfs_putc( packet_readUnsignedByte(), file );
1270 }
1271 }
1272
1273 vfs_close( file );
1274 }
1275 break;
1276
1277 case TO_HOST_DIR:
1278 log_info( "TO_HOST_DIR\n" );
1279 if ( gnet.hostactive )
1280 {
1281 packet_readString( filename, 255 );
1282 vfs_mkdir( filename );
1283 }
1284 break;
1285
1286 case TO_HOST_FILESENT:
1287 log_info( "TO_HOST_FILESENT\n" );
1288 if ( gnet.hostactive )
1289 {
1290 numfileexpected += packet_readUnsignedInt();
1291 numplayerrespond++;
1292 }
1293 break;
1294
1295 case TO_REMOTE_FILESENT:
1296 log_info( "TO_REMOTE_FILESENT\n" );
1297 if ( !gnet.hostactive )
1298 {
1299 numfileexpected += packet_readUnsignedInt();
1300 numplayerrespond++;
1301 }
1302 break;
1303
1304 case TO_REMOTE_MODULE:
1305 log_info( "TO_REMOTE_MODULE\n" );
1306 if ( !gnet.hostactive && !gnet.readytostart )
1307 {
1308 PMod->seed = packet_readUnsignedInt();
1309 packet_readString( filename, 255 );
1310
1311 pickedmodule_index = -1;
1312 pickedmodule_path[0] = CSTR_END;
1313 pickedmodule_name[0] = CSTR_END;
1314 pickedmodule_write_path[0] = CSTR_END;
1315
1316 pickedmodule_index = mnu_get_mod_number( filename );
1317
1318 // Check to see if the module exists
1319 if ( -1 != pickedmodule_index )
1320 {
1321 strncpy( pickedmodule_path, mnu_ModList_get_vfs_path( pickedmodule_index ), SDL_arraysize( pickedmodule_path ) );
1322 strncpy( pickedmodule_name, mnu_ModList_get_name( pickedmodule_index ), SDL_arraysize( pickedmodule_name ) );
1323 strncpy( pickedmodule_write_path, mnu_ModList_get_dest_path( pickedmodule_index ), SDL_arraysize( pickedmodule_write_path ) );
1324
1325 pickedmodule_ready = btrue;
1326
1327 // Make ourselves ready
1328 gnet.readytostart = btrue;
1329
1330 // Tell the host we're ready
1331 net_startNewPacket();
1332 packet_addUnsignedShort( TO_HOST_MODULEOK );
1333 net_sendPacketToHostGuaranteed();
1334 }
1335 else
1336 {
1337 // The module doesn't exist locally
1338 pickedmodule_ready = bfalse;
1339
1340 // Halt the process
1341 gnet.readytostart = bfalse;
1342
1343 // Tell the host we're not ready
1344 net_startNewPacket();
1345 packet_addUnsignedShort( TO_HOST_MODULEBAD );
1346 net_sendPacketToHostGuaranteed();
1347 }
1348 }
1349 break;
1350
1351 case TO_REMOTE_START:
1352 log_info( "TO_REMOTE_START\n" );
1353 if ( !gnet.hostactive )
1354 {
1355 gnet.waitingforplayers = bfalse;
1356 }
1357 break;
1358
1359 case TO_REMOTE_RTS:
1360 log_info( "TO_REMOTE_RTS\n" );
1361 if ( !gnet.hostactive )
1362 {
1363 /* whichorder = get_empty_order();
1364 if(whichorder < MAXORDER)
1365 {
1366 // Add the order on the remote machine
1367 cnt = 0;
1368 while(cnt < MAXSELECT)
1369 {
1370 who = packet_readUnsignedByte();
1371 orderwho[whichorder][cnt] = who;
1372 cnt++;
1373 }
1374 what = packet_readUnsignedInt();
1375 when = packet_readUnsignedInt();
1376 orderwhat[whichorder] = what;
1377 orderwhen[whichorder] = when;
1378 }*/
1379 }
1380 break;
1381
1382 case TO_REMOTE_FILE:
1383 log_info( "TO_REMOTE_FILE\n" );
1384 if ( !gnet.hostactive )
1385 {
1386 packet_readString( filename, 255 );
1387 newfilesize = packet_readUnsignedInt();
1388
1389 // Change the size of the file if need be
1390 newfile = 0;
1391 file = vfs_openReadB( filename );
1392 if ( file )
1393 {
1394 filesize = vfs_fileLength( file );
1395 vfs_close( file );
1396 if ( filesize != newfilesize )
1397 {
1398 // Destroy the old file
1399 newfile = 1;
1400 }
1401 }
1402 else
1403 {
1404 newfile = 1;
1405 }
1406 if ( newfile )
1407 {
1408 // file must be created. Write zeroes to the file to do it
1409 numfile++;
1410 file = vfs_openWriteB( filename );
1411 if ( file )
1412 {
1413 filesize = 0;
1414
1415 while ( filesize < newfilesize )
1416 {
1417 vfs_putc( 0, file );
1418 filesize++;
1419 }
1420
1421 vfs_close( file );
1422 }
1423 }
1424
1425 // Go to the position in the file and copy data
1426 fileposition = packet_readUnsignedInt();
1427 file = vfs_openReadB( filename );
1428 if ( file )
1429 {
1430 if ( 0 == vfs_seek( file, fileposition ) )
1431 {
1432 while ( packet_remainingSize() > 0 )
1433 {
1434 vfs_putc( packet_readUnsignedByte(), file );
1435 }
1436 }
1437
1438 vfs_close( file );
1439 }
1440 }
1441 break;
1442
1443 case TO_REMOTE_DIR:
1444 log_info( "TO_REMOTE_DIR\n" );
1445 if ( !gnet.hostactive )
1446 {
1447 packet_readString( filename, 255 );
1448 vfs_mkdir( filename );
1449 }
1450 break;
1451
1452 case TO_REMOTE_LATCH:
1453 log_info( "TO_REMOTE_LATCH\n" );
1454 if ( !gnet.hostactive )
1455 {
1456 stamp = packet_readUnsignedInt();
1457 time = stamp & LAGAND;
1458 if ((( Uint32 )( ~0 ) ) == nexttimestamp )
1459 {
1460 nexttimestamp = stamp;
1461 }
1462 if ( stamp < nexttimestamp )
1463 {
1464 log_warning( "net_handlePacket: OUT OF ORDER PACKET\n" );
1465 outofsync = btrue;
1466 }
1467 if ( stamp <= update_wld )
1468 {
1469 log_warning( "net_handlePacket: LATE PACKET\n" );
1470 outofsync = btrue;
1471 }
1472 if ( stamp > nexttimestamp )
1473 {
1474 log_warning( "net_handlePacket: MISSED PACKET\n" );
1475 nexttimestamp = stamp; // Still use it
1476 outofsync = btrue;
1477 }
1478 if ( stamp == nexttimestamp )
1479 {
1480 // Remember that we got it
1481 numplatimes++;
1482
1483 // Read latches for each player sent
1484 while ( packet_remainingSize() > 0 )
1485 {
1486 player = packet_readUnsignedByte();
1487 PlaStack.lst[player].tlatch[time].button = packet_readUnsignedInt();
1488 PlaStack.lst[player].tlatch[time].x = packet_readSignedShort() / SHORTLATCH;
1489 PlaStack.lst[player].tlatch[time].y = packet_readSignedShort() / SHORTLATCH;
1490 }
1491
1492 nexttimestamp = stamp + 1;
1493 }
1494 }
1495 break;
1496 }
1497 }
1498
1499 //--------------------------------------------------------------------------------------------
listen_for_packets()1500 void listen_for_packets()
1501 {
1502 /// @details ZZ@> This function reads any new messages and sets the player latch and matrix needed
1503 /// lists...
1504
1505 ENetEvent event;
1506 if ( gnet.on )
1507 {
1508 // Listen for new messages
1509 while ( enet_host_service( net_myHost, &event, 0 ) != 0 )
1510 {
1511 switch ( event.type )
1512 {
1513 case ENET_EVENT_TYPE_RECEIVE:
1514 net_handlePacket( &event );
1515 enet_packet_destroy( event.packet );
1516 break;
1517
1518 case ENET_EVENT_TYPE_CONNECT:
1519 // don't allow anyone to connect during the game session
1520 log_warning( "listen_for_packets: Client tried to connect during the game: %x:%u\n",
1521 event.peer->address.host, event.peer->address.port );
1522 #if 1
1523 enet_peer_disconnect( event.peer, 0 );
1524 #else
1525 enet_peer_disconnect( event.peer );
1526 #endif
1527 break;
1528
1529 case ENET_EVENT_TYPE_DISCONNECT:
1530
1531 // Is this a player disconnecting, or just a rejected connection
1532 // from above?
1533 if ( event.peer->data != 0 )
1534 {
1535 NetPlayerInfo *info = ( NetPlayerInfo * )event.peer->data;
1536
1537 // uh oh, how do we handle losing a player?
1538 log_warning( "listen_for_packets: Player %d disconnected!\n",
1539 info->playerSlot );
1540 }
1541 break;
1542
1543 default:
1544 break;
1545 }
1546 }
1547 }
1548 }
1549
1550 //--------------------------------------------------------------------------------------------
unbuffer_player_latches()1551 void unbuffer_player_latches()
1552 {
1553 /// @details ZZ@> This function sets character latches based on player input to the host
1554
1555 PLA_REF ipla;
1556 CHR_REF character;
1557
1558 // if ( PMod->rtscontrol ) { numplatimes--; return; }
1559
1560 // get the "network" latch for each valid player
1561 numplatimes = 0;
1562 for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
1563 {
1564 Uint32 latch_count, tnc;
1565 latch_t tmp_latch;
1566 player_t * ppla;
1567 time_latch_t * tlatch_list;
1568
1569 if ( !PlaStack.lst[ipla].valid ) continue;
1570 ppla = PlaStack.lst + ipla;
1571 tlatch_list = ppla->tlatch;
1572
1573 // copy the latch from last time
1574 tmp_latch = ppla->net_latch;
1575
1576 // what are the minimum and maximum indices that can be applies this update?
1577 for ( tnc = 0; tnc < ppla->tlatch_count; tnc++ )
1578 {
1579 int dt;
1580
1581 dt = update_wld - tlatch_list[tnc].time;
1582
1583 if ( dt < 0 )
1584 break;
1585 }
1586 latch_count = tnc;
1587
1588 if ( 1 == latch_count )
1589 {
1590 // there is just one valid latch
1591 tmp_latch.x = tlatch_list[0].x;
1592 tmp_latch.y = tlatch_list[0].y;
1593 tmp_latch.b = tlatch_list[0].button;
1594
1595 //log_info( "<<%1.4f, %1.4f>, 0x%x>, Just one latch for %s\n", tmp_latch.x, tmp_latch.y, tmp_latch.b, ChrList.lst[ppla->index].Name );
1596 }
1597 else if ( latch_count > 1 )
1598 {
1599 int weight, weight_sum;
1600 int dt;
1601
1602 // estimate the best latch value by weighting latches that are back in time
1603 // by dt*dt. This estimates the effect of actually integrating the position over
1604 // that much time without the hastle of actually integrating the trajectory.
1605
1606 // blank the current latch so that we can sum the latch values
1607 latch_init( &( tmp_latch ) );
1608
1609 // apply the latch
1610 weight_sum = 0;
1611 for ( tnc = 0; tnc < latch_count; tnc++ )
1612 {
1613 dt = update_wld - tlatch_list[tnc].time;
1614
1615 weight = ( dt + 1 ) * ( dt + 1 );
1616
1617 weight_sum += weight;
1618 tmp_latch.x += tlatch_list[tnc].x * weight;
1619 tmp_latch.y += tlatch_list[tnc].y * weight;
1620 SET_BIT( tmp_latch.b, tlatch_list[tnc].button );
1621 }
1622
1623 numplatimes = MAX( numplatimes, latch_count );
1624 if ( weight_sum > 0.0f )
1625 {
1626 tmp_latch.x /= ( float )weight_sum;
1627 tmp_latch.y /= ( float )weight_sum;
1628 }
1629
1630 //log_info( "<<%1.4f, %1.4f>, 0x%x>, %d, multiple latches for %s\n", tmp_latch.x, tmp_latch.y, tmp_latch.b, latch_count, ChrList.lst[ppla->index].Name );
1631 }
1632 else
1633 {
1634 // there are no valid latches
1635 // do nothing. this lets the old value of the latch persist.
1636 // this might be a decent guess as to what to do if a packet was
1637 // dropped?
1638 //log_info( "<<%1.4f, %1.4f>, 0x%x>, latch dead reckoning for %s\n", tmp_latch.x, tmp_latch.y, tmp_latch.b, ChrList.lst[ppla->index].Name );
1639 }
1640
1641 if ( latch_count >= ppla->tlatch_count )
1642 {
1643 // we have emptied all of the latches
1644 ppla->tlatch_count = 0;
1645 }
1646 else if ( latch_count > 0 )
1647 {
1648 int index;
1649
1650 // concatenate the list
1651 for ( tnc = latch_count, index = 0; tnc < ppla->tlatch_count; tnc++, index++ )
1652 {
1653 tlatch_list[index].x = tlatch_list[tnc].x;
1654 tlatch_list[index].y = tlatch_list[tnc].y;
1655 tlatch_list[index].button = tlatch_list[tnc].button;
1656 tlatch_list[index].time = tlatch_list[tnc].time;
1657 }
1658 ppla->tlatch_count = index;
1659 }
1660
1661 // fix the network latch
1662 ppla->net_latch = tmp_latch;
1663 }
1664
1665 // set the player latch
1666 for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
1667 {
1668 chr_t * pchr;
1669 player_t * ppla;
1670
1671 if ( !PlaStack.lst[ipla].valid ) continue;
1672 ppla = PlaStack.lst + ipla;
1673
1674 character = PlaStack.lst[ipla].index;
1675 if ( !INGAME_CHR( character ) ) continue;
1676 pchr = ChrList.lst + character;
1677
1678 pchr->latch = ppla->net_latch;
1679 }
1680
1681 // Let players respawn
1682 for ( ipla = 0; ipla < MAX_PLAYER; ipla++ )
1683 {
1684 chr_t * pchr;
1685 player_t * ppla;
1686
1687 if ( !PlaStack.lst[ipla].valid ) continue;
1688 ppla = PlaStack.lst + ipla;
1689
1690 character = PlaStack.lst[ipla].index;
1691 if ( !INGAME_CHR( character ) ) continue;
1692 pchr = ChrList.lst + character;
1693
1694 if ( cfg.difficulty < GAME_HARD && HAS_SOME_BITS( pchr->latch.b, LATCHBUTTON_RESPAWN ) && PMod->respawnvalid )
1695 {
1696 if ( !pchr->alive && 0 == local_stats.revivetimer )
1697 {
1698 respawn_character( character );
1699 TeamStack.lst[pchr->team].leader = character;
1700 SET_BIT( pchr->ai.alert, ALERTIF_CLEANEDUP );
1701
1702 // cost some experience for doing this... never lose a level
1703 pchr->experience *= EXPKEEP;
1704 if ( cfg.difficulty > GAME_EASY ) pchr->money *= EXPKEEP;
1705 }
1706
1707 // remove all latches other than latchbutton_respawn
1708 UNSET_BIT( pchr->latch.b, LATCHBUTTON_RESPAWN );
1709 }
1710 }
1711 }
1712
1713 //--------------------------------------------------------------------------------------------
net_initialize()1714 void net_initialize()
1715 {
1716 /// @details ZZ@> This starts up the network and logs whatever goes on
1717
1718 gnet.serviceon = bfalse;
1719 numsession = 0;
1720 numservice = 0;
1721
1722 net_instance_init( &gnet );
1723
1724 // Clear all the state variables to 0 to start.
1725 memset( net_playerPeers, 0, sizeof( ENetPeer* ) * MAX_PLAYER );
1726 memset( net_playerInfo, 0, sizeof( NetPlayerInfo ) * MAX_PLAYER );
1727 memset( packetbuffer, 0, MAXSENDSIZE * sizeof( Uint8 ) );
1728 memset( net_transferStates, 0, sizeof( NetFileTransfer ) * NET_MAX_FILE_TRANSFERS );
1729 memset( &net_receiveState, 0, sizeof( NetFileTransfer ) );
1730
1731 sv_last_frame = ( Uint32 )~0;
1732
1733 if ( gnet.on )
1734 {
1735 // initialize enet
1736 log_info( "net_initialize: Initializing enet... " );
1737 if ( enet_initialize() != 0 )
1738 {
1739 log_info( "Failure!\n" );
1740 gnet.on = bfalse;
1741 gnet.serviceon = bfalse;
1742 }
1743 else
1744 {
1745 log_info( "Success!\n" );
1746 gnet.serviceon = btrue;
1747 numservice = 1;
1748 }
1749 }
1750 else
1751 {
1752 // We're not doing networking this time...
1753 log_info( "net_initialize: Networking not enabled.\n" );
1754 }
1755 }
1756
1757 //--------------------------------------------------------------------------------------------
net_shutDown()1758 void net_shutDown()
1759 {
1760 log_info( "net_shutDown: Turning off networking.\n" );
1761 enet_deinitialize();
1762 }
1763
1764 //--------------------------------------------------------------------------------------------
find_open_sessions()1765 void find_open_sessions()
1766 {
1767 /*PORT
1768 /// @details ZZ@> This function finds some open games to join
1769
1770 DPSESSIONDESC2 sessionDesc;
1771 HRESULT hr;
1772 if(gnet.on)
1773 {
1774 numsession = 0;
1775 if(globalnetworkerr) vfs_printf(globalnetworkerr, " Looking for open games...\n");
1776 ZeroMemory(&sessionDesc, sizeof(DPSESSIONDESC2));
1777 sessionDesc.dwSize = sizeof(DPSESSIONDESC2);
1778 sessionDesc.guidApplication = NETWORKID;
1779 hr = lpDirectPlay3A->EnumSessions(&sessionDesc, 0, SessionsCallback, hGlobalWindow, DPENUMSESSIONS_AVAILABLE);
1780 if(globalnetworkerr) vfs_printf(globalnetworkerr, " %d sessions found\n", numsession);
1781 }
1782 */
1783 }
1784
1785 //--------------------------------------------------------------------------------------------
sv_letPlayersJoin()1786 void sv_letPlayersJoin()
1787 {
1788 /// @details ZZ@> This function finds all the players in the game
1789
1790 ENetEvent event;
1791 STRING hostName;
1792
1793 // Check all pending events for players joining
1794 while ( enet_host_service( net_myHost, &event, 0 ) > 0 )
1795 {
1796 switch ( event.type )
1797 {
1798 case ENET_EVENT_TYPE_CONNECT:
1799 // Look up the hostname the player is connecting from
1800 enet_address_get_host( &event.peer->address, hostName, 64 );
1801
1802 log_info( "sv_letPlayersJoin: A new player connected from %s:%u\n",
1803 hostName, event.peer->address.port );
1804
1805 // save the player data here.
1806 enet_address_get_host( &event.peer->address, hostName, 64 );
1807 strncpy( netplayername[numplayer], hostName, 16 );
1808
1809 event.peer->data = &( net_playerInfo[numplayer] );
1810 numplayer++;
1811
1812 break;
1813
1814 case ENET_EVENT_TYPE_RECEIVE:
1815 log_info( "sv_letPlayersJoin: Recieved a packet when we weren't expecting it...\n" );
1816 log_info( "\tIt came from %x:%u\n", event.peer->address.host, event.peer->address.port );
1817
1818 // clean up the packet
1819 enet_packet_destroy( event.packet );
1820 break;
1821
1822 case ENET_EVENT_TYPE_DISCONNECT:
1823 log_info( "sv_letPlayersJoin: A client disconnected! Address %x:%u\n",
1824 event.peer->address.host, event.peer->address.port );
1825
1826 // Reset that peer's data
1827 event.peer->data = NULL;
1828 break;
1829
1830 default:
1831 break;
1832 }
1833 }
1834 }
1835
1836 //--------------------------------------------------------------------------------------------
cl_joinGame(const char * hostname)1837 int cl_joinGame( const char* hostname )
1838 {
1839 /// @details ZZ@> This function tries to join one of the sessions we found
1840
1841 ENetAddress address;
1842 ENetEvent event;
1843 if ( gnet.on )
1844 {
1845 log_info( "cl_joinGame: Creating client network connection... " );
1846 // Create my host thingamabober
1847 /// @todo Should I limit client bandwidth here?
1848 net_myHost = enet_host_create( NULL, 1, 0, 0, 0 );
1849 if ( NULL == net_myHost )
1850 {
1851 // can't create a network connection at all
1852 log_info( "Failure!\n" );
1853 return bfalse;
1854 }
1855 else
1856 {
1857 log_info( "Success!\n" );
1858 };
1859
1860 // Now connect to the remote host
1861 log_info( "cl_joinGame: Attempting to connect to %s:%d\n", hostname, NET_EGOBOO_PORT );
1862 enet_address_set_host( &address, hostname );
1863 address.port = NET_EGOBOO_PORT;
1864 net_gameHost = enet_host_connect( net_myHost, &address, NET_EGOBOO_NUM_CHANNELS, 0 );
1865 if ( NULL == net_gameHost )
1866 {
1867 log_info( "cl_joinGame: No available peers to create a connection!\n" );
1868 return bfalse;
1869 }
1870
1871 // Wait for up to 5 seconds for the connection attempt to succeed
1872 if ( enet_host_service( net_myHost, &event, 5000 ) > 0 &&
1873 event.type == ENET_EVENT_TYPE_CONNECT )
1874 {
1875 log_info( "cl_joinGame: Connected to %s:%d\n", hostname, NET_EGOBOO_PORT );
1876 return btrue;
1877 // return create_player(bfalse);
1878 }
1879 else
1880 {
1881 log_info( "cl_joinGame: Could not connect to %s:%d!\n", hostname, NET_EGOBOO_PORT );
1882 }
1883 }
1884
1885 return bfalse;
1886 }
1887
1888 //--------------------------------------------------------------------------------------------
stop_players_from_joining()1889 void stop_players_from_joining()
1890 {
1891 /// @details ZZ@> This function stops players from joining a game
1892 }
1893
1894 //--------------------------------------------------------------------------------------------
sv_hostGame()1895 int sv_hostGame()
1896 {
1897 /// @details ZZ@> This function tries to host a new session
1898
1899 ENetAddress address;
1900 if ( gnet.on )
1901 {
1902 // Try to create a new session
1903 address.host = ENET_HOST_ANY;
1904 address.port = NET_EGOBOO_PORT;
1905
1906 log_info( "sv_hostGame: Creating game on port %d\n", NET_EGOBOO_PORT );
1907 net_myHost = enet_host_create( &address, MAX_PLAYER, 0, 0, 0 );
1908 if ( NULL == net_myHost )
1909 {
1910 log_info( "sv_hostGame: Could not create network connection!\n" );
1911 return bfalse;
1912 }
1913
1914 // Try to create a host player
1915 // return create_player(btrue);
1916 net_amHost = btrue;
1917
1918 // Moved from net_sayHello because there they cause a race issue
1919 gnet.waitingforplayers = btrue;
1920 playersloaded = 0;
1921 }
1922
1923 // Run in solo mode
1924 return btrue;
1925 }
1926
1927 //--------------------------------------------------------------------------------------------
1928 /*void turn_on_service( int service )
1929 {
1930 /// ZZ@> This function turns on a network service ( IPX, TCP, serial, modem )
1931 }*/
1932
1933 //--------------------------------------------------------------------------------------------
net_pendingFileTransfers()1934 int net_pendingFileTransfers()
1935 {
1936 return net_numFileTransfers;
1937 }
1938
1939 //--------------------------------------------------------------------------------------------
net_updateFileTransfers()1940 void net_updateFileTransfers()
1941 {
1942 NetFileTransfer *state;
1943 ENetPacket *packet;
1944 size_t nameLen, fileSize;
1945 Uint32 networkSize;
1946 vfs_FILE *file;
1947 char *p;
1948
1949 // Are there any pending file sends?
1950 if ( net_numFileTransfers > 0 )
1951 {
1952 if ( !net_waitingForXferAck )
1953 {
1954 state = &net_transferStates[net_fileTransferHead];
1955
1956 // Check and see if this is a directory, instead of a file
1957 if ( vfs_isDirectory( state->sourceName ) )
1958 {
1959 // Tell the target to create a directory
1960 log_info( "net_updateFileTranfers: Creating directory %s on target\n", state->destName );
1961 net_startNewPacket();
1962 packet_addUnsignedShort( NET_CREATE_DIRECTORY );
1963 packet_addString( state->destName );
1964 net_sendPacketToPeerGuaranteed( state->target );
1965
1966 net_waitingForXferAck = 1;
1967 }
1968 else
1969 {
1970 file = vfs_openReadB( state->sourceName );
1971 if ( file )
1972 {
1973 log_info( "net_updateFileTransfers: Attempting to send %s to %s\n", state->sourceName, state->destName );
1974
1975 fileSize = vfs_fileLength( file );
1976 vfs_seek( file, 0 );
1977
1978 // Make room for the file's name
1979 nameLen = strlen( state->destName ) + 1;
1980 transferSize = nameLen;
1981
1982 // And for the file's size
1983 transferSize += 6; // Uint32 size, and Uint16 message type
1984 transferSize += fileSize;
1985
1986 transferBuffer = EGOBOO_NEW_ARY( Uint8, transferSize );
1987 *( Uint16* )transferBuffer = ENET_HOST_TO_NET_16( NET_TRANSFER_FILE );
1988
1989 // Add the string and file length to the buffer
1990 p = ( char * )( transferBuffer + 2 );
1991 strcpy( p, state->destName );
1992 p += nameLen;
1993
1994 networkSize = ENET_HOST_TO_NET_32(( Uint32 )fileSize );
1995 *( size_t* )p = networkSize;
1996 p += 4;
1997
1998 vfs_read( p, 1, fileSize, file );
1999 vfs_close( file );
2000
2001 packet = enet_packet_create( transferBuffer, transferSize, ENET_PACKET_FLAG_RELIABLE );
2002 enet_peer_send( state->target, NET_GUARANTEED_CHANNEL, packet );
2003
2004 EGOBOO_DELETE_ARY( transferBuffer );
2005 transferSize = 0;
2006
2007 net_waitingForXferAck = 1;
2008 }
2009 else
2010 {
2011 log_warning( "net_updateFileTransfers: Could not open file %s to send it!\n", state->sourceName );
2012 }
2013 }
2014
2015 // update transfer queue state
2016 memset( state, 0, sizeof( *state ) );
2017 net_fileTransferHead++;
2018 if ( net_fileTransferHead >= NET_MAX_FILE_TRANSFERS )
2019 {
2020 net_fileTransferHead = 0;
2021 }
2022
2023 } // end if waiting for ack
2024 } // end if net_numFileTransfers > 0
2025
2026 // Let the recieve loop run at least once
2027 listen_for_packets();
2028 }
2029
2030 //--------------------------------------------------------------------------------------------
net_send_message()2031 void net_send_message()
2032 {
2033 /// @details ZZ@> sends the message in the keyboard buffer to all other players
2034
2035 if ( console_mode || !console_done ) return;
2036
2037 // if(gnet.on)
2038 // {
2039 // start_building_packet();
2040 // add_packet_us(TO_ANY_TEXT);
2041 // add_packet_sz(keyb.buffer);
2042 // send_packet_to_all_players();
2043 // }
2044 }
2045
2046 //--------------------------------------------------------------------------------------------
net_instance_init(net_instance_t * pnet)2047 bool_t net_instance_init( net_instance_t * pnet )
2048 {
2049 if ( NULL == pnet ) return bfalse;
2050
2051 memset( pnet, 0, sizeof( *pnet ) );
2052
2053 return bfalse;
2054 }
2055
2056 //--------------------------------------------------------------------------------------------
2057 //--------------------------------------------------------------------------------------------
pla_get_ichr(const PLA_REF iplayer)2058 CHR_REF pla_get_ichr( const PLA_REF iplayer )
2059 {
2060 player_t * pplayer;
2061
2062 if ( iplayer >= MAX_PLAYER || !PlaStack.lst[iplayer].valid ) return ( CHR_REF )MAX_CHR;
2063 pplayer = PlaStack.lst + iplayer;
2064
2065 if ( !INGAME_CHR( pplayer->index ) ) return ( CHR_REF )MAX_CHR;
2066
2067 return pplayer->index;
2068 }
2069
2070 //--------------------------------------------------------------------------------------------
pla_get_pchr(const PLA_REF iplayer)2071 chr_t * pla_get_pchr( const PLA_REF iplayer )
2072 {
2073 player_t * pplayer;
2074
2075 if ( iplayer >= MAX_PLAYER || !PlaStack.lst[iplayer].valid ) return NULL;
2076 pplayer = PlaStack.lst + iplayer;
2077
2078 if ( !INGAME_CHR( pplayer->index ) ) return NULL;
2079
2080 return ChrList.lst + pplayer->index;
2081 }
2082
2083 //--------------------------------------------------------------------------------------------
net_reset_players()2084 void net_reset_players()
2085 {
2086 PLA_REF cnt;
2087
2088 // Reset the initial player data and latches
2089 for ( cnt = 0; cnt < MAX_PLAYER; cnt++ )
2090 {
2091 memset( PlaStack.lst + cnt, 0, sizeof( player_t ) );
2092
2093 // reset the device
2094 input_device_init( &( PlaStack.lst[cnt].device ) );
2095 }
2096 PlaStack.count = 0;
2097
2098 nexttimestamp = (( Uint32 )~0 );
2099 numplatimes = 0;
2100 }
2101
2102 //--------------------------------------------------------------------------------------------
tlatch_ary_init(time_latch_t ary[],size_t len)2103 void tlatch_ary_init( time_latch_t ary[], size_t len )
2104 {
2105 size_t cnt;
2106
2107 if ( NULL == ary || 0 == len ) return;
2108
2109 for ( cnt = 0; cnt < len; cnt++ )
2110 {
2111 ary[cnt].x = 0;
2112 ary[cnt].y = 0;
2113 ary[cnt].button = 0;
2114 ary[cnt].time = ( Uint32 )( ~0 );
2115 }
2116 }
2117
2118 //--------------------------------------------------------------------------------------------
pla_reinit(player_t * ppla)2119 void pla_reinit( player_t * ppla )
2120 {
2121 if ( NULL == ppla ) return;
2122
2123 ppla->valid = bfalse;
2124 ppla->index = ( CHR_REF )MAX_CHR;
2125 ppla->device.bits = INPUT_BITS_NONE;
2126 }
2127
2128 //--------------------------------------------------------------------------------------------
player_init(player_t * ppla)2129 void player_init( player_t * ppla )
2130 {
2131 if ( NULL == ppla ) return;
2132
2133 memset( ppla, 0, sizeof( *ppla ) );
2134
2135 ppla->index = ( CHR_REF )MAX_CHR;
2136
2137 // initialize the device
2138 input_device_init( &( ppla->device ) );
2139
2140 // initialize the latches
2141 latch_init( &( ppla->local_latch ) );
2142 latch_init( &( ppla->net_latch ) );
2143
2144 // initialize the tlatch array
2145 tlatch_ary_init( ppla->tlatch, MAXLAG );
2146 }
2147
2148 //--------------------------------------------------------------------------------------------
2149 // Sustain old movements to ease mouse play
input_device_add_latch(input_device_t * pdevice,float newx,float newy)2150 void input_device_add_latch( input_device_t * pdevice, float newx, float newy )
2151 {
2152 float dist;
2153
2154 if ( NULL == pdevice ) return;
2155
2156 pdevice->latch_old = pdevice->latch;
2157
2158 pdevice->latch.x = pdevice->latch.x * pdevice->sustain + newx * pdevice->cover;
2159 pdevice->latch.y = pdevice->latch.y * pdevice->sustain + newy * pdevice->cover;
2160
2161 // make sure that the latch never overflows
2162 dist = pdevice->latch.x * pdevice->latch.x + pdevice->latch.y * pdevice->latch.y;
2163 if ( dist > 1.0f )
2164 {
2165 float scale = 1.0f / SQRT( dist );
2166
2167 pdevice->latch.x *= scale;
2168 pdevice->latch.y *= scale;
2169 }
2170 }
2171
2172 //--------------------------------------------------------------------------------------------
chr_get_ppla(const CHR_REF ichr)2173 player_t* chr_get_ppla( const CHR_REF ichr )
2174 {
2175 PLA_REF iplayer;
2176
2177 if ( !INGAME_CHR( ichr ) ) return NULL;
2178 iplayer = ChrList.lst[ichr].is_which_player;
2179
2180 if ( !VALID_PLA( iplayer ) ) return NULL;
2181
2182 return PlaStack.lst + iplayer;
2183 }
2184