home *** CD-ROM | disk | FTP | other *** search
/ Freelog Special Issue 2 / Freelog_HS_3_Setp_Oct_Nov_2000_CD2.mdx / Arcade / Orbit / src / network.c < prev    next >
C/C++ Source or Header  |  1999-09-27  |  19KB  |  1,075 lines

  1. /*
  2.  
  3. ORBIT, a freeware space combat simulator
  4. Copyright (C) 1999  Steve Belczyk <steve1@genesis.nred.ma.us>
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20. */
  21.  
  22. #include "orbit.h"
  23.  
  24. #ifndef WIN32
  25. #include <sys/socket.h>
  26. #include <unistd.h>
  27. #include <netinet/in.h>
  28. #include <netdb.h>
  29. #include <arpa/inet.h>
  30. #include <netinet/tcp.h>
  31. #endif
  32.  
  33. #include <limits.h>
  34. #include <fcntl.h>
  35. #include <errno.h>
  36. #include <stdarg.h>
  37.  
  38. /*
  39.  *  All sorts of stuff for network communication
  40.  */
  41.  
  42. int endian;    /* Endian for transmitting network values */
  43.  
  44. InitNetwork()
  45. /*
  46.  *  Initialize network data structures
  47.  */
  48. {
  49.     int c;
  50.  
  51.     Log ("InitNetwork: Initializing network");
  52.  
  53.     am_server = 0;
  54.     am_client = 0;
  55.  
  56.     recv_bytes = xmit_bytes = 0;
  57.  
  58.     for (c=0; c<NCLIENTS; c++)
  59.     {
  60.         client[c].active = 0;
  61.         client[c].is_me = 0;
  62.         client[c].ping = 0.0;
  63.         client[c].target = (-1);
  64.         client[c].frags = 0;
  65.         client[c].ip[0] = 0;
  66.  
  67.         client[c].timer.idle = 0.0;
  68.         client[c].timer.ping = 0.0;
  69.  
  70.         client[c].state = NETSTATE_MAGIC;
  71.     }
  72. }
  73.  
  74. int OpenNetwork()
  75. /*
  76.  *  Really only need this for Winsock
  77.  */
  78. {
  79. #ifdef WIN32
  80.     WSADATA wsadata;
  81. #endif
  82.  
  83.     Log ("OpenNetwork: Opening network");
  84.  
  85. #ifdef WIN32
  86.     if (SOCKET_ERROR == WSAStartup (0x202, &wsadata))
  87.     {
  88.         Log ("OpenNetwork: WSAStartup failed with error %d",
  89.             WSAGetLastError());
  90.         WSACleanup();
  91.         return 0;
  92.     }
  93. #endif
  94.  
  95.     return 1;
  96. }
  97.  
  98. int CloseNetwork()
  99. /*
  100.  *  Close Winsock
  101.  */
  102. {
  103.     Log ("CloseNetwork: Closing network");
  104.  
  105. #ifdef WIN32
  106.     WSACleanup();
  107. #endif
  108. }
  109.  
  110. int BecomeServer()
  111. /*
  112.  *  Become an ORBIT server
  113.  */
  114. {
  115.     struct sockaddr_in address;
  116.     SOCKET listening_socket;
  117.     int one = 1;
  118.     int b, t, c;
  119.  
  120.     Cprint ("Becoming ORBIT server...");
  121.     Log ("BecomeServer: Becoming ORBIT server...");
  122.  
  123.     /* Determine how to send floats */
  124.     if (!FindEndian()) return 0;
  125.  
  126.     /* Open Winsock */
  127.     if (!OpenNetwork()) return 0;
  128.  
  129.     /* Set address and port to listen on */
  130.     memset ((char *) &address, 0, sizeof(address));
  131.     address.sin_family = AF_INET;
  132.     address.sin_port = htons (server.port);
  133.     address.sin_addr.s_addr = htonl (INADDR_ANY);
  134.  
  135.     /* Create the socket.  This shouldn't cause any network activity;
  136.        it's just creating a kernel data structure */
  137.     Log ("BecomeServer: creating listening socket");
  138.     listening_socket = socket (AF_INET, SOCK_STREAM, 0);
  139.     if (listening_socket < 0)
  140.     {
  141.         Log ("BecomeServer: socket returned %d", listening_socket);
  142.         CloseNetwork();
  143.         return 0;
  144.     }
  145.  
  146.     /* Remember listening socket so we can close it later */
  147.     server.listening_socket = listening_socket;
  148.  
  149.     /* Set the listening socket option SO_REUSEADDR. */
  150.     setsockopt (listening_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
  151.         sizeof(one));
  152.  
  153.     /* Bind the listening socket to the address information */
  154.     b = bind (listening_socket, (struct sockaddr *) &address, sizeof(address));
  155.     if (b < 0)
  156.     {
  157.         Log ("BecomeServer: bind() returned %d", b);
  158. #ifndef WIN32
  159.         close (listening_socket);
  160. #else
  161.         closesocket (listening_socket);
  162. #endif
  163.         CloseNetwork();
  164.         return 0;
  165.     }
  166.  
  167.     /* Set number of connections to queue */
  168.     listen (listening_socket, 3);
  169.  
  170.     /* Put the socket in non-blocking mode so we can poll it
  171.        (This should really be done by getting the flags and setting
  172.        the one bit) */
  173. #ifdef WIN32
  174.     ioctlsocket (listening_socket, FIONBIO, &one);
  175. #else
  176.     fcntl (listening_socket, F_SETFL, O_NONBLOCK);
  177. #endif
  178.  
  179.     /* Remember I'm a server */
  180.     am_server = 1;
  181.  
  182.     /* Save IP address? */
  183.     strcpy (server.ip, inet_ntoa(address.sin_addr));
  184.  
  185.     Cprint ("Now an ORBIT server, listening on port %d", server.port);
  186.     Log ("BecomeServer: Successfully became server");
  187.  
  188.     /* Reset targets, events, weapons and planets, etc; */
  189.     InitTargets();
  190.     ResetEvents();
  191.     InitWeapons();
  192.     ResetPlanets();
  193.     InitWaypoints();
  194.     ResetModels();
  195.     lock.target = (-1);
  196.     compression = 1.0;
  197.  
  198.     /* Network players are always vulnerable */
  199.     vulnerable = 1;
  200.  
  201.     /* Set up a client and target for me */
  202.     c = FindClient();
  203.     client[c].active = 1;
  204.     client[c].is_me = 1;
  205.     server.client = c;
  206.     t = client[c].target = InitClientTarget();
  207.     strcpy (target[t].name, player.name);
  208.     target[t].hidden = target[t].invisible = 1;
  209.  
  210.     return 1;
  211. }
  212.  
  213. int BecomeClient (s)
  214. char *s;
  215. /*
  216.  *  Try to become ORBIT client
  217.  */
  218. {
  219. /*    struct in_addr *addr;    */
  220.     SOCKET sock;
  221.     int c, port;
  222.     struct sockaddr_in address;
  223.     char ip[128];
  224.  
  225. #ifdef WIN32
  226.     unsigned long one = 1;
  227. #else
  228.     int one = 1;
  229. #endif
  230.  
  231.     Log ("BecomeClient: Trying to become client");
  232.  
  233.     /* Determine how to send floats */
  234.     if (!FindEndian()) return 0;
  235.  
  236.     /* Parse address as ip[ port] */
  237.     port = (-1);
  238.     sscanf (s, "%s %d", ip, &port);
  239.  
  240.     /* Init Winsock */
  241.     if (!OpenNetwork()) return 0;
  242.  
  243.     /* Set up address, port of server */
  244.     address.sin_family = AF_INET;
  245.     address.sin_port = htons ((port < 0) ? ORBIT_PORT : port);
  246.     address.sin_addr.s_addr = inet_addr (ip);
  247.  
  248.     /* Create the socket */
  249.     sock = socket (AF_INET, SOCK_STREAM, 0);
  250.     if (sock < 0)
  251.     {
  252.         Log ("BecomeClient: socket error: %d", errno);
  253.         CloseNetwork();
  254.         return 0;
  255.     }
  256.  
  257.     /* Connect to the server */
  258.     Log ("BecomeClient: Connecting to server %s on port %d...",
  259.         ip, (port < 0 ? ORBIT_PORT : port));
  260.     Cprint ("Connecting to server %s on port %d...",
  261.         ip, (port < 0 ? ORBIT_PORT : port));
  262.     c = connect (sock, (struct sockaddr *) &address, sizeof(address));
  263.  
  264.     /* Did it work? */
  265.     if (c < 0)
  266.     {
  267.         /* No */
  268.         Mprint ("Could not connect to server");
  269.         Log ("BecomeClient: connect() error: %d", errno);
  270.         CloseNetwork();
  271.         return 0;
  272.     }
  273.  
  274.     /* Yes!  We are connected */
  275.     Mprint ("Connected to server");
  276.     Log ("BecomeClient: Connected to server");
  277.  
  278.     /* Declare I am a client */
  279.     am_client = 1;
  280.  
  281.     /* Remember this socket */
  282.     clientme.socket = sock;
  283.  
  284.     /* Make the socket non-blocking */
  285. #ifdef WIN32
  286.     ioctlsocket (clientme.socket, FIONBIO, &one);
  287. #else
  288.     fcntl (clientme.socket, F_SETFL, O_NONBLOCK);
  289. #endif
  290.  
  291.     /* Disable the Nagle algorithm */
  292.     setsockopt (clientme.socket, IPPROTO_TCP, TCP_NODELAY, (char *) &one,
  293.         sizeof(one));
  294.  
  295.     /* Init incoming packet buffer */
  296.     clientme.pkt[0] = 0;
  297.     clientme.ptr = 0;
  298.  
  299.     /* Init timers */
  300.     clientme.timer.pos = 0.0;
  301.     clientme.timer.server = 0.0;
  302.  
  303.     /* Init packet state */
  304.     clientme.state = NETSTATE_MAGIC;
  305.  
  306.     /* Send our name and model */
  307.     SendASCIIPacket (clientme.socket, "NAME %s\n", player.name);
  308.     SendASCIIPacket (clientme.socket, "MODL %s\n", player.model);
  309.     SendASCIIPacket (clientme.socket, "VERS %s\n", VERSION);
  310.  
  311.     /* Report our position */
  312.     ReportPosition();
  313.  
  314.     /* Network players are always vulnerable */
  315.     vulnerable = 1;
  316.  
  317.     /* Reset targets, events, weapons and planets, etc; */
  318.     InitTargets();
  319.     ResetEvents();
  320.     InitWeapons();
  321.     ResetPlanets();
  322.     InitWaypoints();
  323.     ResetModels();
  324.     lock.target = (-1);
  325.     compression = 1.0;
  326.  
  327.     return 1;
  328. }
  329.  
  330. DoNetwork()
  331. /*
  332.  *  Process network activity
  333.  */
  334. {
  335.     /* Are we client or server (or neither?) */
  336.     if (am_server) DoServer();
  337.     if (am_client) DoClient();
  338.  
  339.     return;
  340. }
  341.  
  342. void SendASCIIPacket (SOCKET socket, char *fmt, ...)
  343. /*
  344.  *  Write an ASCII packet to given network socket
  345.  */
  346. {
  347.     va_list ap;
  348.     char buf[1024];
  349.     int len;
  350. #ifndef BINARYPACKETS
  351.     int e;
  352. #endif
  353.  
  354.     /* Start up varargs stuff */
  355.     va_start (ap, fmt);
  356.  
  357.     /* Get packet into string */
  358.     vsprintf (buf, fmt, ap);
  359.  
  360.     /* Wrap up varargs */
  361.     va_end (ap);
  362.  
  363.     /* Add trailing null */
  364.     buf[strlen(buf)] = 0;
  365.  
  366.     /* Send it */
  367.     len = 1 + strlen (buf);
  368. #ifdef BINARYPACKETS
  369.     XmitBinaryPacket (socket, buf, len);
  370. #else
  371.     e = send (socket, buf, len, 0);
  372. #endif
  373.     xmit_bytes += len;
  374. }
  375.  
  376. XmitBinaryPacket (socket, buf, len)
  377. SOCKET socket;
  378. char *buf;
  379. int len;
  380. {
  381.     char pkt[512];
  382.     int i;
  383.  
  384.     /* Length check */
  385.     if (len > 255)
  386.     {
  387.         Cprint ("PANIC: Packet too large: %d", len);
  388.         return;
  389.     }
  390.  
  391.     /* Put in magic byte */
  392.     pkt[0] = NET_MAGIC;
  393.  
  394.     /* Put in size */
  395.     pkt[1] = len;
  396.  
  397.     /* Put in data */
  398.     for (i=0; i<len; i++) pkt[2+i] = buf[i];
  399.  
  400.     /* Send it! */
  401.     send (socket, pkt, len+2, 0);
  402. }
  403.  
  404. ShutdownClient()
  405. /*
  406.  *  Undo being a client
  407.  */
  408. {
  409.     if (!am_client) return;
  410.  
  411.     Log ("ShutdownClient: Shutting down network client");
  412.  
  413.     /* Close the socket to the server */
  414. #ifndef WIN32
  415.     close (clientme.socket);
  416. #else
  417.     closesocket (clientme.socket);
  418. #endif
  419.  
  420.     /* Shut down Winsock */
  421.     CloseNetwork();
  422.  
  423.     /* Show no longer client */
  424.     am_client = 0;
  425.  
  426.     /* Tell Sparky */
  427.     Mprint ("Disconnected from server");
  428.  
  429.     /* Reset network data structures */
  430.     InitNetwork();
  431.     InitTargets();
  432. }
  433.  
  434. ShutdownServer()
  435. /*
  436.  *  Stop being a server
  437.  */
  438. {
  439.     int c;
  440.  
  441.     if (!am_server) return;
  442.  
  443.     Log ("ShutdownServer: Shutting down network server");
  444.  
  445.     /* Close each active client connection */
  446.     for (c=0; c<NCLIENTS; c++)
  447.     {
  448.         if (client[c].active && (c != server.client))
  449.         {
  450.             Log ("ShutdownServer: Closing client %d", c);
  451.             DropClient (c);
  452.         }
  453.     }
  454.  
  455.     /* Stop listening for clients */
  456. #ifndef WIN32
  457.     close (server.listening_socket);
  458. #else
  459.     closesocket (server.listening_socket);
  460. #endif
  461.  
  462.     /* Shut down Winsock */
  463.     CloseNetwork();
  464.  
  465.     /* No longer server */
  466.     am_server = 0;
  467.  
  468.     /* Hey Sparky */
  469.     Mprint ("No longer a server");
  470.  
  471.     /* Reset network data structures */
  472.     InitNetwork();
  473. }
  474.  
  475. ShutdownNetwork()
  476. /*
  477.  *  Shut down all network connections and services
  478.  */
  479. {
  480.     Log ("ShutdownNetwork: Shutting down network");
  481.  
  482.     if (am_server) ShutdownServer();
  483.     if (am_client) ShutdownClient();
  484. }
  485.  
  486. DropClient (c)
  487. int c;
  488. /*
  489.  *  Hang up on client c
  490.  */
  491. {
  492.     int cc;
  493. #ifndef WIN32
  494.     close (client[c].socket);
  495. #else
  496.     closesocket (client[c].socket);
  497. #endif
  498.  
  499.     client[c].active = 0;
  500.  
  501.     /* Notify us */
  502.     Cprint ("%s is gone", target[client[c].target].name);
  503.  
  504.     /* Notify everyone */
  505.     for (cc=0; cc<NCLIENTS; cc++)
  506.     {
  507.         if (client[cc].active && (cc != server.client) && (c != cc) )
  508.         {
  509.             SendASCIIPacket (client[cc].socket, "GBYE %d %s",
  510.                 c, target[client[c].target].name);
  511.         }
  512.     }
  513.  
  514.     /* Destroy associated target */
  515.     DestroyTarget (client[c].target);
  516. }
  517.  
  518. QueuePositionReport()
  519. /*
  520.  *  Force our position to be sent
  521.  */
  522. {
  523.     int c;
  524.  
  525.     if (am_client)
  526.     {
  527.         clientme.timer.pos = CLIENTPOSINTERVAL;
  528.     }
  529.     else if (am_server)
  530.     {
  531.         for (c=0; c<NCLIENTS; c++)
  532.         {
  533.             client[c].timer.posn[server.client] = client[c].posninterval;
  534.         }
  535.     }
  536. }
  537.  
  538. int InitClientTarget()
  539. /*
  540.  *  Set up a target for a client
  541.  */
  542. {
  543.     int m, t;
  544.  
  545.     t = FindTarget();
  546.     target[t].age = 0.1;
  547.     strcpy (target[t].name, "Sparky");
  548.     target[t].invisible = 0;
  549.     target[t].hidden = 0;
  550.     target[t].model = m = LoadModel ("light2.tri");
  551.     target[t].list = model[m].list;
  552.     target[t].shieldregen = SHIELD_REGEN;
  553.  
  554.     return t;
  555. }
  556.  
  557. NetHitTarget (t, m)
  558. int t, m;
  559. /*
  560.  *  Target t was hit by missile m
  561.  */
  562. {
  563.     int c;
  564.  
  565.     if (!am_server) return;
  566.  
  567.     /* Find the client that belongs to this target */
  568.     c = FindClientByTarget (t);
  569.  
  570.     /* Don't bother if it's me */
  571.     if (c == server.client) return;
  572.  
  573.     /* Send them the packet */
  574.     if (client[c].active)
  575.     {
  576.         SendASCIIPacket (client[c].socket,
  577.             "MHIT %lf", weapon[msl[m].weapon].yield);
  578.     }
  579. }
  580.  
  581. NetDestroyTarget (t, m)
  582. int t, m;
  583. /*
  584.  *  Target t was destroyed by missile m
  585.  */
  586. {
  587.     int cvictim, ckiller;
  588.  
  589.     if (!am_server) return;
  590.  
  591.     /* Find the client that belongs to the victim */
  592.     cvictim = FindClientByTarget (t);
  593.  
  594.     /* Find the client that belongs to the killer */
  595.     ckiller = FindClientByTarget (msl[m].owner);
  596.  
  597.     /* Tell everyone */
  598.     NetDestroyClient (cvictim, ckiller);
  599. }
  600.  
  601. NetDestroyClient (cv, ck)
  602. int cv, ck;
  603. /*
  604.  *  Client cv was killed by client ck
  605.  */
  606. {
  607.     int c;
  608.  
  609.     /* Adjust frags */
  610.     client[ck].frags++;
  611.  
  612.     /* Tell everyone */
  613.     for (c=0; c<NCLIENTS; c++)
  614.     {
  615.         if (client[c].active && (c != server.client) )
  616.         {
  617.             SendASCIIPacket (client[c].socket, "MDIE %d %d", cv, ck);
  618.         }
  619.     }
  620.  
  621.     /* Tell me */
  622.     Cprint ("%s was killed by %s",
  623.         target[client[cv].target].name,
  624.         target[client[ck].target].name);
  625.  
  626.     /* Make client's target hidden */
  627.     if (cv != server.client) target[client[cv].target].hidden = 1;
  628.  
  629.     CheckLock();
  630. }
  631.  
  632. NetTargetCratered (t, p)
  633. int t, p;
  634. /*
  635.  *  Target t cratered on planet p
  636.  */
  637. {
  638.     int c, cc;
  639.  
  640.     /* Get client */
  641.     cc = FindClientByTarget (t);
  642.  
  643.     /* Adjust frags */
  644.     client[cc].frags--;
  645.  
  646.     /* Tell everyone */
  647.     for (c=0; c<NCLIENTS; c++)
  648.     {
  649.         if (client[c].active && (c != server.client) )
  650.         {
  651.             SendASCIIPacket (client[c].socket, "CRAT %d %d", cc, p);
  652.         }
  653.     }
  654.  
  655.     /* Tell me */
  656.     Cprint ("%s cratered on %s", target[t].name, planet[p].name);
  657.  
  658.     /* Hide target */
  659.     if (cc != server.client) target[t].hidden = 1;
  660.  
  661.     CheckLock();
  662. }    
  663.  
  664. FindClientByTarget (t)
  665. int t;
  666. /*
  667.  *  Figure out what client belongs to this target
  668.  */
  669. {
  670.     int c;
  671.  
  672.     /* Is it me? */
  673.     if (t == (-1)) return server.client;
  674.  
  675.     /* Loop through clients */
  676.     for (c=0; c<NCLIENTS; c++)
  677.     {
  678.         if (client[c].active && (t==client[c].target) ) return c;
  679.     }
  680.  
  681.     /* When in doubt, make it me */
  682.     return server.client;
  683. }
  684.  
  685. NetClientFires (clnt, wep)
  686. int clnt, wep;
  687. /*
  688.  *  Client clnt has fired weapon wep
  689.  */
  690. {
  691.     double v[3], d;
  692.     int c, t1, t2;
  693.  
  694.     if (!am_server) return;
  695.  
  696.     t1 = client[clnt].target;
  697.  
  698.     /* Loop through clients */
  699.     for (c=0; c<NCLIENTS; c++)
  700.     {
  701.         if (client[c].active && (c != clnt) && (c != server.client))
  702.         {
  703.             t2 = client[c].target;
  704.  
  705.             /* Find distance between clients */
  706.             Vsub (v, target[t1].pos, target[t2].pos);
  707.             d = Mag2 (v);
  708.  
  709.             /* Don't bother if too far */
  710.             if (d > TARG_MAXRANGE2) continue;
  711.  
  712.             /* Send packet */
  713.             SendASCIIPacket (client[c].socket,
  714.                 "FIRE %d %d", clnt, wep);
  715.         }
  716.     }
  717. }
  718.  
  719. NetPlayerDies()
  720. /*
  721.  *  We died in a network game
  722.  */
  723. {
  724.     double v[3];
  725.     int i;
  726.  
  727.     /* Change game state */
  728.     state = STATE_DEAD1;
  729.  
  730.     /* Set up timer */
  731.     player.dead_timer = DEAD_TIME;
  732.  
  733.     /* Stop Sparky */
  734.     player.vel[0] = player.vel[1] = player.vel[2] = 0.0;
  735.  
  736.     /* Assign new position */
  737.     do
  738.     {
  739.         for (i=0; i<3; i++) v[i] = player.pos[i] +
  740.             rnd(1000000.0/KM_TO_UNITS1) - 500000.0/KM_TO_UNITS1;
  741.     } while (!RespawnOkay(v));
  742.     Vset (player.pos, v);
  743.  
  744.     /* Give Zorkian message */
  745.     Mprint ("*** You have died ***");
  746. }
  747.  
  748. int RespawnOkay (v)
  749. double v[3];
  750. /*
  751.  *  Check if respawn location is okay
  752.  */
  753. {
  754.     int p;
  755.     double v1[3], d;
  756.  
  757.     for (p=0; p<NPLANETS; p++)
  758.     {
  759.         if (!planet[p].hidden)
  760.         {
  761.             /* Compute range to planet */
  762.             Vsub (v1, planet[p].pos, v);
  763.             d = Mag (v1);
  764.  
  765.             /* Too close? */
  766.             if (d < 5.0 * planet[p].radius) return 0;
  767.         }
  768.     }
  769.  
  770.     /* Okay if we got here */
  771.     return 1;
  772. }
  773.  
  774. FindEndian()
  775. /*
  776.  *  Try to figure out the endianness of this machine, especially with
  777.  *  regard to floats.  Kinda kludgy but it's been working great.
  778.  */
  779. {
  780.     union
  781.     {
  782.         unsigned char c[4];
  783.         float f;
  784.     } u;
  785.  
  786.     /* Assume one way */
  787.     endian = 0;
  788.  
  789.     /* Better have 4-byte floats or we're sunk */
  790.     if (4 != sizeof(float))
  791.     {
  792.         Mprint ("PANIC! This machine doesn't use 4-byte floats");
  793.         Log ("FindEndian: PANIC! This machine doesn't use 4-byte floats");
  794.         return 0;
  795.     }
  796.  
  797.     /* Set a float and pick apart the bytes to see if we
  798.        recognize the order */
  799.     u.f = 3141.59;
  800.  
  801.     /* Test one way */
  802.     if ( (u.c[0] == 0x45) && (u.c[1] == 0x44) &&
  803.          (u.c[2] == 0x59) && (u.c[3] == 0x71) )
  804.     {
  805.         /* Yay! It's MIPS, SPARC, RS/6000, HP or something
  806.            like that */
  807.         endian = 0;
  808.         return 1;
  809.     }
  810.  
  811.     /* Hmm, test other way */
  812.     if ( (u.c[0] == 0x71) && (u.c[1] == 0x59) &&
  813.          (u.c[2] == 0x44) && (u.c[3] == 0x45) )
  814.     {
  815.         /* Yay! Intel or DEC or something like that */
  816.         endian = 1;
  817.         return 1;
  818.     }
  819.  
  820.     /* Bad news, Sparky! */
  821.     Mprint ("Unrecognized floating point format! No network for you!");
  822.     Log ("FindEndian: Unrecognized floating point format");
  823.     
  824.     return 0;
  825. }
  826.  
  827. EncFloat (d, c)
  828. double d;
  829. unsigned char *c;
  830. /*
  831.  *  Encode a double
  832.  */
  833. {
  834.     union
  835.     {
  836.         unsigned char c[4];
  837.         float f;
  838.     } u;
  839.  
  840.     /* Convert to float */
  841.     u.f = (float) d;
  842.  
  843.     /* Write bytes */
  844.     if (endian)
  845.     {
  846.         c[0] = u.c[0];
  847.         c[1] = u.c[1];
  848.         c[2] = u.c[2];
  849.         c[3] = u.c[3];
  850.     }
  851.     else
  852.     {
  853.         c[0] = u.c[3];
  854.         c[1] = u.c[2];
  855.         c[2] = u.c[1];
  856.         c[3] = u.c[0];
  857.     }
  858. }
  859.  
  860. double DecFloat (c)
  861. unsigned char *c;
  862. /*
  863.  *  Decode a float
  864.  */
  865. {
  866.     union
  867.     {
  868.         unsigned char c[4];
  869.         float f;
  870.     } u;
  871.  
  872.     /* Move into union */
  873.     if (endian)
  874.     {
  875.         u.c[0] = c[0];
  876.         u.c[1] = c[1];
  877.         u.c[2] = c[2];
  878.         u.c[3] = c[3];
  879.     }
  880.     else
  881.     {
  882.         u.c[3] = c[0];
  883.         u.c[2] = c[1];
  884.         u.c[1] = c[2];
  885.         u.c[0] = c[3];
  886.     }
  887.  
  888.     return (double) u.f;
  889. }
  890.  
  891. EncVector (double v[3], char *c)
  892. /*
  893.  *  Encode a whole vector
  894.  */
  895. {
  896.     EncFloat (v[0], &c[0]);
  897.     EncFloat (v[1], &c[4]);
  898.     EncFloat (v[2], &c[8]);
  899. }
  900.  
  901. EncUnitVector (double v[3], char *c)
  902. /*
  903.  *  Encode vector of unit floats
  904.  */
  905. {
  906.     c[0] = EncUnitFloat (v[0]);
  907.     c[1] = EncUnitFloat (v[1]);
  908.     c[2] = EncUnitFloat (v[2]);
  909. }
  910.  
  911. DecVector (v, c)
  912. double v[3];
  913. unsigned char *c;
  914. /*
  915.  *  Decode a whole vector
  916.  */
  917. {
  918.     v[0] = DecFloat (&c[0]);
  919.     v[1] = DecFloat (&c[4]);
  920.     v[2] = DecFloat (&c[8]);
  921. }
  922.  
  923. int EncUnitFloat (d)
  924. double d;
  925. /*
  926.  *  Convert double on [-1,1] to integer on [0,255]
  927.  */
  928. {
  929.     int i;
  930.  
  931.     if (d < -1.0) d = -1.0;
  932.     if (d >  1.0) d =  1.0;
  933.  
  934.     i = (int) ((d + 1.0) * 127.5);
  935.  
  936.     return i;
  937. }
  938.  
  939. double DecUnitFloat (c)
  940. unsigned char c;
  941. /*
  942.  *  Convert integer on [0,255] to double on [-1,1]
  943.  */
  944. {
  945.     double d;
  946.     int i;
  947.  
  948.     i = 0xff & c;
  949.     d = (((double) i) / 127.5) - 1.0;
  950.  
  951.     return d;
  952. }
  953.  
  954. DecUnitVector (v, c)
  955. double v[3];
  956. unsigned char *c;
  957. {
  958.     v[0] = DecUnitFloat (c[0]);
  959.     v[1] = DecUnitFloat (c[1]);
  960.     v[2] = DecUnitFloat (c[2]);
  961. }
  962.  
  963. void SendBinaryPacket (SOCKET socket, char *fmt, ...)
  964. /*
  965.  *  Send a binary packet
  966.  */
  967. {
  968.     int i, p, len;
  969.     unsigned char buf[256];
  970.     va_list ap;
  971.  
  972.     /* Start up varargs */
  973.     va_start (ap, fmt);
  974.  
  975.     p = 0;
  976.     len = strlen (fmt);
  977.  
  978.     /* Loop through format */
  979.     for (i=0; i<len; i++)
  980.     {
  981.         switch (fmt[i])
  982.         {
  983.         case 'c':    /* Single character */
  984.             buf[p++] = va_arg (ap, int);
  985.             break;
  986.  
  987.         case 'F':    /* Normal float */
  988.             EncFloat (va_arg (ap, double), &buf[p]);
  989.             p += 4;
  990.             break;
  991.  
  992.         case 'f':    /* Unit float */
  993.             buf[p++] = EncUnitFloat (va_arg (ap, double));
  994.             break;
  995.  
  996.         case 'V':    /* Normal vector */
  997.             EncVector (va_arg (ap, double *), &buf[p]);
  998.             p += 12;
  999.             break;
  1000.  
  1001.         case 'v':    /* Unit vector */
  1002.             EncUnitVector (va_arg (ap, double *), &buf[p]);
  1003.             p += 3;
  1004.             break;
  1005.  
  1006.         default:
  1007.             Log ("SendBinaryPacket: Bad format character: %c", fmt[i]);
  1008.             break;
  1009.         }
  1010.     }
  1011.  
  1012.     va_end (ap);
  1013.  
  1014.     /* Send it off! */
  1015.     XmitBinaryPacket (socket, buf, p);
  1016.     xmit_bytes += 2 + p;
  1017. }
  1018.  
  1019. void DecodeBinaryPacket (char *pkt, char *fmt, ...)
  1020. /*
  1021.  *  Decode a binary packet
  1022.  */
  1023. {
  1024.     int i, p, len;
  1025.     va_list ap;
  1026.     double *d;
  1027.  
  1028.     /* Start up varargs */
  1029.     va_start (ap, fmt);
  1030.  
  1031.     len = strlen (fmt);
  1032.     p = 0;
  1033.  
  1034.     /* Loop through format */
  1035.     for (i=0; i<len; i++)
  1036.     {
  1037.         switch (fmt[i])
  1038.         {
  1039.         case 'c':    /* Single character */
  1040.             *(va_arg (ap, int *)) = pkt[p];
  1041.             p++;
  1042.             break;
  1043.  
  1044.         case 'F':    /* Normal float */
  1045.             *(va_arg (ap, double *)) = DecFloat (&pkt[p]);
  1046.             p += 4;
  1047.             break;
  1048.  
  1049.         case 'f':    /* Unit float */
  1050.             *(va_arg (ap, double *)) = DecUnitFloat (pkt[p]);
  1051.             p++;
  1052.             break;
  1053.  
  1054.         case 'V':    /* Normal vector */
  1055.             d = va_arg (ap, double *);
  1056.             DecVector (d, &pkt[p]);
  1057.             p += 12;
  1058.             break;
  1059.  
  1060.         case 'v':    /* Unit vector */
  1061.             d = va_arg (ap, double *);
  1062.             DecUnitVector (d, &pkt[p]);
  1063.             p += 3;
  1064.             break;
  1065.  
  1066.         default:
  1067.             Log ("DecBinaryPacket: Bad format character: %c", fmt[i]);
  1068.             break;
  1069.         }
  1070.     }
  1071.  
  1072.     va_end (ap);
  1073. }
  1074.  
  1075.