MercuryNetClient.cpp

Go to the documentation of this file.
00001 #include "MercuryNetClient.h"
00002 #include "MercuryLog.h"
00003 #include "MercuryObject.h"
00004 #include "MercuryODE.h"
00005 
00006 #define MSG_SYNCNETTIME 1
00007 
00008 MercuryNetClient::MercuryNetClient()
00009 {
00010     m_pSocket = new ezSockets;
00011     m_pNetClass = NULL;
00012 }
00013 
00014 MercuryNetClient::~MercuryNetClient()
00015 {
00016     m_thdMain.Halt();
00017     m_thdMain.Close();
00018     delete m_pSocket;
00019 }
00020 
00021 bool MercuryNetClient::Connect( const MString & sHost, int iPort )
00022 {
00023     bool bSucess;
00024     m_pSocket->Create();
00025     bSucess = m_pSocket->Connect( sHost, iPort );
00026 
00027     if( bSucess )
00028     {
00029         m_thdMain.Create( CoreThreadCaller, this );
00030         RegisterMessage( MSG_SYNCNETTIME, "syncnettime" );
00031         m_delTimeID = 0;
00032         PStack s;
00033         MESSAGEMAN->BroadcastMessage( "syncnettime", s );
00034         return true;
00035     } 
00036     else
00037         return false;
00038 }
00039 
00040 void MercuryNetClient::Update( const float fDTime )
00041 {
00042 }
00043 
00044 void MercuryNetClient::SendCommand( const MString & sCommandName, const PStack & kParameters )
00045 {
00046     ezSocketsPacket p;
00047     p.ClearPacket();
00048     p.Write4( 3 );
00049     p.WriteNT( sCommandName );
00050     NetEncodePStack( p, kParameters );
00051     m_pSocket->SendPack( p );
00052 }
00053 
00054 void * MercuryNetClient::CoreThreadCaller( void * NetClient)
00055 {
00056     ((MercuryNetClient*)(NetClient))->CoreThread();
00057     return NULL;
00058 }
00059 
00060 void MercuryNetClient::CoreThread( )
00061 {
00062     ezSocketsPacket pack;
00063 
00064     m_pSocket->mode = ezSockets::skPackets;
00065     m_pSocket->bBlocking = true;
00066     m_tmrSync.Touch();
00067 
00068     while( !m_pSocket->IsError() )
00069     {
00070         if( !m_pSocket->ReadPack( pack ) )
00071             break;
00072 
00073         unsigned char cCode = pack.Read4();
00074         switch( cCode )
00075         {
00076         case 0:
00077             break;
00078         case 1:
00079             break;
00080         case 2: //Message
00081         case 3: //Command
00082             {
00083             MString sName = pack.ReadNT();
00084             unsigned long iParameters = pack.Read1();
00085             PStack t;
00086             NetDecodePStack( pack, t );
00087             if( cCode == 2 )
00088                 MESSAGEMAN->PostSystemMessage( sName, t );
00089             else if( cCode == 3 )
00090                 if( m_pNetClass )
00091                 {
00092                     PStack ret;
00093                     m_pNetClass->Command( ret, sName.c_str(), t );
00094                 }
00095             }
00096             break;
00097         case 4: //Time sync
00098             {
00099             double dCurTime = m_tmrSync.Age();
00100             double dOrigTime;
00101             double dSrvTime;
00102             long delTimeID = pack.Read4();
00103 
00104             pack.ReadData( 8, (char*)&dOrigTime );
00105             pack.ReadData( 8, (char*)&dSrvTime );
00106 
00107             //Round-trip-packet-time
00108             double dPingTime = ( dCurTime - dOrigTime );
00109 
00110             //Ok, this looks a little weird, but here's the reasoning:
00111             //  We know the time it was on the client
00112             //  We know what time it was on the server when the server received it
00113             //  We know that ping times are rougly symmetric
00114             //  Therefore, the time now on the server is the ping time/2 + the server time.
00115 
00116             double thisDelTime = ( ( dSrvTime + (dPingTime/2) ) - dCurTime);
00117 
00118             //If we're one of the first two sync's just set the time, otherwise
00119             //factor it in statistically with diminishing importance.
00120             if( delTimeID < 2 )
00121                 m_delTime = thisDelTime;
00122             else
00123                 m_delTime = m_delTime * .9f + thisDelTime * .1f;
00124 
00125             LOG.Info( ssprintf( "Time Synchronization: %f %f", dPingTime, m_delTime ) );
00126             }
00127             break;
00128         case 5:
00129             {
00130             if( !m_pWorld )
00131                 break;
00132             ODEUnitInfo t;
00133             double dServerTime;
00134             unsigned iNumToReceive;
00135 
00136             pack.ReadData( 8, (char*)&dServerTime );
00137             iNumToReceive = pack.Read4();
00138 
00139             double dDeltaTime = m_tmrSync.Age() - dServerTime + m_delTime;
00140 
00141             MHash<MercuryODEObject *> & AllObjects = m_pWorld->GetAllObjectMap();
00142 
00143             for( unsigned i = 0; i < iNumToReceive; i++ )
00144             {
00145                 MString sPackName = pack.ReadNT();
00146                 pack.ReadData( sizeof(ODEUnitInfo), (char*)&t );
00147                 if( !AllObjects.get( sPackName ) )
00148                     continue;
00149                 dBodyID b = (*AllObjects.get( sPackName ))->m_oBody;
00150                 if( !b )
00151                     continue;
00152 
00153                 t.pos = t.pos + t.linvel * dDeltaTime;
00154 
00155                 dBodySetPosition( b, t.pos.x, t.pos.y, t.pos.z );
00156 
00157                 dBodyEnable( b );
00158                 dQuaternion q;
00159                 q[0] = t.rot.w; q[1] = t.rot.x; q[2] = t.rot.y; q[3] = t.rot.z;
00160                 dBodySetQuaternion( b, q );
00161                 dBodySetLinearVel( b, t.linvel.x, t.linvel.y, t.linvel.z );
00162                 dBodySetAngularVel( b, t.angvel.x, t.angvel.y, t.angvel.z );
00163             }
00164             }
00165             break;
00166         }
00167     }
00168     m_pSocket->Close();
00169 
00170 }
00171 
00172 void MercuryNetClient::Message( int Message, PStack & data, const MString & name )
00173 {
00174     switch( Message )
00175     {
00176     case MSG_SYNCNETTIME:
00177         double dCurrentTime = m_tmrSync.Age();
00178         ezSocketsPacket p;
00179         p.ClearPacket();
00180         p.Write4( 4 );
00181         p.Write4( m_delTimeID++ );  //Must be post-increment
00182 
00183         p.WriteData( (char*)&dCurrentTime, 8 );
00184         m_pSocket->SendPack( p );
00185 
00186         PStack s;
00187         MESSAGEMAN->PostSystemMessage( "syncnettime", s, 1 );
00188         break;
00189     }
00190 }

Hosted by SourceForge.net Logo