]> git.mxchange.org Git - flightgear.git/blob - src/MultiPlayer/multiplaymgr.cxx
Unused local variable removed
[flightgear.git] / src / MultiPlayer / multiplaymgr.cxx
1 //////////////////////////////////////////////////////////////////////
2 //
3 // multiplaymgr.hpp
4 //
5 // Written by Duncan McCreanor, started February 2003.
6 // duncan.mccreanor@airservicesaustralia.com
7 //
8 // With minor additions by Vivian Meazza, January 2006
9 //
10 // Copyright (C) 2003  Airservices Australia
11 // Copyright (C) 2005  Oliver Schroeder
12 //
13 // This program is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU General Public License as
15 // published by the Free Software Foundation; either version 2 of the
16 // License, or (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful, but
19 // WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 // General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 //
27 // $Id$
28 //  
29 //////////////////////////////////////////////////////////////////////
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #ifdef FG_MPLAYER_AS
36
37 #include <sys/types.h>
38 #if !(defined(_MSC_VER) || defined(__MINGW32__))
39 #   include <sys/socket.h>
40 #   include <netinet/in.h>
41 #   include <arpa/inet.h>
42 #endif
43 #include <stdlib.h>
44
45 #include <plib/netSocket.h>
46
47 #include <simgear/debug/logstream.hxx>
48
49 #include <Main/fg_props.hxx>
50 #include "multiplaymgr.hxx"
51 #include "mpmessages.hxx"
52 #include "mpplayer.hxx"
53
54 #define MAX_PACKET_SIZE 1024
55
56 // These constants are provided so that the ident 
57 // command can list file versions
58 const char sMULTIPLAYMGR_BID[] = 
59     "$Id$";
60 const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID;
61
62 //////////////////////////////////////////////////////////////////////
63 //
64 //  MultiplayMgr constructor
65 //
66 //////////////////////////////////////////////////////////////////////
67 FGMultiplayMgr::FGMultiplayMgr() 
68 {
69     m_Initialised   = false;
70     m_LocalPlayer   = NULL;
71     m_RxAddress     = "0";
72     m_RxPort        = 0;
73     m_Initialised   = false;
74     m_HaveServer    = false;
75
76         send_all_props= false;
77 } // FGMultiplayMgr::FGMultiplayMgr()
78 //////////////////////////////////////////////////////////////////////
79
80 //////////////////////////////////////////////////////////////////////
81 //
82 //  MultiplayMgr destructor
83 //
84 //////////////////////////////////////////////////////////////////////
85 FGMultiplayMgr::~FGMultiplayMgr() 
86 {
87     Close();
88 } // FGMultiplayMgr::~FGMultiplayMgr()
89 //////////////////////////////////////////////////////////////////////
90
91 //////////////////////////////////////////////////////////////////////
92 // Name: getSendAll
93 // Description: getter for send_all
94 /////////////////////////////////////////////////////////////////////
95 bool FGMultiplayMgr::getSendAllProps() {
96         return send_all_props;
97 }
98
99 //////////////////////////////////////////////////////////////////////
100 // Name: setSendAll
101 // Description: setter for send_all
102 /////////////////////////////////////////////////////////////////////
103 void FGMultiplayMgr::setSendAllProps(bool s) {
104         send_all_props = s;
105 }
106
107 //////////////////////////////////////////////////////////////////////
108 //
109 //  Initialise object
110 //
111 //////////////////////////////////////////////////////////////////////
112 bool
113 FGMultiplayMgr::init (void) 
114 {
115     string  TxAddress;      // Destination address
116     int     TxPort;
117
118     //////////////////////////////////////////////////
119     //  Initialise object if not already done
120     //////////////////////////////////////////////////
121     if (m_Initialised) 
122     {
123         SG_LOG( SG_NETWORK, SG_WARN,
124           "FGMultiplayMgr::init - already initialised" );
125         return (false);
126     }
127     //////////////////////////////////////////////////
128     //  Set members from property values
129     //////////////////////////////////////////////////
130     TxAddress      = fgGetString   ("/sim/multiplay/txhost");
131     TxPort         = fgGetInt      ("/sim/multiplay/txport");
132     m_Callsign     = fgGetString   ("/sim/multiplay/callsign");
133     m_RxAddress    = fgGetString   ("/sim/multiplay/rxhost");
134     m_RxPort       = fgGetInt      ("/sim/multiplay/rxport");
135     if (m_RxPort <= 0)
136     {
137         m_RxPort = 5000;
138     }
139     if (m_Callsign == "")
140     {
141         // FIXME: use getpwuid
142         m_Callsign = "JohnDoe"; 
143     }
144     if (m_RxAddress == "")
145     {
146         m_RxAddress = "127.0.0.1";
147     }
148     if ((TxPort > 0) && (TxAddress != ""))
149     {
150         m_HaveServer = true;
151         m_Server.set (TxAddress.c_str(), TxPort); 
152     }
153     SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txaddress= "<<TxAddress);
154     SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-txport= "<<TxPort );
155     SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<m_RxAddress );
156     SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<m_RxPort);
157     SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<m_Callsign);
158     m_DataSocket = new netSocket();
159     if (!m_DataSocket->open(false))
160     {
161         SG_LOG( SG_NETWORK, SG_ALERT,
162           "FGMultiplayMgr::init - Failed to create data socket" );
163         return (false);
164     }
165     m_DataSocket->setBlocking(false);
166     m_DataSocket->setBroadcast(true);
167     if (m_DataSocket->bind(m_RxAddress.c_str(), m_RxPort) != 0)
168     {
169         perror("bind");
170         SG_LOG( SG_NETWORK, SG_ALERT,
171           "FGMultiplayMgr::Open - Failed to bind receive socket" );
172         return (false);
173     }
174     m_LocalPlayer = new MPPlayer();
175     if (!m_LocalPlayer->Open(m_RxAddress, m_RxPort, m_Callsign,
176                             fgGetString("/sim/model/path"), true)) 
177     {
178         SG_LOG( SG_NETWORK, SG_ALERT,
179           "FGMultiplayMgr::init - Failed to create local player" );
180         return (false);
181     }
182     m_Initialised = true;
183         send_all_props= true;
184     return (true);
185 } // FGMultiplayMgr::init()
186 //////////////////////////////////////////////////////////////////////
187
188 //////////////////////////////////////////////////////////////////////
189 //
190 //  Closes and deletes the local player object. Closes
191 //  and deletes the tx socket. Resets the object state to unitialised.
192 //
193 //////////////////////////////////////////////////////////////////////
194 void
195 FGMultiplayMgr::Close (void) 
196 {
197     //////////////////////////////////////////////////
198     //  Delete local player
199     //////////////////////////////////////////////////
200     if (m_LocalPlayer) 
201     {
202         delete m_LocalPlayer;
203         m_LocalPlayer = NULL;
204     }
205     //////////////////////////////////////////////////
206     //  Delete any existing players
207     //////////////////////////////////////////////////
208     t_MPClientListIterator CurrentPlayer;
209     t_MPClientListIterator P;
210     CurrentPlayer  = m_MPClientList.begin ();
211     while (CurrentPlayer != m_MPClientList.end ())
212     {
213         P = CurrentPlayer;
214         delete (*P);
215         *P = 0;
216         CurrentPlayer = m_MPClientList.erase (P);
217     }
218     //////////////////////////////////////////////////
219     //  Delete socket
220     //////////////////////////////////////////////////
221     if (m_DataSocket) 
222     {
223         m_DataSocket->close();
224         delete m_DataSocket;
225         m_DataSocket = NULL;
226     }
227     m_Initialised = false;
228 } // FGMultiplayMgr::Close(void)
229 //////////////////////////////////////////////////////////////////////
230
231 //////////////////////////////////////////////////////////////////////
232 //
233 //  Description: Sends the position data for the local position.
234 //
235 //////////////////////////////////////////////////////////////////////
236 void
237 FGMultiplayMgr::SendMyPosition
238     (
239         const double lat, const double lon, const double alt,
240         const double heading, const double roll, const double pitch,
241         const double speedN, const double speedE, const double speedD,
242         const double left_aileron, const double right_aileron, const double elevator, const double rudder,
243         //const double rpms[6],
244         const double rateH, const double rateR, const double rateP,
245                 const double accN, const double accE, const double accD
246     )
247 {
248     T_MsgHdr        MsgHdr;
249     T_PositionMsg   PosMsg;
250     char Msg[sizeof(T_MsgHdr) + sizeof(T_PositionMsg)];
251
252     if ((! m_Initialised) || (! m_HaveServer))
253     {
254         if (! m_Initialised)
255         SG_LOG( SG_NETWORK, SG_ALERT,
256           "FGMultiplayMgr::SendMyPosition - not initialised" );
257         if (! m_HaveServer)
258         SG_LOG( SG_NETWORK, SG_ALERT,
259           "FGMultiplayMgr::SendMyPosition - no server" );
260         return;
261     }
262     m_LocalPlayer->SetPosition(lat, lon, alt,
263                                heading, roll, pitch,
264                                speedN, speedE, speedD,
265                                left_aileron, right_aileron, elevator, rudder,
266                                //rpms,
267                                rateH, rateR, rateP,
268                                                            accN, accE, accD);
269     m_LocalPlayer->FillPosMsg(&MsgHdr, &PosMsg);
270     memcpy(Msg, &MsgHdr, sizeof(T_MsgHdr));
271     memcpy(Msg + sizeof(T_MsgHdr), &PosMsg, sizeof(T_PositionMsg));
272     m_DataSocket->sendto (Msg,
273       sizeof(T_MsgHdr) + sizeof(T_PositionMsg), 0, &m_Server);
274         SG_LOG( SG_NETWORK, SG_DEBUG,
275           "FGMultiplayMgr::SendMyPosition" );
276         
277 } // FGMultiplayMgr::SendMyPosition()
278 //////////////////////////////////////////////////////////////////////
279
280 //////////////////////////////////////////////////////////////////////
281 //
282 //  Description: Sends the property data for the local player.
283 //
284 //////////////////////////////////////////////////////////////////////
285 void FGMultiplayMgr::SendPropMessage (const string &property, SGPropertyNode::Type type, double value)
286         
287         {SG_LOG( SG_NETWORK, SG_INFO,
288           "FGMultiplayMgr::Property: " << property << " Type " << type << " value " << value);
289
290     T_MsgHdr      MsgHdr;
291     T_PropertyMsg PropMsg;
292     unsigned int iNextBlockPosition = 0;
293     char Msg[sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)];
294
295     if ((! m_Initialised) || (! m_HaveServer))
296     {
297         return;
298     }
299     m_LocalPlayer->FillMsgHdr(&MsgHdr, PROP_MSG_ID);
300     
301     strncpy(PropMsg.property, property.c_str(), MAX_PROPERTY_LEN);
302         PropMsg.property[MAX_PROPERTY_LEN-1] = '\0';
303         PropMsg.type = XDR_encode_uint32(type);
304     PropMsg.val = XDR_encode_double(value);
305     SG_LOG( SG_NETWORK, SG_INFO,
306                 "FGMultiplayMgr::sending property message: "
307                  << PropMsg.property << " " << PropMsg.type << " " << PropMsg.val);
308     
309         memcpy (Msg, &MsgHdr, sizeof(T_MsgHdr));
310     memcpy (Msg + sizeof(T_MsgHdr), &PropMsg, sizeof(T_PropertyMsg));
311     m_DataSocket->sendto (Msg,
312                           sizeof(T_MsgHdr) + sizeof(T_PropertyMsg), 0, &m_Server);
313 } // FGMultiplayMgr::SendPropMessage ()
314
315 //////////////////////////////////////////////////////////////////////
316 //
317 //  Name: SendTextMessage
318 //  Description: Sends a message to the player. The message must
319 //  contain a valid and correctly filled out header and optional
320 //  message body.
321 //
322 //////////////////////////////////////////////////////////////////////
323 void
324 FGMultiplayMgr::SendTextMessage
325     (
326     const string &MsgText
327     ) const
328 {
329     T_MsgHdr    MsgHdr;
330     T_ChatMsg   ChatMsg;
331     unsigned int iNextBlockPosition = 0;
332     char Msg[sizeof(T_MsgHdr) + sizeof(T_ChatMsg)];
333
334     if ((! m_Initialised) || (! m_HaveServer))
335     {
336         return;
337     }
338     m_LocalPlayer->FillMsgHdr(&MsgHdr, CHAT_MSG_ID);
339     //////////////////////////////////////////////////
340     // Divide the text string into blocks that fit
341     // in the message and send the blocks.
342     //////////////////////////////////////////////////
343     while (iNextBlockPosition < MsgText.length()) 
344     {
345         strncpy (ChatMsg.Text, 
346           MsgText.substr(iNextBlockPosition, MAX_CHAT_MSG_LEN - 1).c_str(),
347           MAX_CHAT_MSG_LEN);
348         ChatMsg.Text[MAX_CHAT_MSG_LEN - 1] = '\0';
349         memcpy (Msg, &MsgHdr, sizeof(T_MsgHdr));
350         memcpy (Msg + sizeof(T_MsgHdr), &ChatMsg, sizeof(T_ChatMsg));
351         m_DataSocket->sendto (Msg,
352           sizeof(T_MsgHdr) + sizeof(T_ChatMsg), 0, &m_Server);
353         iNextBlockPosition += MAX_CHAT_MSG_LEN - 1;
354     }
355 } // FGMultiplayMgr::SendTextMessage ()
356 //////////////////////////////////////////////////////////////////////
357
358 //////////////////////////////////////////////////////////////////////
359 //
360 //  Name: ProcessData
361 //  Description: Processes data waiting at the receive socket. The
362 //  processing ends when there is no more data at the socket.
363 //  
364 //////////////////////////////////////////////////////////////////////
365 void
366 FGMultiplayMgr::ProcessData (void) 
367 {
368     char        Msg[MAX_PACKET_SIZE];   // Buffer for received message
369     int         Bytes;                  // Bytes received
370     T_MsgHdr*   MsgHdr;                 // Pointer to header in received data
371     netAddress  SenderAddress;
372
373     if (! m_Initialised)
374     {
375         SG_LOG( SG_NETWORK, SG_ALERT,
376           "FGMultiplayMgr::ProcessData - not initialised" );
377         return;
378     }
379     //////////////////////////////////////////////////
380     //  Read the receive socket and process any data
381     //////////////////////////////////////////////////
382     do {
383         //////////////////////////////////////////////////
384         //  Although the recv call asks for 
385         //  MAX_PACKET_SIZE of data, the number of bytes
386         //  returned will only be that of the next
387         //  packet waiting to be processed.
388         //////////////////////////////////////////////////
389         Bytes = m_DataSocket->recvfrom (Msg, MAX_PACKET_SIZE, 0,
390                                          &SenderAddress);
391         //////////////////////////////////////////////////
392         //  no Data received
393         //////////////////////////////////////////////////
394         if (Bytes <= 0)
395         {
396             if (errno != EAGAIN)
397             {
398                 perror("FGMultiplayMgr::MP_ProcessData");
399             }
400             return;
401         }
402         if (Bytes <= (int)sizeof(MsgHdr)) 
403         {
404             SG_LOG( SG_NETWORK, SG_ALERT,
405               "FGMultiplayMgr::MP_ProcessData - "
406               << "received message with insufficient data" );
407             return;
408         }
409         //////////////////////////////////////////////////
410         //  Read header
411         //////////////////////////////////////////////////
412         MsgHdr = (T_MsgHdr *)Msg;
413         MsgHdr->Magic       = XDR_decode_uint32 (MsgHdr->Magic);
414         MsgHdr->Version     = XDR_decode_uint32 (MsgHdr->Version);
415         MsgHdr->MsgId       = XDR_decode_uint32 (MsgHdr->MsgId);
416         MsgHdr->MsgLen      = XDR_decode_uint32 (MsgHdr->MsgLen);
417         MsgHdr->ReplyPort   = XDR_decode_uint32 (MsgHdr->ReplyPort);
418         if (MsgHdr->Magic != MSG_MAGIC)
419         {
420             SG_LOG( SG_NETWORK, SG_ALERT,
421               "FGMultiplayMgr::MP_ProcessData - "
422               << "message has invalid magic number!" );
423         }
424         if (MsgHdr->Version != PROTO_VER) 
425         {
426             SG_LOG( SG_NETWORK, SG_ALERT,
427               "FGMultiplayMgr::MP_ProcessData - "
428               << "message has invalid protocoll number!" );
429         }
430         //////////////////////////////////////////////////
431         //  Process the player data unless we generated it
432         //////////////////////////////////////////////////
433         if (m_Callsign == MsgHdr->Callsign) 
434         {
435             return;
436         }
437         //////////////////////////////////////////////////
438         //  Process messages
439         //////////////////////////////////////////////////
440         switch(MsgHdr->MsgId)
441         {
442             case CHAT_MSG_ID:
443                 ProcessChatMsg ((char*) & Msg, SenderAddress);
444                 break;
445             case POS_DATA_ID:
446                 ProcessPosMsg ((char*) & Msg, SenderAddress);
447                 break;
448             case PROP_MSG_ID:
449                 ProcessPropMsg ((char *) & Msg, SenderAddress);
450                 break;
451             default:
452                 SG_LOG( SG_NETWORK, SG_ALERT,
453                   "FGMultiplayMgr::MP_ProcessData - "
454                   << "Unknown message Id received: " 
455                   << MsgHdr->MsgId );
456                 break;
457         } // switch
458     } while (Bytes > 0);
459 } // FGMultiplayMgr::ProcessData(void)
460 //////////////////////////////////////////////////////////////////////
461
462 //////////////////////////////////////////////////////////////////////
463 //
464 //  handle a position message
465 //
466 //////////////////////////////////////////////////////////////////////
467 void
468 FGMultiplayMgr::ProcessPosMsg
469     (
470     const char *Msg,
471     netAddress & SenderAddress
472     )
473 {
474     T_PositionMsg*  PosMsg;     // Pointer to position message in received data
475     T_MsgHdr*       MsgHdr;     // Pointer to header in received data
476     bool            ActivePlayer; 
477     int             time, timeusec;
478     double          lat, lon, alt;
479     double          hdg, roll, pitch;
480     double          speedN, speedE, speedD;
481     double          left_aileron, right_aileron, elevator, rudder;
482     //double        rpms[6];
483     double          rateH, rateR, rateP;
484     double          accN, accE, accD;
485     t_MPClientListIterator CurrentPlayer;
486
487     ActivePlayer = false;
488     MsgHdr = (T_MsgHdr *)Msg;
489     if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PositionMsg))
490     {
491         SG_LOG( SG_NETWORK, SG_ALERT,
492           "FGMultiplayMgr::MP_ProcessData - "
493           << "Position message received with insufficient data" );
494         return;
495     } else if (MsgHdr->MsgLen > sizeof(T_MsgHdr) + sizeof(T_PositionMsg)) {
496         SG_LOG( SG_NETWORK, SG_ALERT,
497                 "FGMultiplayMgr::MP_ProcessData - "
498                 << "Position message received with more data than I can handle" );
499     }
500     PosMsg = (T_PositionMsg *)(Msg + sizeof(T_MsgHdr));
501     time = XDR_decode_uint32 (PosMsg->time);
502     timeusec = XDR_decode_uint32 (PosMsg->timeusec);
503     lat = XDR_decode_double (PosMsg->lat);
504     lon = XDR_decode_double (PosMsg->lon);
505     alt = XDR_decode_double (PosMsg->alt);
506     hdg = XDR_decode_double (PosMsg->hdg);
507     roll = XDR_decode_double (PosMsg->roll);
508     pitch = XDR_decode_double (PosMsg->pitch);
509     speedN = XDR_decode_double (PosMsg->speedN);
510     speedE = XDR_decode_double (PosMsg->speedE);
511     speedD = XDR_decode_double (PosMsg->speedD);
512     left_aileron = XDR_decode_float (PosMsg->left_aileron);
513     right_aileron = XDR_decode_float (PosMsg->right_aileron);
514     elevator = XDR_decode_float (PosMsg->elevator);
515     rudder = XDR_decode_float (PosMsg->rudder);
516     /*for (int i = 0; i < 6; i++) {
517         rpms[i] = XDR_decode_float (PosMsg->rpms[i]);
518     }*/
519     rateH = XDR_decode_float (PosMsg->rateH);
520     rateR = XDR_decode_float (PosMsg->rateR);
521     rateP = XDR_decode_float (PosMsg->rateP);
522     accN = XDR_decode_float (PosMsg->accN);
523     accE = XDR_decode_float (PosMsg->accE);
524     accD = XDR_decode_float (PosMsg->accD);
525
526     //////////////////////////////////////////////////
527     //  Check if the player is already in the game 
528     //  by using the Callsign
529     //////////////////////////////////////////////////
530     for (CurrentPlayer  = m_MPClientList.begin ();
531          CurrentPlayer != m_MPClientList.end ();
532          CurrentPlayer++)
533     {
534         if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
535         {
536             // Player found. Update the data for the player if the timestamp is OK
537             if ((*CurrentPlayer)->CheckTime(time, timeusec))
538                 (*CurrentPlayer)->SetPosition(lat, lon, alt,
539                                               hdg, roll, pitch,
540                                               speedN, speedE, speedD,
541                                               left_aileron, right_aileron, elevator, rudder,
542                                               //rpms,
543                                               rateH, rateR, rateP,
544                                                                                           accN, accE, accD
545                                                                                           );
546             ActivePlayer = true;
547         }
548     } // for (...)
549     if (ActivePlayer) 
550     {   // nothing more to do
551         return;
552     }
553     //////////////////////////////////////////////////
554     //  Player not active, so add as new player
555     //////////////////////////////////////////////////
556     MPPlayer* NewPlayer;
557     NewPlayer = new MPPlayer;
558     NewPlayer->Open(SenderAddress.getHost(), MsgHdr->ReplyPort,
559         MsgHdr->Callsign, PosMsg->Model, false);
560     if (NewPlayer->CheckTime(time, timeusec))
561         NewPlayer->SetPosition(lat, lon, alt,
562                                hdg, roll, pitch,
563                                speedN, speedE, speedD,
564                                left_aileron, right_aileron, elevator, rudder,
565                                //rpms,
566                                rateH, rateR, rateP,
567                                                            accN, accE, accD);
568     m_MPClientList.push_back (NewPlayer);
569
570         // if we have a new player then we need to send all our properties
571         send_all_props = true;
572
573 } // FGMultiplayMgr::ProcessPosMsg()
574 //////////////////////////////////////////////////////////////////////
575
576 //////////////////////////////////////////////////////////////////////
577 //
578 //  handle a chat message
579 //  FIXME: display chat message withi flightgear
580 //
581 //////////////////////////////////////////////////////////////////////
582 void
583 FGMultiplayMgr::ProcessChatMsg
584     (
585     const char *Msg,
586     netAddress & SenderAddress
587     )
588 {
589     T_ChatMsg*  ChatMsg;    // Pointer to chat message in received data
590     T_MsgHdr*   MsgHdr;     // Pointer to header in received data
591
592     MsgHdr = (T_MsgHdr *)Msg;
593     if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + 1)
594     {
595         SG_LOG( SG_NETWORK, SG_ALERT,
596           "FGMultiplayMgr::MP_ProcessData - "
597           << "Chat message received with insufficient data" );
598         return;
599     }
600     
601     char *MsgBuf = new char[MsgHdr->MsgLen - sizeof(T_MsgHdr)];
602     strncpy(MsgBuf, ((T_ChatMsg *)(Msg + sizeof(T_MsgHdr)))->Text, MsgHdr->MsgLen - sizeof(T_MsgHdr));
603     MsgBuf[MsgHdr->MsgLen - sizeof(T_MsgHdr) - 1] = '\0';
604     
605     ChatMsg = (T_ChatMsg *)(Msg + sizeof(T_MsgHdr));
606     SG_LOG ( SG_NETWORK, SG_ALERT, 
607       "Chat [" << MsgHdr->Callsign << "]" << " " << MsgBuf << endl);
608     delete [] MsgBuf;
609 } // FGMultiplayMgr::ProcessChatMsg ()
610 //////////////////////////////////////////////////////////////////////
611
612 //////////////////////////////////////////////////////////////////////
613 //
614 //  handle a property message
615 //
616 //////////////////////////////////////////////////////////////////////
617 void FGMultiplayMgr::ProcessPropMsg ( const char *Msg, netAddress & SenderAddress )
618 {
619     T_PropertyMsg* PropMsg; // Pointer to the message itself
620     T_MsgHdr*      MsgHdr;  // Pointer to the message header
621     t_MPClientListIterator CurrentPlayer;
622     
623     MsgHdr = (T_MsgHdr *) Msg;
624        
625         if (MsgHdr->MsgLen < sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)) {
626         SG_LOG( SG_NETWORK, SG_ALERT,
627                 "FGMultiplayMgr::MP_ProcessData - "
628                 << "Properties message received with insufficient data" );
629                 return;
630         } else if (MsgHdr->MsgLen > sizeof(T_MsgHdr) + sizeof(T_PropertyMsg)) {
631         SG_LOG( SG_NETWORK, SG_ALERT,
632                 "FGMultiplayMgr::MP_ProcessData - "
633                 << "Properties message received with more data than I know how to handle" );
634                 return;
635         }
636     
637     PropMsg = (T_PropertyMsg *)(Msg + sizeof(T_MsgHdr));
638     
639     //////////////////////////////////////////////////
640     //  Check if the player is already in the game 
641     //  by using the Callsign, but don't activate
642     //  new players (they need to send a position
643     //  message)
644     //////////////////////////////////////////////////
645     for (CurrentPlayer  = m_MPClientList.begin ();
646          CurrentPlayer != m_MPClientList.end ();
647          CurrentPlayer++)
648     {
649         if ((*CurrentPlayer)->CompareCallsign(MsgHdr->Callsign))
650         {
651             // Player found. Update the data for the player.
652             (*CurrentPlayer)->SetProperty(PropMsg->property,
653                                           (SGPropertyNode::Type) XDR_decode_uint32(PropMsg->type),
654                                           XDR_decode_double(PropMsg->val));
655                         SG_LOG( SG_NETWORK, SG_INFO,
656                 "FGMultiplayMgr::MP_ProcessData - "
657                 << PropMsg->property
658                 << (SGPropertyNode::Type) XDR_decode_uint32(PropMsg->type)
659                                 << XDR_decode_double(PropMsg->val) );
660         }
661         } // for (...)
662 }
663
664 //////////////////////////////////////////////////////////////////////
665 //
666 //  For each active player, tell the player object
667 //  to update its position on the scene. If a player object
668 //  returns status information indicating that it has not
669 //  had an update for some time then the player is deleted.
670 //
671 //////////////////////////////////////////////////////////////////////
672 void
673 FGMultiplayMgr::Update (void) 
674 {
675     MPPlayer::TPlayerDataState ePlayerDataState;
676     t_MPClientListIterator CurrentPlayer;
677
678     CurrentPlayer  = m_MPClientList.begin ();
679     while (CurrentPlayer != m_MPClientList.end ())
680     {
681         ePlayerDataState = (*CurrentPlayer)->Draw();
682         //////////////////////////////////////////////////
683         // If the player has not received an update for
684         // some time then assume that the player has quit.
685         //////////////////////////////////////////////////
686         if (ePlayerDataState == MPPlayer::PLAYER_DATA_EXPIRED) 
687         {
688             SG_LOG( SG_NETWORK, SG_ALERT, "FGMultiplayMgr::Update - "
689               << "Deleting player from game. Callsign: "
690               << (*CurrentPlayer)->Callsign() );
691             t_MPClientListIterator P;
692                 P = CurrentPlayer;
693                 delete (*P);
694             *P = 0;
695             CurrentPlayer = m_MPClientList.erase (P);
696         }
697         else    CurrentPlayer++;
698     }
699 } // FGMultiplayMgr::Update()
700 //////////////////////////////////////////////////////////////////////
701
702 #endif // FG_MPLAYER_AS
703