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