main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. // Demonstrates ReplicaManager 3: A system to automatically create, destroy, and serialize objects
  11. #include "StringTable.h"
  12. #include "RakPeerInterface.h"
  13. #include <stdio.h>
  14. #include "Kbhit.h"
  15. #include <string.h>
  16. #include "BitStream.h"
  17. #include "MessageIdentifiers.h"
  18. #include "ReplicaManager3.h"
  19. #include "NetworkIDManager.h"
  20. #include "RakSleep.h"
  21. #include "FormatString.h"
  22. #include "RakString.h"
  23. #include "GetTime.h"
  24. #include "SocketLayer.h"
  25. #include "Getche.h"
  26. #include "Rand.h"
  27. #include "VariableDeltaSerializer.h"
  28. #include "Gets.h"
  29. enum
  30. {
  31. CLIENT,
  32. SERVER,
  33. P2P
  34. } topology;
  35. // ReplicaManager3 is in the namespace RakNet
  36. using namespace RakNet;
  37. struct SampleReplica : public Replica3
  38. {
  39. SampleReplica() {var1Unreliable=0; var2Unreliable=0; var3Reliable=0; var4Reliable=0;}
  40. ~SampleReplica() {}
  41. virtual RakNet::RakString GetName(void) const=0;
  42. virtual void WriteAllocationID(RakNet::Connection_RM3 *destinationConnection, RakNet::BitStream *allocationIdBitstream) const {
  43. allocationIdBitstream->Write(GetName());
  44. }
  45. void PrintStringInBitstream(RakNet::BitStream *bs)
  46. {
  47. if (bs->GetNumberOfBitsUsed()==0)
  48. return;
  49. RakNet::RakString rakString;
  50. bs->Read(rakString);
  51. printf("Receive: %s\n", rakString.C_String());
  52. }
  53. virtual void SerializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *destinationConnection) {
  54. // variableDeltaSerializer is a helper class that tracks what variables were sent to what remote system
  55. // This call adds another remote system to track
  56. variableDeltaSerializer.AddRemoteSystemVariableHistory(destinationConnection->GetRakNetGUID());
  57. constructionBitstream->Write(GetName() + RakNet::RakString(" SerializeConstruction"));
  58. }
  59. virtual bool DeserializeConstruction(RakNet::BitStream *constructionBitstream, RakNet::Connection_RM3 *sourceConnection) {
  60. PrintStringInBitstream(constructionBitstream);
  61. return true;
  62. }
  63. virtual void SerializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *destinationConnection) {
  64. // variableDeltaSerializer is a helper class that tracks what variables were sent to what remote system
  65. // This call removes a remote system
  66. variableDeltaSerializer.RemoveRemoteSystemVariableHistory(destinationConnection->GetRakNetGUID());
  67. destructionBitstream->Write(GetName() + RakNet::RakString(" SerializeDestruction"));
  68. }
  69. virtual bool DeserializeDestruction(RakNet::BitStream *destructionBitstream, RakNet::Connection_RM3 *sourceConnection) {
  70. PrintStringInBitstream(destructionBitstream);
  71. return true;
  72. }
  73. virtual void DeallocReplica(RakNet::Connection_RM3 *sourceConnection) {
  74. delete this;
  75. }
  76. /// Overloaded Replica3 function
  77. virtual void OnUserReplicaPreSerializeTick(void)
  78. {
  79. /// Required by VariableDeltaSerializer::BeginIdenticalSerialize()
  80. variableDeltaSerializer.OnPreSerializeTick();
  81. }
  82. virtual RM3SerializationResult Serialize(SerializeParameters *serializeParameters) {
  83. VariableDeltaSerializer::SerializationContext serializationContext;
  84. // Put all variables to be sent unreliably on the same channel, then specify the send type for that channel
  85. serializeParameters->pro[0].reliability=UNRELIABLE_WITH_ACK_RECEIPT;
  86. // Sending unreliably with an ack receipt requires the receipt number, and that you inform the system of ID_SND_RECEIPT_ACKED and ID_SND_RECEIPT_LOSS
  87. serializeParameters->pro[0].sendReceipt=replicaManager->GetRakPeerInterface()->IncrementNextSendReceipt();
  88. serializeParameters->messageTimestamp=RakNet::GetTime();
  89. // Begin writing all variables to be sent UNRELIABLE_WITH_ACK_RECEIPT
  90. variableDeltaSerializer.BeginUnreliableAckedSerialize(
  91. &serializationContext,
  92. serializeParameters->destinationConnection->GetRakNetGUID(),
  93. &serializeParameters->outputBitstream[0],
  94. serializeParameters->pro[0].sendReceipt
  95. );
  96. // Write each variable
  97. variableDeltaSerializer.SerializeVariable(&serializationContext, var1Unreliable);
  98. // Write each variable
  99. variableDeltaSerializer.SerializeVariable(&serializationContext, var2Unreliable);
  100. // Tell the system this is the last variable to be written
  101. variableDeltaSerializer.EndSerialize(&serializationContext);
  102. // All variables to be sent using a different mode go on different channels
  103. serializeParameters->pro[1].reliability=RELIABLE_ORDERED;
  104. // Same as above, all variables to be sent with a particular reliability are sent in a batch
  105. // We use BeginIdenticalSerialize instead of BeginSerialize because the reliable variables have the same values sent to all systems. This is memory-saving optimization
  106. variableDeltaSerializer.BeginIdenticalSerialize(
  107. &serializationContext,
  108. serializeParameters->whenLastSerialized==0,
  109. &serializeParameters->outputBitstream[1]
  110. );
  111. variableDeltaSerializer.SerializeVariable(&serializationContext, var3Reliable);
  112. variableDeltaSerializer.SerializeVariable(&serializationContext, var4Reliable);
  113. variableDeltaSerializer.EndSerialize(&serializationContext);
  114. // This return type makes is to ReplicaManager3 itself does not do a memory compare. we entirely control serialization ourselves here.
  115. // Use RM3SR_SERIALIZED_ALWAYS instead of RM3SR_SERIALIZED_ALWAYS_IDENTICALLY to support sending different data to different system, which is needed when using unreliable and dirty variable resends
  116. return RM3SR_SERIALIZED_ALWAYS;
  117. }
  118. virtual void Deserialize(RakNet::DeserializeParameters *deserializeParameters) {
  119. VariableDeltaSerializer::DeserializationContext deserializationContext;
  120. // Deserialization is written similar to serialization
  121. // Note that the Serialize() call above uses two different reliability types. This results in two separate Send calls
  122. // So Deserialize is potentially called twice from a single Serialize
  123. variableDeltaSerializer.BeginDeserialize(&deserializationContext, &deserializeParameters->serializationBitstream[0]);
  124. if (variableDeltaSerializer.DeserializeVariable(&deserializationContext, var1Unreliable))
  125. printf("var1Unreliable changed to %i\n", var1Unreliable);
  126. if (variableDeltaSerializer.DeserializeVariable(&deserializationContext, var2Unreliable))
  127. printf("var2Unreliable changed to %i\n", var2Unreliable);
  128. variableDeltaSerializer.EndDeserialize(&deserializationContext);
  129. variableDeltaSerializer.BeginDeserialize(&deserializationContext, &deserializeParameters->serializationBitstream[1]);
  130. if (variableDeltaSerializer.DeserializeVariable(&deserializationContext, var3Reliable))
  131. printf("var3Reliable changed to %i\n", var3Reliable);
  132. if (variableDeltaSerializer.DeserializeVariable(&deserializationContext, var4Reliable))
  133. printf("var4Reliable changed to %i\n", var4Reliable);
  134. variableDeltaSerializer.EndDeserialize(&deserializationContext);
  135. }
  136. virtual void SerializeConstructionRequestAccepted(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *requestingConnection) {
  137. serializationBitstream->Write(GetName() + RakNet::RakString(" SerializeConstructionRequestAccepted"));
  138. }
  139. virtual void DeserializeConstructionRequestAccepted(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *acceptingConnection) {
  140. PrintStringInBitstream(serializationBitstream);
  141. }
  142. virtual void SerializeConstructionRequestRejected(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *requestingConnection) {
  143. serializationBitstream->Write(GetName() + RakNet::RakString(" SerializeConstructionRequestRejected"));
  144. }
  145. virtual void DeserializeConstructionRequestRejected(RakNet::BitStream *serializationBitstream, RakNet::Connection_RM3 *rejectingConnection) {
  146. PrintStringInBitstream(serializationBitstream);
  147. }
  148. virtual void OnPoppedConnection(RakNet::Connection_RM3 *droppedConnection)
  149. {
  150. // Same as in SerializeDestruction(), no longer track this system
  151. variableDeltaSerializer.RemoveRemoteSystemVariableHistory(droppedConnection->GetRakNetGUID());
  152. }
  153. void NotifyReplicaOfMessageDeliveryStatus(RakNetGUID guid, uint32_t receiptId, bool messageArrived)
  154. {
  155. // When using UNRELIABLE_WITH_ACK_RECEIPT, the system tracks which variables were updated with which sends
  156. // So it is then necessary to inform the system of messages arriving or lost
  157. // Lost messages will flag each variable sent in that update as dirty, meaning the next Serialize() call will resend them with the current values
  158. variableDeltaSerializer.OnMessageReceipt(guid,receiptId,messageArrived);
  159. }
  160. void RandomizeVariables(void)
  161. {
  162. if (randomMT()%2)
  163. {
  164. var1Unreliable=randomMT();
  165. printf("var1Unreliable changed to %i\n", var1Unreliable);
  166. }
  167. if (randomMT()%2)
  168. {
  169. var2Unreliable=randomMT();
  170. printf("var2Unreliable changed to %i\n", var2Unreliable);
  171. }
  172. if (randomMT()%2)
  173. {
  174. var3Reliable=randomMT();
  175. printf("var3Reliable changed to %i\n", var3Reliable);
  176. }
  177. if (randomMT()%2)
  178. {
  179. var4Reliable=randomMT();
  180. printf("var4Reliable changed to %i\n", var4Reliable);
  181. }
  182. }
  183. // Demonstrate per-variable synchronization
  184. // We manually test each variable to the last synchronized value and only send those values that change
  185. int var1Unreliable,var2Unreliable,var3Reliable,var4Reliable;
  186. // Class to save and compare the states of variables this Serialize() to the last Serialize()
  187. // If the value is different, true is written to the bitStream, followed by the value. Otherwise false is written.
  188. // It also tracks which variables changed which Serialize() call, so if an unreliable message was lost (ID_SND_RECEIPT_LOSS) those variables are flagged 'dirty' and resent
  189. VariableDeltaSerializer variableDeltaSerializer;
  190. };
  191. struct ClientCreatible_ClientSerialized : public SampleReplica {
  192. virtual RakNet::RakString GetName(void) const {return RakNet::RakString("ClientCreatible_ClientSerialized");}
  193. virtual RM3SerializationResult Serialize(SerializeParameters *serializeParameters)
  194. {
  195. return SampleReplica::Serialize(serializeParameters);
  196. }
  197. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {
  198. return QueryConstruction_ClientConstruction(destinationConnection,topology!=CLIENT);
  199. }
  200. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection) {
  201. return QueryRemoteConstruction_ClientConstruction(sourceConnection,topology!=CLIENT);
  202. }
  203. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection) {
  204. return QuerySerialization_ClientSerializable(destinationConnection,topology!=CLIENT);
  205. }
  206. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const {
  207. return QueryActionOnPopConnection_Client(droppedConnection);
  208. }
  209. };
  210. struct ServerCreated_ClientSerialized : public SampleReplica {
  211. virtual RakNet::RakString GetName(void) const {return RakNet::RakString("ServerCreated_ClientSerialized");}
  212. virtual RM3SerializationResult Serialize(SerializeParameters *serializeParameters)
  213. {
  214. return SampleReplica::Serialize(serializeParameters);
  215. }
  216. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {
  217. return QueryConstruction_ServerConstruction(destinationConnection,topology!=CLIENT);
  218. }
  219. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection) {
  220. return QueryRemoteConstruction_ServerConstruction(sourceConnection,topology!=CLIENT);
  221. }
  222. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection) {
  223. return QuerySerialization_ClientSerializable(destinationConnection,topology!=CLIENT);
  224. }
  225. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const {
  226. return QueryActionOnPopConnection_Server(droppedConnection);
  227. }
  228. };
  229. struct ClientCreatible_ServerSerialized : public SampleReplica {
  230. virtual RakNet::RakString GetName(void) const {return RakNet::RakString("ClientCreatible_ServerSerialized");}
  231. virtual RM3SerializationResult Serialize(SerializeParameters *serializeParameters)
  232. {
  233. if (topology==CLIENT)
  234. return RM3SR_DO_NOT_SERIALIZE;
  235. return SampleReplica::Serialize(serializeParameters);
  236. }
  237. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {
  238. return QueryConstruction_ClientConstruction(destinationConnection,topology!=CLIENT);
  239. }
  240. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection) {
  241. return QueryRemoteConstruction_ClientConstruction(sourceConnection,topology!=CLIENT);
  242. }
  243. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection) {
  244. return QuerySerialization_ServerSerializable(destinationConnection,topology!=CLIENT);
  245. }
  246. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const {
  247. return QueryActionOnPopConnection_Client(droppedConnection);
  248. }
  249. };
  250. struct ServerCreated_ServerSerialized : public SampleReplica {
  251. virtual RakNet::RakString GetName(void) const {return RakNet::RakString("ServerCreated_ServerSerialized");}
  252. virtual RM3SerializationResult Serialize(SerializeParameters *serializeParameters)
  253. {
  254. if (topology==CLIENT)
  255. return RM3SR_DO_NOT_SERIALIZE;
  256. return SampleReplica::Serialize(serializeParameters);
  257. }
  258. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {
  259. return QueryConstruction_ServerConstruction(destinationConnection,topology!=CLIENT);
  260. }
  261. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection) {
  262. return QueryRemoteConstruction_ServerConstruction(sourceConnection,topology!=CLIENT);
  263. }
  264. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection) {
  265. return QuerySerialization_ServerSerializable(destinationConnection,topology!=CLIENT);
  266. }
  267. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const {
  268. return QueryActionOnPopConnection_Server(droppedConnection);
  269. }
  270. };
  271. struct P2PReplica : public SampleReplica {
  272. virtual RakNet::RakString GetName(void) const {return RakNet::RakString("P2PReplica");}
  273. virtual RM3ConstructionState QueryConstruction(RakNet::Connection_RM3 *destinationConnection, ReplicaManager3 *replicaManager3) {
  274. return QueryConstruction_PeerToPeer(destinationConnection);
  275. }
  276. virtual bool QueryRemoteConstruction(RakNet::Connection_RM3 *sourceConnection) {
  277. return QueryRemoteConstruction_PeerToPeer(sourceConnection);
  278. }
  279. virtual RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *destinationConnection) {
  280. return QuerySerialization_PeerToPeer(destinationConnection);
  281. }
  282. virtual RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *droppedConnection) const {
  283. return QueryActionOnPopConnection_PeerToPeer(droppedConnection);
  284. }
  285. };
  286. class SampleConnection : public Connection_RM3 {
  287. public:
  288. SampleConnection(const SystemAddress &_systemAddress, RakNetGUID _guid) : Connection_RM3(_systemAddress, _guid) {}
  289. virtual ~SampleConnection() {}
  290. // See documentation - Makes all messages between ID_REPLICA_MANAGER_DOWNLOAD_STARTED and ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE arrive in one tick
  291. bool QueryGroupDownloadMessages(void) const {return true;}
  292. virtual Replica3 *AllocReplica(RakNet::BitStream *allocationId, ReplicaManager3 *replicaManager3)
  293. {
  294. RakNet::RakString typeName;
  295. allocationId->Read(typeName);
  296. if (typeName=="ClientCreatible_ClientSerialized") return new ClientCreatible_ClientSerialized;
  297. if (typeName=="ServerCreated_ClientSerialized") return new ServerCreated_ClientSerialized;
  298. if (typeName=="ClientCreatible_ServerSerialized") return new ClientCreatible_ServerSerialized;
  299. if (typeName=="ServerCreated_ServerSerialized") return new ServerCreated_ServerSerialized;
  300. if (typeName=="P2PReplica") return new P2PReplica;
  301. return 0;
  302. }
  303. protected:
  304. };
  305. class ReplicaManager3Sample : public ReplicaManager3
  306. {
  307. virtual Connection_RM3* AllocConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID) const {
  308. return new SampleConnection(systemAddress,rakNetGUID);
  309. }
  310. virtual void DeallocConnection(Connection_RM3 *connection) const {
  311. delete connection;
  312. }
  313. };
  314. int main(void)
  315. {
  316. char ch;
  317. RakNet::SocketDescriptor sd;
  318. sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255
  319. char ip[128];
  320. static const int SERVER_PORT=12345;
  321. // ReplicaManager3 requires NetworkIDManager to lookup pointers from numbers.
  322. NetworkIDManager networkIdManager;
  323. // Each application has one instance of RakPeerInterface
  324. RakNet::RakPeerInterface *rakPeer;
  325. // The system that performs most of our functionality for this demo
  326. ReplicaManager3Sample replicaManager;
  327. printf("Demonstration of ReplicaManager3.\n");
  328. printf("1. Demonstrates creating objects created by the server and client.\n");
  329. printf("2. Demonstrates automatic serialization data members\n");
  330. printf("Difficulty: Intermediate\n\n");
  331. printf("Start as (c)lient, (s)erver, (p)eer? ");
  332. ch=getche();
  333. rakPeer = RakNet::RakPeerInterface::GetInstance();
  334. if (ch=='c' || ch=='C')
  335. {
  336. topology=CLIENT;
  337. sd.port=0;
  338. }
  339. else if (ch=='s' || ch=='S')
  340. {
  341. topology=SERVER;
  342. sd.port=SERVER_PORT;
  343. }
  344. else
  345. {
  346. topology=P2P;
  347. sd.port=SERVER_PORT;
  348. while (IRNS2_Berkley::IsPortInUse(sd.port,sd.hostAddress,sd.socketFamily, SOCK_DGRAM)==true)
  349. sd.port++;
  350. }
  351. // Start RakNet, up to 32 connections if the server
  352. rakPeer->Startup(32,&sd,1);
  353. rakPeer->AttachPlugin(&replicaManager);
  354. replicaManager.SetNetworkIDManager(&networkIdManager);
  355. rakPeer->SetMaximumIncomingConnections(32);
  356. printf("\nMy GUID is %s\n", rakPeer->GetMyGUID().ToString());
  357. printf("\n");
  358. if (topology==CLIENT)
  359. {
  360. printf("Enter server IP: ");
  361. Gets(ip, sizeof(ip));
  362. if (ip[0]==0)
  363. strcpy(ip, "127.0.0.1");
  364. rakPeer->Connect(ip,SERVER_PORT,0,0,0);
  365. printf("Connecting...\n");
  366. }
  367. printf("Commands:\n(Q)uit\n'C'reate objects\n'R'andomly change variables in my objects\n'D'estroy my objects\n");
  368. // Enter infinite loop to run the system
  369. RakNet::Packet *packet;
  370. bool quit=false;
  371. while (!quit)
  372. {
  373. for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
  374. {
  375. switch (packet->data[0])
  376. {
  377. case ID_CONNECTION_ATTEMPT_FAILED:
  378. printf("ID_CONNECTION_ATTEMPT_FAILED\n");
  379. quit=true;
  380. break;
  381. case ID_NO_FREE_INCOMING_CONNECTIONS:
  382. printf("ID_NO_FREE_INCOMING_CONNECTIONS\n");
  383. quit=true;
  384. break;
  385. case ID_CONNECTION_REQUEST_ACCEPTED:
  386. printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
  387. break;
  388. case ID_NEW_INCOMING_CONNECTION:
  389. printf("ID_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString());
  390. break;
  391. case ID_DISCONNECTION_NOTIFICATION:
  392. printf("ID_DISCONNECTION_NOTIFICATION\n");
  393. break;
  394. case ID_CONNECTION_LOST:
  395. printf("ID_CONNECTION_LOST\n");
  396. break;
  397. case ID_ADVERTISE_SYSTEM:
  398. // The first conditional is needed because ID_ADVERTISE_SYSTEM may be from a system we are connected to, but replying on a different address.
  399. // The second conditional is because AdvertiseSystem also sends to the loopback
  400. if (rakPeer->GetSystemAddressFromGuid(packet->guid)==RakNet::UNASSIGNED_SYSTEM_ADDRESS &&
  401. rakPeer->GetMyGUID()!=packet->guid)
  402. {
  403. printf("Connecting to %s\n", packet->systemAddress.ToString(true));
  404. rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0);
  405. }
  406. break;
  407. case ID_SND_RECEIPT_LOSS:
  408. case ID_SND_RECEIPT_ACKED:
  409. {
  410. uint32_t msgNumber;
  411. memcpy(&msgNumber, packet->data+1, 4);
  412. DataStructures::List<Replica3*> replicaListOut;
  413. replicaManager.GetReplicasCreatedByMe(replicaListOut);
  414. unsigned int idx;
  415. for (idx=0; idx < replicaListOut.Size(); idx++)
  416. {
  417. ((SampleReplica*)replicaListOut[idx])->NotifyReplicaOfMessageDeliveryStatus(packet->guid,msgNumber, packet->data[0]==ID_SND_RECEIPT_ACKED);
  418. }
  419. }
  420. break;
  421. }
  422. }
  423. if (kbhit())
  424. {
  425. ch=getch();
  426. if (ch=='q' || ch=='Q')
  427. {
  428. printf("Quitting.\n");
  429. quit=true;
  430. }
  431. if (ch=='c' || ch=='C')
  432. {
  433. printf("Objects created.\n");
  434. if (topology==SERVER||topology==CLIENT)
  435. {
  436. replicaManager.Reference(new ClientCreatible_ClientSerialized);
  437. replicaManager.Reference(new ServerCreated_ClientSerialized);
  438. replicaManager.Reference(new ClientCreatible_ServerSerialized);
  439. replicaManager.Reference(new ServerCreated_ServerSerialized);
  440. }
  441. else
  442. {
  443. // for (int i=0; i < 20; i++)
  444. replicaManager.Reference(new P2PReplica);
  445. }
  446. }
  447. if (ch=='r' || ch=='R')
  448. {
  449. DataStructures::List<Replica3*> replicaListOut;
  450. replicaManager.GetReplicasCreatedByMe(replicaListOut);
  451. unsigned int idx;
  452. for (idx=0; idx < replicaListOut.Size(); idx++)
  453. {
  454. ((SampleReplica*)replicaListOut[idx])->RandomizeVariables();
  455. }
  456. }
  457. if (ch=='d' || ch=='D')
  458. {
  459. printf("My objects destroyed.\n");
  460. DataStructures::List<Replica3*> replicaListOut;
  461. // The reason for ClearPointers is that in the sample, I don't track which objects have and have not been allocated at the application level. So ClearPointers will call delete on every object in the returned list, which is every object that the application has created. Another way to put it is
  462. // A. Send a packet to tell other systems to delete these objects
  463. // B. Delete these objects on my own system
  464. replicaManager.GetReplicasCreatedByMe(replicaListOut);
  465. replicaManager.BroadcastDestructionList(replicaListOut, RakNet::UNASSIGNED_SYSTEM_ADDRESS);
  466. for (unsigned int i=0; i < replicaListOut.Size(); i++)
  467. RakNet::OP_DELETE(replicaListOut[i], _FILE_AND_LINE_);
  468. }
  469. }
  470. RakSleep(30);
  471. for (int i=0; i < 4; i++)
  472. {
  473. if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=SERVER_PORT+i)
  474. rakPeer->AdvertiseSystem("255.255.255.255", SERVER_PORT+i, 0,0,0);
  475. }
  476. }
  477. rakPeer->Shutdown(100,0);
  478. RakNet::RakPeerInterface::DestroyInstance(rakPeer);
  479. }
粤ICP备19079148号