]> git.mxchange.org Git - flightgear.git/blobdiff - src/MultiPlayer/mpplayer.cxx
Unused local variable removed
[flightgear.git] / src / MultiPlayer / mpplayer.cxx
index a89e373a794bbdf3a712ae86e77f42ba0784e99a..0ea86cad36710ac883fbbd67ca23db9d104d0036 100644 (file)
@@ -1,9 +1,14 @@
+//////////////////////////////////////////////////////////////////////
+//
 // mpplayer.cxx -- routines for a player within a multiplayer Flightgear
 //
 // Written by Duncan McCreanor, started February 2003.
 // duncan.mccreanor@airservicesaustralia.com
 //
+// With additions by Vivian Meazza, January 2006
+//
 // Copyright (C) 2003  Airservices Australia
+// Copyright (C) 2005  Oliver Schroeder
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -19,6 +24,7 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 //
+//////////////////////////////////////////////////////////////////////
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 *
 ******************************************************************/
 
+#include <simgear/timing/timestamp.hxx>
+
 #include "mpplayer.hxx"
 
 #include <stdlib.h>
 #if !(defined(_MSC_VER) || defined(__MINGW32__))
-# include <netdb.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
+#   include <netdb.h>
+#   include <sys/socket.h>
+#   include <netinet/in.h>
+#   include <arpa/inet.h>
 #endif
 #include <plib/netSocket.h>
 #include <plib/sg.h>
 
-#include <Main/globals.hxx>
-#include <Model/loader.hxx>
-#include <Scenery/scenery.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/scene/model/modellib.hxx>
+#include <simgear/scene/model/placementtrans.hxx>
 
+#include <AIModel/AIBase.hxx>
+#include <AIModel/AIManager.hxx>
+#include <AIModel/AIMultiplayer.hxx>
+#include <Main/globals.hxx>
+//#include <Scenery/scenery.hxx>
 
 // These constants are provided so that the ident command can list file versions.
 const char sMPPLAYER_BID[] = "$Id$";
 const char sMPPLAYER_HID[] = MPPLAYER_HID;
 
-
-/******************************************************************
-* Name: MPPlayer
-* Description: Constructor.
-******************************************************************/
-MPPlayer::MPPlayer() {
-
-    // Initialise private members
-    m_bInitialised = false;
-    m_LastUpdate = 0;
+//////////////////////////////////////////////////////////////////////
+//
+//  constructor
+//
+//////////////////////////////////////////////////////////////////////
+MPPlayer::MPPlayer()
+{
+    m_Initialised   = false;
+    m_LastUpdate    = 0;
+    m_LastUpdate    = 0;
+    m_LastTime      = 0;
+    m_LastUTime     = 0;
+    m_Elapsed       = 0;
+    m_TimeOffset    = 0.0;
+    m_Callsign      = "none";
     m_PlayerAddress.set("localhost", 0);
-    m_sCallsign = "none";
-
-
-}
-
+    m_AIModel = NULL;
+} // MPPlayer::MPPlayer()
+//////////////////////////////////////////////////////////////////////
 
 /******************************************************************
 * Name: ~MPPlayer
 * Description: Destructor.
 ******************************************************************/
-MPPlayer::~MPPlayer() {
-
+MPPlayer::~MPPlayer() 
+{
     Close();
-
 }
 
-
 /******************************************************************
 * Name: Open
 * Description: Initialises class.
 ******************************************************************/
-bool MPPlayer::Open(const string &sAddress, const int &iPort, const string &sCallsign, const string &sModelName, bool bLocalPlayer) {
-
-    bool bSuccess = true;
-
-    if (!m_bInitialised) {
-
-        m_PlayerAddress.set(sAddress.c_str(), iPort);
-        m_sCallsign = sCallsign;
-        m_sModelName = sModelName;
-        m_bLocalPlayer = bLocalPlayer;
-
+bool 
+MPPlayer::Open
+    (
+    const string &Address,
+    const int &Port,
+    const string &Callsign,
+    const string &ModelName,
+    bool LocalPlayer
+    )
+{
+    bool Success = true;
+
+    if (!m_Initialised)
+    {
+        m_PlayerAddress.set(Address.c_str(), Port);
+        m_Callsign = Callsign;
+        m_ModelName = ModelName;
+        m_LocalPlayer = LocalPlayer;
+        SG_LOG( SG_NETWORK, SG_ALERT, "Initialising " << m_Callsign
+           << " using '" << m_ModelName << "'" );
         // If the player is remote then load the model
-        if (!bLocalPlayer) {
-
-             LoadModel();
-
+        if (!LocalPlayer)
+        {
+             try {
+                 LoadAI();
+             } catch (...) {
+                 SG_LOG( SG_NETWORK, SG_ALERT,
+                   "Failed to load remote model '" << ModelName << "'." );
+                 return false;
+             }
         }
-
-        m_bInitialised = bSuccess;
-
-    } else {
-        SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - Attempt to open an already open player connection." );
-        bSuccess = false;
+        m_Initialised = Success;
+    }
+    else
+    {
+        SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Open - "
+          << "Attempt to open an already opened player connection." );
+        Success = false;
     }
-
-
     /* Return true if open succeeds */
-    return bSuccess;
-
+    return Success;
 }
 
-
 /******************************************************************
 * Name: Close
 * Description: Resets the object.
 ******************************************************************/
-void MPPlayer::Close(void) {
-
+void
+MPPlayer::Close(void)
+{
     // Remove the model from the game
-    if (m_bInitialised && !m_bLocalPlayer) {
-
-        // Disconnect the model from the transform, then the transform from the scene.
-        m_ModelTrans->removeKid(m_Model);
-        globals->get_scenery()->get_aircraft_branch()->removeKid( m_ModelTrans);
-
-        // Flush the model loader so that it erases the model from its list of
-        // models.
-        globals->get_model_loader()->flush();
-
-        // Assume that plib/ssg deletes the model and transform as their
-        // refcounts should be zero.
-
+    if (m_Initialised && !m_LocalPlayer) 
+    {
+        m_Initialised = 0;
+        
+        // get the model manager
+        FGAIManager *aiModelMgr = (FGAIManager *) globals->get_subsystem("ai_model");
+        if (!aiModelMgr) {
+            SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::Close - "
+                    << "Cannot find AI model manager!" );
+            return;
+        }
+        
+        // remove it
+        aiModelMgr->destroyObject(m_AIModel->getID());
+        m_AIModel = NULL;
     }
-
-    m_bInitialised = false;
-    m_bUpdated = false;
-    m_LastUpdate = 0;
-    m_sCallsign = "none";
-
+    m_Initialised   = false;
+    m_Updated       = false;
+    m_LastUpdate    = 0;
+    m_LastUpdate    = 0;
+    m_LastTime      = 0;
+    m_LastUTime     = 0;
+    m_Elapsed       = 0;
+    m_TimeOffset    = 0.0;
+    m_Callsign      = "none";
 }
 
+/******************************************************************
+* Name: CheckTime
+* Description: Checks if the time is valid for a position update
+* and perhaps sets the time offset
+******************************************************************/
+bool MPPlayer::CheckTime(int time, int timeusec)
+{
+    double curOffset;
+    int toff, utoff;
+    
+    SGTimeStamp now;
+    
+    // calculate the offset
+    toff = ((int) now.get_seconds()) - time;
+    utoff = ((int) now.get_usec()) - timeusec;
+    while (utoff < 0) {
+        toff--;
+        utoff += 1000000;
+    }
+    
+    // set it
+    curOffset = ((double)toff) + (((double)utoff) / 1000000);
+        
+    if (m_LastUpdate == 0) {
+        // set the main offset
+        m_TimeOffset = curOffset;
+        m_Elapsed = 0;
+        return true;
+    } else {
+        // check it
+        if (time < m_LastTime ||
+            (time == m_LastTime && timeusec <= m_LastUTime)) {
+            return false;
+        } else {
+            // set the current offset
+            m_LastOffset = curOffset;
+            // calculate the Hz
+            toff = time - m_LastTime;
+            utoff = timeusec - m_LastUTime;
+            while (utoff < 0) {
+                toff--;
+                utoff += 1000000;
+            }
+            m_Elapsed = ((double)toff) + (((double)utoff)/1000000);
+            
+            m_LastTime = time;
+            m_LastUTime = timeusec;
+            
+            return true;
+        }
+    }
+}
 
 /******************************************************************
 * Name: SetPosition
 * Description: Updates position data held for this player and resets
 * the last update time.
 ******************************************************************/
-void MPPlayer::SetPosition(const sgMat4 PlayerPosMat4) {
-
-
+void
+MPPlayer::SetPosition
+    (
+        const double lat, const double lon, const double alt,
+        const double heading, const double roll, const double pitch,
+        const double speedN, const double speedE, const double speedD,
+        const double left_aileron, const double right_aileron, const double elevator, const double rudder,
+        //const double rpms[6],
+        const double rateH, const double rateR, const double rateP,
+        const double accN, const double accE, const double accD
+    )
+{
     // Save the position matrix and update time
-    if (m_bInitialised) {
-        sgCopyMat4(m_ModelPos, PlayerPosMat4);
+    if (m_Initialised)
+    {
+        // calculate acceleration
+        /*if (m_Elapsed > 0) {
+            m_accN = (speedN - m_speedN) / m_Elapsed;
+            m_accE = (speedE - m_speedE) / m_Elapsed;
+            m_accD = (speedD - m_speedD) / m_Elapsed;
+        } else {
+            m_accN = 0;
+            m_accE = 0;
+            m_accD = 0;
+        }*/
+        
+        // store the position
+        m_lat = lat;
+        m_lon = lon;
+        m_alt = alt;
+        m_hdg = heading;
+        m_roll = roll;
+        m_pitch = pitch;
+        m_speedN = speedN;
+        m_speedE = speedE;
+        m_speedD = speedD;
+        m_accN = accN;
+        m_accE = accE;
+        m_accD = accD;
+        m_left_aileron = left_aileron;
+        m_right_aileron = right_aileron;
+        m_elevator = elevator;
+        m_rudder = rudder;
+
+        /*for (int i = 0; i < 6; i++) {
+            m_rpms[i] = rpms[i];
+        }
+        m_rateH = rateH;
+        m_rateR = rateR;
+        m_rateP = rateP;*/
+        
+        if (!m_LocalPlayer) {
+            m_AIModel->setLatitude(m_lat);
+            m_AIModel->setLongitude(m_lon);
+            m_AIModel->setAltitude(m_alt);
+            m_AIModel->setHeading(m_hdg);
+            m_AIModel->setBank(m_roll);
+            m_AIModel->setPitch(m_pitch);
+            m_AIModel->setSpeedN(m_speedN);
+            m_AIModel->setSpeedE(m_speedE);
+            m_AIModel->setSpeedD(m_speedD); 
+            m_AIModel->setAccN(m_accN);
+            m_AIModel->setAccE(m_accE);
+            m_AIModel->setAccD(m_accD);
+            m_AIModel->setRateH(m_rateH);
+            m_AIModel->setRateR(m_rateR);
+            m_AIModel->setRateP(m_rateP);
+                
+            // set properties
+            SGPropertyNode *root = m_AIModel->getProps();
+            root->getNode("surface-positions/left-aileron-pos-norm", true)->setDoubleValue(m_left_aileron);
+            root->getNode("surface-positions/right-aileron-pos-norm", true)->setDoubleValue(m_right_aileron);
+            root->getNode("surface-positions/elevator-pos-norm", true)->setDoubleValue(m_elevator);
+            root->getNode("surface-positions/rudder-pos-norm", true)->setDoubleValue(m_rudder);
+            /*root->getNode("engines/engine/rpm", true)->setDoubleValue(m_rpms[0]);
+            root->getNode("engines/engine[1]/rpm", true)->setDoubleValue(m_rpms[1]);
+            root->getNode("engines/engine[2]/rpm", true)->setDoubleValue(m_rpms[2]);
+            root->getNode("engines/engine[3]/rpm", true)->setDoubleValue(m_rpms[3]);
+            root->getNode("engines/engine[4]/rpm", true)->setDoubleValue(m_rpms[4]);
+            root->getNode("engines/engine[5]/rpm", true)->setDoubleValue(m_rpms[5]);*/
+                
+            // Adjust by the last offset
+            //cout << "OFFSET: " << (m_LastOffset - m_TimeOffset) << endl;
+            
+            //m_AIModel->timewarp(m_LastOffset - m_TimeOffset);
+
+            // set the timestamp for the data update (sim elapsed time (secs))
+            m_AIModel->setTimeStamp();
+        }
+        
         time(&m_LastUpdate);
-        m_bUpdated = true;
+        
+        m_Updated = true;
     }
-
-
 }
 
+/******************************************************************
+ * Name: SetProperty
+ * Description: Sets a property of this player.
+ ******************************************************************/
+void MPPlayer::SetProperty(string property, SGPropertyNode::Type type, double val)
+{    
+    // get rid of any leading /
+    while (property[0] == '/') property = property.substr(1);
+    
+    // get our root node
+    SGPropertyNode *node = m_AIModel->getProps()->getNode(property.c_str(), true);
+        
+    // set the property
+    switch (type) {
+        case 2:
+            node->setBoolValue( val != 0.0 );
+            break;
+        case 3:
+            node->setIntValue((int) val);
+            break;
+        case 4:
+            node->setLongValue((long) val);
+            break;
+        case 5:
+            node->setFloatValue((float) val);
+            break;
+        case 6:
+        default:
+            node->setDoubleValue(val);
+    }
+}
 
 /******************************************************************
 * Name: Draw
 * Description: Updates the position for the player's model
 * The state of the player's data is returned.
 ******************************************************************/
-MPPlayer::TPlayerDataState MPPlayer::Draw(void) {
-
+MPPlayer::TPlayerDataState
+MPPlayer::Draw (void)
+{
     MPPlayer::TPlayerDataState eResult = PLAYER_DATA_NOT_AVAILABLE;
-
-    sgCoord sgPlayerCoord;
-
-    if (m_bInitialised && !m_bLocalPlayer) {
-        if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE)) {
+    if (m_Initialised && !m_LocalPlayer) 
+    {
+        if ((time(NULL) - m_LastUpdate < TIME_TO_LIVE))
+        {
             // Peform an update if it has changed since the last update
-            if (m_bUpdated) {
-
-                // Transform and update player model
-                sgSetCoord( &sgPlayerCoord, m_ModelPos);
-                m_ModelTrans->setTransform( &sgPlayerCoord );
-
+            if (m_Updated)
+            {
+                /*
+                m_AIModel->setLatitude(m_lat);
+                m_AIModel->setLongitude(m_lon);
+                m_AIModel->setAltitude(m_alt);
+                m_AIModel->setHeading(m_hdg);
+                m_AIModel->setBank(m_roll);
+                m_AIModel->setPitch(m_pitch);
+                m_AIModel->setSpeedN(m_speedN);
+                m_AIModel->setSpeedE(m_speedE);
+                m_AIModel->_setVS_fps(m_speedU*60.0); // it needs input in fpm
+                m_AIModel->setRateH(m_rateH);
+                m_AIModel->setRateR(m_rateR);
+                m_AIModel->setRateP(m_rateP);
+                
+                // set properties
+                SGPropertyNode *root = m_AIModel->getProps();
+                root->getNode("controls/flight/aileron", true)->setDoubleValue(m_aileron);
+                root->getNode("controls/flight/elevator", true)->setDoubleValue(m_elevator);
+                root->getNode("controls/flight/rudder", true)->setDoubleValue(m_rudder);
+                root->getNode("engines/engine/rpm", true)->setDoubleValue(m_rpms[0]);
+                root->getNode("engines/engine[1]/rpm", true)->setDoubleValue(m_rpms[1]);
+                root->getNode("engines/engine[2]/rpm", true)->setDoubleValue(m_rpms[2]);
+                root->getNode("engines/engine[3]/rpm", true)->setDoubleValue(m_rpms[3]);
+                root->getNode("engines/engine[4]/rpm", true)->setDoubleValue(m_rpms[4]);
+                root->getNode("engines/engine[5]/rpm", true)->setDoubleValue(m_rpms[5]);
+                
+                // Adjust by the last offset
+                m_AIModel->update(m_LastOffset - m_TimeOffset);
+                */
                 eResult = PLAYER_DATA_AVAILABLE;
-
+                
                 // Clear the updated flag so that the position data
                 // is only available if it has changed
-                m_bUpdated = false;
+                m_Updated = false;
             }
-
-        // Data has not been updated for some time.
-        } else {
+        }
+        else
+        {   // Data has not been updated for some time.
             eResult = PLAYER_DATA_EXPIRED;
         }
-
     }
-
     return eResult;
-
 }
 
-
 /******************************************************************
 * Name: Callsign
 * Description: Returns the player's callsign.
 ******************************************************************/
-string MPPlayer::Callsign(void) const {
-
-    return m_sCallsign;
-
+string
+MPPlayer::Callsign(void) const
+{
+    return m_Callsign;
 }
 
-
 /******************************************************************
 * Name: CompareCallsign
 * Description: Returns true if the player's callsign matches
 * the given callsign.
 ******************************************************************/
-bool MPPlayer::CompareCallsign(const char *sCallsign) const {
-
-    return (m_sCallsign == sCallsign);
-
+bool
+MPPlayer::CompareCallsign(const char *Callsign) const 
+{
+    return (m_Callsign == Callsign);
 }
 
-
 /******************************************************************
-* Name: LoadModel
-* Description: Loads the player's aircraft model.
+ * Name: LoadAI
+ * Description: Loads the AI model into the AI core.
 ******************************************************************/
-void MPPlayer::LoadModel(void) {
-
-
-    m_ModelTrans = new ssgTransform;
-
-    // Load the model
-    m_Model = globals->get_model_loader()->load_model( globals->get_fg_root(),
-                                                       m_sModelName,
-                                                       globals->get_props(),
-                                                       globals->get_sim_time_sec() );
-    m_Model->clrTraversalMaskBits( SSGTRAV_HOT );
-
-    // Add model to transform
-    m_ModelTrans->addKid( m_Model );
-
-    // Optimise model and transform
-    ssgFlatten( m_Model );
-    ssgStripify( m_ModelTrans );
-
-    // Place on scene under aircraft branch
-    globals->get_scenery()->get_aircraft_branch()->addKid( m_ModelTrans );
-
-
+void
+MPPlayer::LoadAI(void)
+{
+    // then get the model manager
+    FGAIManager *aiModelMgr = (FGAIManager *) globals->get_subsystem("ai_model");
+    if (!aiModelMgr) {
+        SG_LOG( SG_NETWORK, SG_ALERT, "MPPlayer::LoadAI - "
+                << "Cannot find AI model manager!" );
+        return;
+    }
+    
+    // then get the model
+    fgSetBool("/sim/freeze/clock", true);
+    m_AIModel = new FGAIMultiplayer;
+    m_AIModel->setAcType("Multiplayer");
+    m_AIModel->setCompany(m_Callsign);
+    m_AIModel->setPath(m_ModelName.c_str());
+    aiModelMgr->attach(m_AIModel);
+    fgSetBool("/sim/freeze/clock", false);
 }
 
-
 /******************************************************************
 * Name: FillPosMsg
 * Description: Populates the header and data for a position message.
 ******************************************************************/
-void MPPlayer::FillPosMsg(T_MsgHdr *MsgHdr, T_PositionMsg *PosMsg) {
+void
+MPPlayer::FillPosMsg
+    (
+    T_MsgHdr *MsgHdr,
+    T_PositionMsg *PosMsg
+    )
+{
+    SGTimeStamp now;
 
     FillMsgHdr(MsgHdr, POS_DATA_ID);
-
-    strncpy(PosMsg->sModel, m_sModelName.c_str(), MAX_MODEL_NAME_LEN);
-    PosMsg->sModel[MAX_MODEL_NAME_LEN - 1] = '\0';
-    sgCopyMat4(PosMsg->PlayerPos, m_ModelPos);
-
-
+    strncpy(PosMsg->Model, m_ModelName.c_str(), MAX_MODEL_NAME_LEN);
+    PosMsg->Model[MAX_MODEL_NAME_LEN - 1] = '\0';
+    PosMsg->time = XDR_encode_uint32 (now.get_seconds());
+    PosMsg->timeusec = XDR_encode_uint32 (now.get_usec());
+    PosMsg->lat = XDR_encode_double (m_lat);
+    PosMsg->lon = XDR_encode_double (m_lon);
+    PosMsg->alt = XDR_encode_double (m_alt);
+    PosMsg->hdg = XDR_encode_double (m_hdg);
+    PosMsg->roll = XDR_encode_double (m_roll);
+    PosMsg->pitch = XDR_encode_double (m_pitch);
+    PosMsg->speedN = XDR_encode_double (m_speedN);
+    PosMsg->speedE = XDR_encode_double (m_speedE);
+    PosMsg->speedD = XDR_encode_double (m_speedD);
+    PosMsg->left_aileron = XDR_encode_float ((float) m_left_aileron);
+    PosMsg->right_aileron = XDR_encode_float ((float) m_right_aileron);
+    PosMsg->elevator = XDR_encode_float ((float) m_elevator);
+    PosMsg->rudder = XDR_encode_float ((float) m_rudder);
+    /*for (int i = 0; i < 6; i++) {
+        PosMsg->rpms[i] = XDR_encode_float ((float) m_rpms[i]);
+    }*/
+    PosMsg->rateH =  XDR_encode_float ((float) m_rateH);
+    PosMsg->rateR =  XDR_encode_float ((float) m_rateR);
+    PosMsg->rateP =  XDR_encode_float ((float) m_rateP);
+    PosMsg->accN  =  XDR_encode_float ((float) m_accN);
+    PosMsg->accE =  XDR_encode_float ((float) m_accE);
+    PosMsg->accD =  XDR_encode_float ((float) m_accD);
 }
 
-
 /******************************************************************
 * Name: FillMsgHdr
 * Description: Populates the header of a multiplayer message.
 ******************************************************************/
-void MPPlayer::FillMsgHdr(T_MsgHdr *MsgHdr, const int iMsgId) {
-
-    struct in_addr address;
-
-    MsgHdr->MsgId = iMsgId;
-
-    switch (iMsgId) {
+void
+MPPlayer::FillMsgHdr
+    (
+    T_MsgHdr *MsgHdr, 
+    const int MsgId
+    )
+{
+    uint32_t        len;
+
+    switch (MsgId)
+    {
         case CHAT_MSG_ID:
-            MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
+            len = sizeof(T_MsgHdr) + sizeof(T_ChatMsg);
             break;
         case POS_DATA_ID:
-            MsgHdr->iMsgLen = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
+            len = sizeof(T_MsgHdr) + sizeof(T_PositionMsg);
+            break;
+        case PROP_MSG_ID:
+            len = sizeof(T_MsgHdr) + sizeof(T_PropertyMsg);
             break;
         default:
-            MsgHdr->iMsgLen = sizeof(T_MsgHdr);
+            len = sizeof(T_MsgHdr);
             break;
     }
-
-    address.s_addr = inet_addr( m_PlayerAddress.getHost() );
-    MsgHdr->lReplyAddress = address.s_addr;
-
-    MsgHdr->iReplyPort = m_PlayerAddress.getPort();
-
-    strncpy(MsgHdr->sCallsign, m_sCallsign.c_str(), MAX_CALLSIGN_LEN);
-    MsgHdr->sCallsign[MAX_CALLSIGN_LEN - 1] = '\0';
-
-
+    MsgHdr->Magic           = XDR_encode_uint32 (MSG_MAGIC);
+    MsgHdr->Version         = XDR_encode_uint32 (PROTO_VER);
+    MsgHdr->MsgId           = XDR_encode_uint32 (MsgId);
+    MsgHdr->MsgLen          = XDR_encode_uint32 (len);
+    // inet_addr returns address in network byte order
+    // no need to encode it
+    MsgHdr->ReplyAddress   = inet_addr( m_PlayerAddress.getHost() );
+    MsgHdr->ReplyPort      = XDR_encode_uint32 (m_PlayerAddress.getPort());
+    strncpy(MsgHdr->Callsign, m_Callsign.c_str(), MAX_CALLSIGN_LEN);
+    MsgHdr->Callsign[MAX_CALLSIGN_LEN - 1] = '\0';
 }
 
 #endif // FG_MPLAYER_AS