ClientObjectManager::ClientObjectManager( Mode mode, PluginState state, sigc::signal<void>& rUpdateSignal, sigc::signal<void>& rLateUpdateSignal, ClientPluginManager& rPluginManager, RakNet::RakPeerInterface& rRakPeer, RakNet::ReplicaManager3& rReplicaManager, RakNet::NetworkIDManager& rNetworkIDManager ): ObjectManager( mode, rRakPeer.GetMyGUID(), rRakPeer.GetGUIDFromIndex( 0 ), rUpdateSignal, rLateUpdateSignal, rPluginManager.getPlugin<ClientObjectTemplateManager>(), rReplicaManager, rNetworkIDManager, rPluginManager.getServer().getServerConnection().getRPC3() ), ClientPlugin( mode, state, rPluginManager, rRakPeer, rReplicaManager, rNetworkIDManager ), mPermissionManager( rPluginManager.getPlugin<PermissionManager>() ) { PropertySynchronization::storeUserObject(); try { Plugin::getPluginManager().getPlugin<LuaPlugin>().get().object( "ObjectManager" ) = this; } catch( Exception e ) { LCLOGE << "Could not add ObjectManager object to lua: " << e.what(); } }
int main(int argc, char **argv) { const char *DEFAULT_SERVER_ADDRESS="test.dnsalias.net"; const unsigned short DEFAULT_SERVER_PORT=60000; const char *serverAddress; unsigned short serverPort; #ifndef _DEBUG // Only use DEFAULT_SERVER_ADDRESS for debugging if (argc<2) { PrintHelp(); return false; } #endif if (argc<2) serverAddress=DEFAULT_SERVER_ADDRESS; else serverAddress=argv[1]; if (argc<3) serverPort=DEFAULT_SERVER_PORT; else serverPort=atoi(argv[2]); // ---- RAKPEER ----- RakNet::RakPeerInterface *rakPeer; rakPeer=RakNet::RakPeerInterface::GetInstance(); static const unsigned short clientLocalPort=0; RakNet::SocketDescriptor sd(clientLocalPort,0); // Change this if you want RakNet::StartupResult sr = rakPeer->Startup(1,&sd,1); // Change this if you want rakPeer->SetMaximumIncomingConnections(0); // Change this if you want if (sr!=RakNet::RAKNET_STARTED) { printf("Startup failed. Reason=%i\n", (int) sr); return 1; } RakNet::CloudClient cloudClient; rakPeer->AttachPlugin(&cloudClient); RakNet::ConnectionAttemptResult car = rakPeer->Connect(serverAddress, serverPort, 0, 0); if (car==RakNet::CANNOT_RESOLVE_DOMAIN_NAME) { printf("Cannot resolve domain name\n"); return 1; } printf("Connecting to %s...\n", serverAddress); bool didRebalance=false; // So we only reconnect to a lower load server once, for load balancing RakNet::Packet *packet; while (1) { for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { switch (packet->data[0]) { case ID_CONNECTION_LOST: printf("Lost connection to server.\n"); return 1; case ID_CONNECTION_ATTEMPT_FAILED: printf("Failed to connect to server at %s.\n", packet->systemAddress.ToString(true)); return 1; case ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY: case ID_OUR_SYSTEM_REQUIRES_SECURITY: case ID_PUBLIC_KEY_MISMATCH: case ID_INVALID_PASSWORD: case ID_CONNECTION_BANNED: // You won't see these unless you modified CloudServer printf("Server rejected the connection.\n"); return 1; case ID_INCOMPATIBLE_PROTOCOL_VERSION: printf("Server is running an incompatible RakNet version.\n"); return 1; case ID_NO_FREE_INCOMING_CONNECTIONS: printf("Server has no free connections\n"); return 1; case ID_IP_RECENTLY_CONNECTED: printf("Recently connected. Retrying."); rakPeer->Connect(serverAddress, serverPort, 0, 0); break; case ID_CONNECTION_REQUEST_ACCEPTED: printf("Connected to server.\n"); UploadInstanceToCloud(&cloudClient, packet->guid); GetClientSubscription(&cloudClient, packet->guid); GetServers(&cloudClient, packet->guid); break; case ID_CLOUD_GET_RESPONSE: { RakNet::CloudQueryResult cloudQueryResult; cloudClient.OnGetReponse(&cloudQueryResult, packet); unsigned int rowIndex; const bool wasCallToGetServers=cloudQueryResult.cloudQuery.keys[0].primaryKey=="CloudConnCount"; printf("\n"); if (wasCallToGetServers) printf("Downloaded server list. %i servers.\n", cloudQueryResult.rowsReturned.Size()); else printf("Downloaded client list. %i clients.\n", cloudQueryResult.rowsReturned.Size()); unsigned short connectionsOnOurServer=65535; unsigned short lowestConnectionsServer=65535; RakNet::SystemAddress lowestConnectionAddress; for (rowIndex=0; rowIndex < cloudQueryResult.rowsReturned.Size(); rowIndex++) { RakNet::CloudQueryRow *row = cloudQueryResult.rowsReturned[rowIndex]; if (wasCallToGetServers) { unsigned short connCount; RakNet::BitStream bsIn(row->data, row->length, false); bsIn.Read(connCount); printf("%i. Server found at %s with %i connections\n", rowIndex+1, row->serverSystemAddress.ToString(true), connCount); unsigned short connectionsExcludingOurselves; if (row->serverGUID==packet->guid) connectionsExcludingOurselves=connCount-1; else connectionsExcludingOurselves=connCount; // Find the lowest load server (optional) if (packet->guid==row->serverGUID) { connectionsOnOurServer=connectionsExcludingOurselves; } else if (connectionsExcludingOurselves < lowestConnectionsServer) { lowestConnectionsServer=connectionsExcludingOurselves; lowestConnectionAddress=row->serverSystemAddress; } } else { printf("%i. Client found at %s", rowIndex+1, row->clientSystemAddress.ToString(true)); if (row->clientGUID==rakPeer->GetMyGUID()) printf(" (Ourselves)"); RakNet::BitStream bsIn(row->data, row->length, false); RakNet::RakString clientData; bsIn.Read(clientData); printf(" Data: %s", clientData.C_String()); printf("\n"); } } // Do load balancing by reconnecting to lowest load server (optional) if (didRebalance==false && wasCallToGetServers && cloudQueryResult.rowsReturned.Size()>0 && connectionsOnOurServer>lowestConnectionsServer) { printf("Reconnecting to lower load server %s\n", lowestConnectionAddress.ToString(false)); rakPeer->CloseConnection(packet->guid, true); // Wait for the thread to close, otherwise will immediately get back ID_CONNECTION_ATTEMPT_FAILED because no free outgoing connection slots // Alternatively, just call Startup() with 2 slots instead of 1 RakSleep(500); rakPeer->Connect(lowestConnectionAddress.ToString(false), lowestConnectionAddress.GetPort(), 0, 0); didRebalance=true; } cloudClient.DeallocateWithDefaultAllocator(&cloudQueryResult); } break; case ID_CLOUD_SUBSCRIPTION_NOTIFICATION: { bool wasUpdated; RakNet::CloudQueryRow cloudQueryRow; cloudClient.OnSubscriptionNotification(&wasUpdated, &cloudQueryRow, packet, 0 ); if (wasUpdated) printf("New client at %s\n", cloudQueryRow.clientSystemAddress.ToString(true)); else printf("Lost client at %s\n", cloudQueryRow.clientSystemAddress.ToString(true)); cloudClient.DeallocateWithDefaultAllocator(&cloudQueryRow); } break; } } // Any additional client processing can go here RakSleep(30); } RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; }
int main(void) { char ch; RakNet::SocketDescriptor sd; sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255 char ip[128]; static const int SERVER_PORT=12345; // ReplicaManager3 requires NetworkIDManager to lookup pointers from numbers. NetworkIDManager networkIdManager; // Each application has one instance of RakPeerInterface RakNet::RakPeerInterface *rakPeer; // The system that performs most of our functionality for this demo ReplicaManager3Sample replicaManager; printf("Demonstration of ReplicaManager3.\n"); printf("1. Demonstrates creating objects created by the server and client.\n"); printf("2. Demonstrates automatic serialization data members\n"); printf("Difficulty: Intermediate\n\n"); printf("Start as (c)lient, (s)erver, (p)eer? "); ch=getche(); rakPeer = RakNet::RakPeerInterface::GetInstance(); if (ch=='c' || ch=='C') { topology=CLIENT; sd.port=0; } else if (ch=='s' || ch=='S') { topology=SERVER; sd.port=SERVER_PORT; } else { topology=P2P; sd.port=SERVER_PORT; while (IRNS2_Berkley::IsPortInUse(sd.port,sd.hostAddress,sd.socketFamily, SOCK_DGRAM)==true) sd.port++; } // Start RakNet, up to 32 connections if the server rakPeer->Startup(32,&sd,1); rakPeer->AttachPlugin(&replicaManager); replicaManager.SetNetworkIDManager(&networkIdManager); rakPeer->SetMaximumIncomingConnections(32); printf("\nMy GUID is %s\n", rakPeer->GetMyGUID().ToString()); printf("\n"); if (topology==CLIENT) { printf("Enter server IP: "); Gets(ip, sizeof(ip)); if (ip[0]==0) strcpy(ip, "127.0.0.1"); rakPeer->Connect(ip,SERVER_PORT,0,0,0); printf("Connecting...\n"); } printf("Commands:\n(Q)uit\n'C'reate objects\n'R'andomly change variables in my objects\n'D'estroy my objects\n"); // Enter infinite loop to run the system RakNet::Packet *packet; bool quit=false; while (!quit) { for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive()) { switch (packet->data[0]) { case ID_CONNECTION_ATTEMPT_FAILED: printf("ID_CONNECTION_ATTEMPT_FAILED\n"); quit=true; break; case ID_NO_FREE_INCOMING_CONNECTIONS: printf("ID_NO_FREE_INCOMING_CONNECTIONS\n"); quit=true; break; case ID_CONNECTION_REQUEST_ACCEPTED: printf("ID_CONNECTION_REQUEST_ACCEPTED\n"); break; case ID_NEW_INCOMING_CONNECTION: printf("ID_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString()); break; case ID_DISCONNECTION_NOTIFICATION: printf("ID_DISCONNECTION_NOTIFICATION\n"); break; case ID_CONNECTION_LOST: printf("ID_CONNECTION_LOST\n"); break; case ID_ADVERTISE_SYSTEM: // The first conditional is needed because ID_ADVERTISE_SYSTEM may be from a system we are connected to, but replying on a different address. // The second conditional is because AdvertiseSystem also sends to the loopback if (rakPeer->GetSystemAddressFromGuid(packet->guid)==RakNet::UNASSIGNED_SYSTEM_ADDRESS && rakPeer->GetMyGUID()!=packet->guid) { printf("Connecting to %s\n", packet->systemAddress.ToString(true)); rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0); } break; case ID_SND_RECEIPT_LOSS: case ID_SND_RECEIPT_ACKED: { uint32_t msgNumber; memcpy(&msgNumber, packet->data+1, 4); DataStructures::List<Replica3*> replicaListOut; replicaManager.GetReplicasCreatedByMe(replicaListOut); unsigned int idx; for (idx=0; idx < replicaListOut.Size(); idx++) { ((SampleReplica*)replicaListOut[idx])->NotifyReplicaOfMessageDeliveryStatus(packet->guid,msgNumber, packet->data[0]==ID_SND_RECEIPT_ACKED); } } break; } } if (kbhit()) { ch=getch(); if (ch=='q' || ch=='Q') { printf("Quitting.\n"); quit=true; } if (ch=='c' || ch=='C') { printf("Objects created.\n"); if (topology==SERVER||topology==CLIENT) { replicaManager.Reference(new ClientCreatible_ClientSerialized); replicaManager.Reference(new ServerCreated_ClientSerialized); replicaManager.Reference(new ClientCreatible_ServerSerialized); replicaManager.Reference(new ServerCreated_ServerSerialized); } else { // for (int i=0; i < 20; i++) replicaManager.Reference(new P2PReplica); } } if (ch=='r' || ch=='R') { DataStructures::List<Replica3*> replicaListOut; replicaManager.GetReplicasCreatedByMe(replicaListOut); unsigned int idx; for (idx=0; idx < replicaListOut.Size(); idx++) { ((SampleReplica*)replicaListOut[idx])->RandomizeVariables(); } } if (ch=='d' || ch=='D') { printf("My objects destroyed.\n"); DataStructures::List<Replica3*> replicaListOut; // 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 // A. Send a packet to tell other systems to delete these objects // B. Delete these objects on my own system replicaManager.GetReplicasCreatedByMe(replicaListOut); replicaManager.BroadcastDestructionList(replicaListOut, RakNet::UNASSIGNED_SYSTEM_ADDRESS); for (unsigned int i=0; i < replicaListOut.Size(); i++) RakNet::OP_DELETE(replicaListOut[i], _FILE_AND_LINE_); } } RakSleep(30); for (int i=0; i < 4; i++) { if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=SERVER_PORT+i) rakPeer->AdvertiseSystem("255.255.255.255", SERVER_PORT+i, 0,0,0); } } rakPeer->Shutdown(100,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); }