• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ReadyEvent.cpp

Go to the documentation of this file.
00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_ReadyEvent==1
00003 
00004 #include "ReadyEvent.h"
00005 #include "RakPeerInterface.h"
00006 #include "BitStream.h"
00007 #include "MessageIdentifiers.h"
00008 #include "RakAssert.h"
00009 
00010 #ifdef _MSC_VER
00011 #pragma warning( push )
00012 #endif
00013 
00014 int ReadyEvent::RemoteSystemCompBySystemAddress( const SystemAddress &key, const RemoteSystem &data )
00015 {
00016         if (key < data.systemAddress)
00017                 return -1;
00018         else if (key==data.systemAddress)
00019                 return 0;
00020         else
00021                 return 1;
00022 }
00023 
00024 int ReadyEvent::ReadyEventNodeComp( const int &key, ReadyEvent::ReadyEventNode * const &data )
00025 {
00026         if (key < data->eventId)
00027                 return -1;
00028         else if (key==data->eventId)
00029                 return 0;
00030         else
00031                 return 1;
00032 }
00033 
00034 
00035 ReadyEvent::ReadyEvent()
00036 {
00037         channel=0;
00038 }
00039 
00040 ReadyEvent::~ReadyEvent()
00041 {
00042         Clear();
00043 }
00044 
00045 
00046 bool ReadyEvent::SetEvent(int eventId, bool isReady)
00047 {
00048         bool objectExists;
00049         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00050         if (objectExists==false)
00051         {
00052                 // Totally new event
00053                 CreateNewEvent(eventId, isReady);
00054         }
00055         else
00056         {
00057                 return SetEventByIndex(eventIndex, isReady);
00058         }
00059         return true;
00060 }
00061 bool ReadyEvent::ForceCompletion(int eventId)
00062 {
00063         bool objectExists;
00064         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00065         if (objectExists==false)
00066         {
00067                 // Totally new event
00068                 CreateNewEvent(eventId, true);
00069                 eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00070         }
00071         
00072         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00073         ren->eventStatus=ID_READY_EVENT_FORCE_ALL_SET;
00074         UpdateReadyStatus(eventIndex);
00075 
00076         return true;
00077 }
00078 bool ReadyEvent::DeleteEvent(int eventId)
00079 {
00080         bool objectExists;
00081         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00082         if (objectExists)
00083         {
00084                 RakNet::OP_DELETE(readyEventNodeList[eventIndex], __FILE__, __LINE__);
00085                 readyEventNodeList.RemoveAtIndex(eventIndex);
00086                 return true;
00087         }
00088         return false;
00089 }
00090 bool ReadyEvent::IsEventSet(int eventId)
00091 {
00092         bool objectExists;
00093         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00094         if (objectExists)
00095         {
00096                 return readyEventNodeList[eventIndex]->eventStatus==ID_READY_EVENT_SET || readyEventNodeList[eventIndex]->eventStatus==ID_READY_EVENT_ALL_SET;
00097         }
00098         return false;
00099 }
00100 bool ReadyEvent::IsEventCompletionProcessing(int eventId) const
00101 {
00102         bool objectExists;
00103         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00104         if (objectExists)
00105         {
00106                 bool anyAllReady=false;
00107                 bool allAllReady=true;
00108                 ReadyEventNode *ren = readyEventNodeList[eventIndex];
00109                 if (ren->eventStatus==ID_READY_EVENT_FORCE_ALL_SET)
00110                         return false;
00111                 for (unsigned i=0; i < ren->systemList.Size(); i++)
00112                 {
00113                         if (ren->systemList[i].lastReceivedStatus==ID_READY_EVENT_ALL_SET)
00114                                 anyAllReady=true;
00115                         else
00116                                 allAllReady=false;
00117                 }
00118                 return anyAllReady==true && allAllReady==false;
00119         }
00120         return false;
00121 }
00122 bool ReadyEvent::IsEventCompleted(int eventId) const
00123 {
00124         bool objectExists;
00125         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00126         if (objectExists)
00127         {
00128                 return IsEventCompletedByIndex(eventIndex);
00129         }
00130         return false;
00131 }
00132 
00133 bool ReadyEvent::HasEvent(int eventId)
00134 {
00135         return readyEventNodeList.HasData(eventId);
00136 }
00137 
00138 unsigned ReadyEvent::GetEventListSize(void) const
00139 {
00140         return readyEventNodeList.Size();
00141 }
00142 
00143 int ReadyEvent::GetEventAtIndex(unsigned index) const
00144 {
00145         return readyEventNodeList[index]->eventId;
00146 }
00147 
00148 bool ReadyEvent::AddToWaitList(int eventId, SystemAddress address)
00149 {
00150         bool eventExists;
00151         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &eventExists);
00152         if (eventExists==false)
00153                 eventIndex=CreateNewEvent(eventId, false);
00154 
00155         // Don't do this, otherwise if we are trying to start a 3 player game, it will not allow the 3rd player to hit ready if the first two players have already done so
00156         //if (IsLocked(eventIndex))
00157         //      return false; // Not in the list, but event is already completed, or is starting to complete, and adding more waiters would fail this.
00158 
00159         unsigned i;
00160         unsigned numAdded=0;
00161         if (address==UNASSIGNED_SYSTEM_ADDRESS)
00162         {
00163                 for (i=0; i < rakPeerInterface->GetMaximumNumberOfPeers(); i++)
00164                 {
00165                         SystemAddress internalAddress = rakPeerInterface->GetSystemAddressFromIndex(i);
00166                         if (internalAddress!=UNASSIGNED_SYSTEM_ADDRESS)
00167                         {
00168                                 numAdded+=AddToWaitListInternal(eventIndex, internalAddress);
00169                         }
00170                 }
00171         }
00172         else
00173         {
00174                 numAdded=AddToWaitListInternal(eventIndex, address);
00175         }
00176 
00177         if (numAdded>0)
00178                 UpdateReadyStatus(eventIndex);
00179         return numAdded>0;
00180 }
00181 bool ReadyEvent::RemoveFromWaitList(int eventId, SystemAddress address)
00182 {
00183         bool eventExists;
00184         unsigned eventIndex = readyEventNodeList.GetIndexFromKey(eventId, &eventExists);
00185         if (eventExists)
00186         {
00187                 if (address==UNASSIGNED_SYSTEM_ADDRESS)
00188                 {
00189                         // Remove all waiters
00190                         readyEventNodeList[eventIndex]->systemList.Clear(false, __FILE__, __LINE__);
00191                         UpdateReadyStatus(eventIndex);
00192                 }
00193                 else
00194                 {
00195                         bool systemExists;
00196                         unsigned systemIndex = readyEventNodeList[eventIndex]->systemList.GetIndexFromKey(address, &systemExists);
00197                         if (systemExists)
00198                         {
00199                                 bool isCompleted = IsEventCompletedByIndex(eventIndex);
00200                                 readyEventNodeList[eventIndex]->systemList.RemoveAtIndex(systemIndex);
00201 
00202                                 if (isCompleted==false && IsEventCompletedByIndex(eventIndex))
00203                                         PushCompletionPacket(readyEventNodeList[eventIndex]->eventId);
00204 
00205                                 UpdateReadyStatus(eventIndex);
00206 
00207                                 return true;
00208                         }
00209                 }
00210         }
00211 
00212         return false;
00213 }
00214 bool ReadyEvent::IsInWaitList(int eventId, SystemAddress address)
00215 {
00216         bool objectExists;
00217         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00218         if (objectExists)
00219         {
00220                 return readyEventNodeList[readyIndex]->systemList.HasData(address);
00221         }
00222         return false;
00223 }
00224 
00225 unsigned ReadyEvent::GetRemoteWaitListSize(int eventId) const
00226 {
00227         bool objectExists;
00228         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00229         if (objectExists)
00230         {
00231                 return readyEventNodeList[readyIndex]->systemList.Size();
00232         }
00233         return 0;
00234 }
00235 
00236 SystemAddress ReadyEvent::GetFromWaitListAtIndex(int eventId, unsigned index) const
00237 {
00238         bool objectExists;
00239         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00240         if (objectExists)
00241         {
00242                 return readyEventNodeList[readyIndex]->systemList[index].systemAddress;
00243         }
00244         return UNASSIGNED_SYSTEM_ADDRESS;
00245 }
00246 ReadyEventSystemStatus ReadyEvent::GetReadyStatus(int eventId, SystemAddress address)
00247 {
00248         bool objectExists;
00249         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00250         if (objectExists)
00251         {
00252                 ReadyEventNode *ren = readyEventNodeList[readyIndex];
00253                 unsigned systemIndex = ren->systemList.GetIndexFromKey(address, &objectExists);
00254                 if (objectExists==false)
00255                         return RES_NOT_WAITING;         
00256                 if (ren->systemList[systemIndex].lastReceivedStatus==ID_READY_EVENT_SET)
00257                         return RES_READY;
00258                 if (ren->systemList[systemIndex].lastReceivedStatus==ID_READY_EVENT_UNSET)
00259                         return RES_WAITING;
00260                 if (ren->systemList[systemIndex].lastReceivedStatus==ID_READY_EVENT_ALL_SET)
00261                         return RES_ALL_READY;
00262         }
00263 
00264         return RES_UNKNOWN_EVENT;
00265 }
00266 void ReadyEvent::SetSendChannel(unsigned char newChannel)
00267 {
00268         channel=newChannel;
00269 }
00270 PluginReceiveResult ReadyEvent::OnReceive(Packet *packet)
00271 {
00272         unsigned char packetIdentifier;
00273         packetIdentifier = ( unsigned char ) packet->data[ 0 ];
00274 
00275 //      bool doPrint = packet->systemAddress.port==60002 || rakPeerInterface->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port==60002;
00276 
00277         switch (packetIdentifier)
00278         {
00279         case ID_READY_EVENT_UNSET:
00280         case ID_READY_EVENT_SET:
00281         case ID_READY_EVENT_ALL_SET:
00282 //              if (doPrint) {if (packet->systemAddress.port==60002)    RAKNET_DEBUG_PRINTF("FROM 60002: "); else if (rakPeerInterface->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port==60002)   RAKNET_DEBUG_PRINTF("TO 60002: "); RAKNET_DEBUG_PRINTF("ID_READY_EVENT_SET\n");}
00283                 OnReadyEventPacketUpdate(packet);
00284                 return RR_CONTINUE_PROCESSING;
00285         case ID_READY_EVENT_FORCE_ALL_SET:
00286                 OnReadyEventForceAllSet(packet);
00287                 return RR_CONTINUE_PROCESSING;
00288         case ID_READY_EVENT_QUERY:
00289 //              if (doPrint) {if (packet->systemAddress.port==60002)    RAKNET_DEBUG_PRINTF("FROM 60002: "); else if (rakPeerInterface->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port==60002)   RAKNET_DEBUG_PRINTF("TO 60002: "); RAKNET_DEBUG_PRINTF("ID_READY_EVENT_QUERY\n");}
00290                 OnReadyEventQuery(packet);
00291                 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00292         }
00293 
00294         return RR_CONTINUE_PROCESSING;
00295 }
00296 bool ReadyEvent::AddToWaitListInternal(unsigned eventIndex, SystemAddress address)
00297 {
00298         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00299         bool objectExists;
00300         unsigned systemIndex = ren->systemList.GetIndexFromKey(address, &objectExists);
00301         if (objectExists==false)
00302         {
00303                 RemoteSystem rs;
00304                 rs.lastReceivedStatus=ID_READY_EVENT_UNSET;
00305                 rs.lastSentStatus=ID_READY_EVENT_UNSET;
00306                 rs.systemAddress=address;
00307                 ren->systemList.InsertAtIndex(rs,systemIndex, __FILE__,__LINE__);
00308 
00309                 SendReadyStateQuery(ren->eventId, address);
00310                 return true;
00311         }
00312         return false;
00313 }
00314 void ReadyEvent::OnReadyEventForceAllSet(Packet *packet)
00315 {
00316         RakNet::BitStream incomingBitStream(packet->data, packet->length, false);
00317         incomingBitStream.IgnoreBits(8);
00318         int eventId;
00319         incomingBitStream.Read(eventId);
00320         bool objectExists;
00321         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00322         if (objectExists)
00323         {
00324                 ReadyEventNode *ren = readyEventNodeList[readyIndex];
00325                 if (ren->eventStatus!=ID_READY_EVENT_FORCE_ALL_SET)
00326                 {
00327                         ren->eventStatus=ID_READY_EVENT_FORCE_ALL_SET;
00328                         PushCompletionPacket(ren->eventId);
00329                 }
00330         }
00331 }
00332 void ReadyEvent::OnReadyEventPacketUpdate(Packet *packet)
00333 {
00334         RakNet::BitStream incomingBitStream(packet->data, packet->length, false);
00335         incomingBitStream.IgnoreBits(8);
00336         int eventId;
00337         incomingBitStream.Read(eventId);
00338         bool objectExists;
00339         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00340         if (objectExists)
00341         {
00342                 ReadyEventNode *ren = readyEventNodeList[readyIndex];
00343                 bool systemExists;
00344                 unsigned systemIndex = ren->systemList.GetIndexFromKey(packet->systemAddress, &systemExists);
00345                 if (systemExists)
00346                 {
00347                         // Just return if no change
00348                         if (ren->systemList[systemIndex].lastReceivedStatus==packet->data[0])
00349                                 return;
00350 
00351                         bool wasCompleted = IsEventCompletedByIndex(readyIndex);
00352                         ren->systemList[systemIndex].lastReceivedStatus=packet->data[0];
00353                         // If forced all set, doesn't matter what the new packet is
00354                         if (ren->eventStatus==ID_READY_EVENT_FORCE_ALL_SET)
00355                                 return;
00356                         UpdateReadyStatus(readyIndex);
00357                         if (wasCompleted==false && IsEventCompletedByIndex(readyIndex))
00358                                 PushCompletionPacket(readyIndex);
00359                 }
00360         }
00361 }
00362 void ReadyEvent::OnReadyEventQuery(Packet *packet)
00363 {
00364         RakNet::BitStream incomingBitStream(packet->data, packet->length, false);
00365         incomingBitStream.IgnoreBits(8);
00366         int eventId;
00367         incomingBitStream.Read(eventId);
00368         bool objectExists;
00369         unsigned readyIndex = readyEventNodeList.GetIndexFromKey(eventId, &objectExists);
00370         if (objectExists)
00371         {
00372                 unsigned systemIndex = readyEventNodeList[readyIndex]->systemList.GetIndexFromKey(packet->systemAddress,&objectExists);
00373                 // Force the non-default send, because our initial send may have arrived at a system that didn't yet create the ready event
00374                 if (objectExists)
00375                         SendReadyUpdate(readyIndex, systemIndex, true);
00376         }
00377 }
00378 void ReadyEvent::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
00379 {
00380         (void) systemAddress;
00381         (void) rakNetGUID;
00382         (void) lostConnectionReason;
00383 
00384         RemoveFromAllLists(systemAddress);
00385 }
00386 void ReadyEvent::OnRakPeerShutdown(void)
00387 {
00388         Clear();
00389 }
00390 
00391 bool ReadyEvent::SetEventByIndex(int eventIndex, bool isReady)
00392 {
00393         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00394         if ((ren->eventStatus==ID_READY_EVENT_ALL_SET || ren->eventStatus==ID_READY_EVENT_SET) && isReady==true)
00395                 return true; // Success - no change
00396         if (ren->eventStatus==ID_READY_EVENT_UNSET && isReady==false)
00397                 return true; // Success - no change
00398         if (ren->eventStatus==ID_READY_EVENT_FORCE_ALL_SET)
00399                 return true; // Can't change
00400 
00401         if (isReady)
00402                 ren->eventStatus=ID_READY_EVENT_SET;
00403         else
00404                 ren->eventStatus=ID_READY_EVENT_UNSET;
00405 
00406         UpdateReadyStatus(eventIndex);
00407 
00408         // Check if now completed, and if so, tell the user about it
00409         if (IsEventCompletedByIndex(eventIndex))
00410         {
00411                 PushCompletionPacket(ren->eventId);
00412         }
00413 
00414         return true;
00415 }
00416 
00417 bool ReadyEvent::IsEventCompletedByIndex(unsigned eventIndex) const
00418 {
00419         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00420         unsigned i;
00421         if (ren->eventStatus==ID_READY_EVENT_FORCE_ALL_SET)
00422                 return true;
00423         if (ren->eventStatus!=ID_READY_EVENT_ALL_SET)
00424                 return false;
00425         for (i=0; i < ren->systemList.Size(); i++)
00426                 if (ren->systemList[i].lastReceivedStatus!=ID_READY_EVENT_ALL_SET)
00427                         return false;
00428         return true;
00429 }
00430 
00431 void ReadyEvent::Clear(void)
00432 {
00433         unsigned i;
00434         for (i=0; i < readyEventNodeList.Size(); i++)
00435         {
00436                 RakNet::OP_DELETE(readyEventNodeList[i], __FILE__, __LINE__);
00437         }
00438         readyEventNodeList.Clear(false, __FILE__, __LINE__);
00439 }
00440 
00441 unsigned ReadyEvent::CreateNewEvent(int eventId, bool isReady)
00442 {
00443         ReadyEventNode *ren = RakNet::OP_NEW<ReadyEventNode>( __FILE__, __LINE__ );
00444         ren->eventId=eventId;
00445         if (isReady==false)
00446                 ren->eventStatus=ID_READY_EVENT_UNSET;
00447         else
00448                 ren->eventStatus=ID_READY_EVENT_SET;
00449         return readyEventNodeList.Insert(eventId, ren, true, __FILE__,__LINE__);
00450 }
00451 void ReadyEvent::UpdateReadyStatus(unsigned eventIndex)
00452 {
00453         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00454         bool anyUnset;
00455         unsigned i;
00456         if (ren->eventStatus==ID_READY_EVENT_SET)
00457         {
00458                 // If you are set, and no other systems are ID_READY_EVENT_UNSET, then change your status to ID_READY_EVENT_ALL_SET
00459                 anyUnset=false;
00460                 for (i=0; i < ren->systemList.Size(); i++)
00461                 {
00462                         if (ren->systemList[i].lastReceivedStatus==ID_READY_EVENT_UNSET)
00463                         {
00464                                 anyUnset=true;
00465                                 break;
00466                         }
00467                 }
00468                 if (anyUnset==false)
00469                 {
00470                         ren->eventStatus=ID_READY_EVENT_ALL_SET;
00471                 }
00472         }
00473         else if (ren->eventStatus==ID_READY_EVENT_ALL_SET)
00474         {
00475                 // If you are all set, and any systems are ID_READY_EVENT_UNSET, then change your status to ID_READY_EVENT_SET
00476                 anyUnset=false;
00477                 for (i=0; i < ren->systemList.Size(); i++)
00478                 {
00479                         if (ren->systemList[i].lastReceivedStatus==ID_READY_EVENT_UNSET)
00480                         {
00481                                 anyUnset=true;
00482                                 break;
00483                         }
00484                 }
00485                 if (anyUnset==true)
00486                 {
00487                         ren->eventStatus=ID_READY_EVENT_SET;
00488                 }
00489         }
00490         BroadcastReadyUpdate(eventIndex, false);
00491 }
00492 void ReadyEvent::SendReadyUpdate(unsigned eventIndex, unsigned systemIndex, bool forceIfNotDefault)
00493 {
00494         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00495         RakNet::BitStream bs;
00496         // I do this rather than write true or false, so users that do not use BitStreams can still read the data
00497         if ((ren->eventStatus!=ren->systemList[systemIndex].lastSentStatus) ||
00498                 (forceIfNotDefault && ren->eventStatus!=ID_READY_EVENT_UNSET))
00499         {
00500                 bs.Write(ren->eventStatus);
00501                 bs.Write(ren->eventId);
00502                 SendUnified(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, channel, ren->systemList[systemIndex].systemAddress, false);
00503 
00504                 ren->systemList[systemIndex].lastSentStatus=ren->eventStatus;
00505         }
00506         
00507 }
00508 void ReadyEvent::BroadcastReadyUpdate(unsigned eventIndex, bool forceIfNotDefault)
00509 {
00510         ReadyEventNode *ren = readyEventNodeList[eventIndex];
00511         unsigned systemIndex;
00512         for (systemIndex=0; systemIndex < ren->systemList.Size(); systemIndex++)
00513         {
00514                 SendReadyUpdate(eventIndex, systemIndex, forceIfNotDefault);
00515         }
00516 }
00517 void ReadyEvent::SendReadyStateQuery(unsigned eventId, SystemAddress address)
00518 {
00519         RakNet::BitStream bs;
00520         bs.Write((MessageID)ID_READY_EVENT_QUERY);
00521         bs.Write(eventId);
00522         SendUnified(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, channel, address, false);
00523 }
00524 void ReadyEvent::RemoveFromAllLists(SystemAddress address)
00525 {
00526         unsigned eventIndex;
00527         for (eventIndex=0; eventIndex < readyEventNodeList.Size(); eventIndex++)
00528         {
00529                 bool isCompleted = IsEventCompletedByIndex(eventIndex);
00530                 bool systemExists;
00531                 unsigned systemIndex;
00532                 
00533                 systemIndex = readyEventNodeList[eventIndex]->systemList.GetIndexFromKey(address, &systemExists);
00534                 if (systemExists)
00535                         readyEventNodeList[eventIndex]->systemList.RemoveAtIndex(systemIndex);
00536         
00537                 UpdateReadyStatus(eventIndex);
00538 
00539                 if (isCompleted==false && IsEventCompletedByIndex(eventIndex))
00540                         PushCompletionPacket(readyEventNodeList[eventIndex]->eventId);
00541         }
00542 }
00543 void ReadyEvent::PushCompletionPacket(unsigned eventId)
00544 {
00545         (void) eventId;
00546         // Not necessary
00547         /*
00548         // Pass a packet to the user that we are now completed, as setting ourselves to signaled was the last thing being waited on
00549         Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID)+sizeof(int));
00550         RakNet::BitStream bs(p->data, sizeof(MessageID)+sizeof(int), false);
00551         bs.SetWriteOffset(0);
00552         bs.Write((MessageID)ID_READY_EVENT_ALL_SET);
00553         bs.Write(eventId);
00554         rakPeerInterface->PushBackPacket(p, false);
00555         */
00556 }
00557 #ifdef _MSC_VER
00558 #pragma warning( pop )
00559 #endif
00560 
00561 #endif // _RAKNET_SUPPORT_*

Generated on Thu Sep 30 2010 01:27:27 for RakNet by  doxygen 1.7.1