void FullyConnectedMesh2::AddParticipant( RakNetGUID rakNetGuid )
{
	if (rakPeerInterface->GetConnectionState(rakPeerInterface->GetSystemAddressFromGuid(rakNetGuid))!=IS_CONNECTED)
	{
#ifdef DEBUG_FCM2
		printf("AddParticipant to %s failed (not connected)\n", rakNetGuid.ToString());
#endif
		return;
	}

	AddParticipantInternal(rakNetGuid,0);
}
void NatPunchthroughClient::SendPunchthrough(RakNetGUID destination, const SystemAddress &facilitator)
{
	RakNet::BitStream outgoingBs;
	outgoingBs.Write((MessageID)ID_NAT_PUNCHTHROUGH_REQUEST);
	outgoingBs.Write(destination);
	rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,facilitator,false);

//	RakAssert(rakPeerInterface->GetSystemAddressFromGuid(destination)==UNASSIGNED_SYSTEM_ADDRESS);

	if (natPunchthroughDebugInterface)
	{
		char guidString[128];
		destination.ToString(guidString);
		natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Starting ID_NAT_PUNCHTHROUGH_REQUEST to guid %s.", guidString));
	}
}
	// Implemented event callback from base class PluginInterface2
	virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
	{
		// Call down to the base class in case it does anything in the future (right now it does nothing)
		SQLite3ServerPlugin::OnNewConnection(systemAddress, rakNetGUID, isIncoming);

		// Get the database index associated with the table used for this class
		unsigned int idx = dbHandles.GetIndexOf(connectionStateIdentifier);
		if (idx==(unsigned int)-1)
			return;

		// Store new system's system address and guid. rowCreationTime column is created automatically
		char systemAddressString[64];
		systemAddress.ToString(true,systemAddressString);
		char guidString[128];
		rakNetGUID.ToString(guidString);
		RakNet::RakString query(
			"INSERT INTO connectionState (systemAddress,rakNetGUID) VALUES ('%s','%s');",
			RakNet::RakString(systemAddressString).SQLEscape().C_String(),
			RakNet::RakString(guidString).SQLEscape().C_String());
		sqlite3_exec(dbHandles[idx].dbHandle,query.C_String(),0,0,0);
	}
void RoomsBrowserGFx3_RakNet::OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
{
	if (systemAddress==lobby2Client->GetServerAddress())
	{
		// is connected
		FxResponseArgs<0> rargs;
		FxDelegate::Invoke2(movie, "c2f_NotifyConnectionAttemptToServerSuccess", rargs);
	}
	else
	{
		FxResponseArgs<3> rargs;
		char saString[64];
		systemAddress.ToString(true,saString);
		char guidString[64];
		rakNetGUID.ToString(guidString);
		rargs.Add(saString);
		rargs.Add(guidString);
		rargs.Add(isIncoming);
		FxDelegate::Invoke2(movie, "c2f_NotifyNewConnection", rargs);
	}
}
PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet)
{
	switch (packet->data[0])
	{
	case ID_NAT_GET_MOST_RECENT_PORT:
		{
			OnGetMostRecentPort(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
	case ID_NAT_PUNCHTHROUGH_FAILED:
	case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
		if (packet->wasGeneratedLocally==false)
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		break;
	case ID_NAT_RESPOND_BOUND_ADDRESSES:
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(sizeof(MessageID));
			unsigned char boundAddressCount;
			bs.Read(boundAddressCount);
			if (boundAddressCount<2)
			{
				if (natPunchthroughDebugInterface)
					natPunchthroughDebugInterface->OnClientMessage("INCAPABLE_PORT_STRIDE");

				hasPortStride=INCAPABLE_PORT_STRIDE;
				SendQueuedOpenNAT();
			}
			SystemAddress boundAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
			for (int i=0; i < boundAddressCount && i < MAXIMUM_NUMBER_OF_INTERNAL_IDS; i++)
			{
				bs.Read(boundAddresses[i]);
				if (boundAddresses[i]!=packet->systemAddress)
				{
					RakNet::BitStream outgoingBs;
					outgoingBs.Write((MessageID)ID_NAT_PING);
					uint16_t externalPort = rakPeerInterface->GetExternalID(packet->systemAddress).GetPort();
					outgoingBs.Write( externalPort );
					rakPeerInterface->SendOutOfBand((const char*) boundAddresses[i].ToString(false),boundAddresses[i].GetPort(),(const char*) outgoingBs.GetData(),outgoingBs.GetNumberOfBytesUsed());
					break;
				}
			}
		}
		break;		
	case ID_OUT_OF_BAND_INTERNAL:
		if (packet->length>=2 && packet->data[1]==ID_NAT_PONG)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(sizeof(MessageID)*2);
			uint16_t externalPort;
			bs.Read(externalPort);
			uint16_t externalPort2;
			bs.Read(externalPort2);
			portStride = externalPort2 - externalPort;
			hasPortStride=HAS_PORT_STRIDE;

			if (natPunchthroughDebugInterface)
				natPunchthroughDebugInterface->OnClientMessage(RakString("HAS_PORT_STRIDE %i. Server first external port %i. Server second external port %i.", portStride, externalPort, externalPort2));

			SendQueuedOpenNAT();
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
		else if (packet->length>=2 &&
			(packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) &&
			sp.nextActionTime!=0)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(2);
			uint16_t sessionId;
			bs.Read(sessionId);
//			RakAssert(sessionId<100);
			if (sessionId!=sp.sessionId)
				break;

			char ipAddressString[32];
			packet->systemAddress.ToString(true,ipAddressString);
			// sp.targetGuid==packet->guid is because the internal IP addresses reported may include loopbacks not reported by RakPeer::IsLocalIP()
			if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL && sp.targetGuid==packet->guid)
			{
				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString));
				}
				if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT)
				{
					sp.testMode=SendPing::PUNCHING_FIXED_PORT;
					sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL;
					sp.targetAddress=packet->systemAddress;
					// Keeps trying until the other side gives up too, in case it is unidirectional
					sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*(pc.MAX_PREDICTIVE_PORT_RANGE+1);
				}

				SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
			}
			else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL &&
				sp.targetGuid==packet->guid)
			{
				// They send back our port
				unsigned short ourExternalPort;
				bs.Read(ourExternalPort);
				if (nextExternalPort==0)
				{
					nextExternalPort=ourExternalPort;
				}
				else
				{
					if (sp.testMode!=SendPing::TESTING_INTERNAL_IPS && sp.testMode!=SendPing::WAITING_FOR_INTERNAL_IPS_RESPONSE)
					{
						if (hasPortStride!=HAS_PORT_STRIDE)
						{
							portStride = ourExternalPort - nextExternalPort;
							hasPortStride=HAS_PORT_STRIDE;

							if (natPunchthroughDebugInterface)
							{
								natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated port stride from incoming connection at %i", portStride));
							}

							SendQueuedOpenNAT();
						}

						nextExternalPort += portStride * (pc.MAX_PREDICTIVE_PORT_RANGE+1);

						if (natPunchthroughDebugInterface)
						{
							natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated next external port %i", nextExternalPort));
						}
					}
				}
				SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);

				// Tell the user about the success
				sp.targetAddress=packet->systemAddress;
				PushSuccess();
				//UpdateGroupPunchOnNatResult(sp.facilitator, sp.targetGuid, sp.targetAddress, 1);
				OnReadyForNextPunchthrough();
				bool removedFromFailureQueue=RemoveFromFailureQueue();

				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					if (removedFromFailureQueue)
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString));
					else
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString));
				}
			}

	//		mostRecentNewExternalPort=packet->systemAddress.GetPort();
		}
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_ALREADY_IN_PROGRESS:
		{
			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			// Don't update group, just use later message
			// UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2);
			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString));
			}

		}
		break;
	case ID_NAT_TARGET_NOT_CONNECTED:
	case ID_NAT_CONNECTION_TO_TARGET_LOST:
	case ID_NAT_TARGET_UNRESPONSIVE:
		{
			const char *reason;
			if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
				reason=(char *)"ID_NAT_TARGET_NOT_CONNECTED";
			else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
				reason=(char *)"ID_NAT_CONNECTION_TO_TARGET_LOST";
			else
				reason=(char *)"ID_NAT_TARGET_UNRESPONSIVE";


			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));

			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			//UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2);

			if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST ||
				packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
			{
				uint16_t sessionId;
				incomingBs.Read(sessionId);
				if (sessionId!=sp.sessionId)
					break;
			}

			unsigned int i;
			for (i=0; i < failedAttemptList.Size(); i++)
			{
				if (failedAttemptList[i].guid==targetGuid)
				{
					if (natPunchthroughDebugInterface)
					{
						char guidString[128];
						targetGuid.ToString(guidString);
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason));

					}

					// If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried.

					// Don't need to return failed, the other messages indicate failure anyway
					/*
					Packet *p = AllocatePacketUnified(sizeof(MessageID));
					p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED;
					p->systemAddress=failedAttemptList[i].addr;
					p->systemAddress.systemIndex=(SystemIndex)-1;
					p->guid=failedAttemptList[i].guid;
					rakPeerInterface->PushBackPacket(p, false);
					*/

					failedAttemptList.RemoveAtIndexFast(i);
					break;
				}
			}

			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason));
			}

			// Stop trying punchthrough
			sp.nextActionTime=0;

			/*
			RakNet::BitStream bs(packet->data, packet->length, false);
			bs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID failedSystem;
			bs.Read(failedSystem);
			bool deletedFirst=false;
			unsigned int i=0;
			while (i < pendingOpenNAT.Size())
			{
				if (pendingOpenNAT[i].destination==failedSystem)
				{
					if (i==0)
						deletedFirst=true;
					pendingOpenNAT.RemoveAtIndex(i);
				}
				else
					i++;
			}
			// Failed while in progress. Go to next in attempt queue
			if (deletedFirst && pendingOpenNAT.Size())
			{
				SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
				sp.nextActionTime=0;
			}
			*/
		}
		break;
	case ID_TIMESTAMP:
		if (packet->data[sizeof(MessageID)+sizeof(RakNet::Time)]==ID_NAT_CONNECT_AT_TIME)
		{
			OnConnectAtTime(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
		break;
	}
	return RR_CONTINUE_PROCESSING;
}
int main()
{
	FullyConnectedMesh2 fcm2;
	ConnectionGraph2 cg2;
	rakPeer=RakNet::RakPeerInterface::GetInstance();
	rakPeer->AttachPlugin(&fcm2);
	rakPeer->AttachPlugin(&cg2);
	fcm2.SetAutoparticipateConnections(true);
	RakNet::SocketDescriptor sd;
	sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255
	sd.port=60000;
	while (IRNS2_Berkley::IsPortInUse(sd.port, sd.hostAddress, sd.socketFamily, SOCK_DGRAM)==true)
		sd.port++;
	StartupResult sr = rakPeer->Startup(8,&sd,1);
	RakAssert(sr==RAKNET_STARTED);
	rakPeer->SetMaximumIncomingConnections(8);
	rakPeer->SetTimeoutTime(1000,RakNet::UNASSIGNED_SYSTEM_ADDRESS);
	printf("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
	printf("Started on %s\n", rakPeer->GetMyBoundAddress().ToString(true));
	BitStream contextBs;
	contextBs.Write(RakString("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString()));
	fcm2.SetMyContext(&contextBs);

//	PacketLogger packetLogger;
//	rakPeer->AttachPlugin(&packetLogger);
//	packetLogger.SetLogDirectMessages(false);

	bool quit=false;
	RakNet::Packet *packet;
	char ch;
	while (!quit)
	{
		for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
		{
			switch (packet->data[0])
			{
			case ID_DISCONNECTION_NOTIFICATION:
				// Connection lost normally
				printf("ID_DISCONNECTION_NOTIFICATION\n");
				break;


			case ID_NEW_INCOMING_CONNECTION:
				// Somebody connected.  We have their IP now
				printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString());
				break;

			case ID_CONNECTION_REQUEST_ACCEPTED:
				// Somebody connected.  We have their IP now
				printf("ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString());
				break;


			case ID_CONNECTION_LOST:
				// Couldn't deliver a reliable packet - i.e. the other system was abnormally
				// terminated
				printf("ID_CONNECTION_LOST\n");
				break;

			case ID_ADVERTISE_SYSTEM:
				if (packet->guid!=rakPeer->GetMyGUID())
					rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0);
				break;

			case ID_FCM2_NEW_HOST:
				{
				if (packet->guid==rakPeer->GetMyGUID())
					printf("Got new host (ourselves)");
				else
					printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
					RakNet::BitStream bs(packet->data,packet->length,false);
					bs.IgnoreBytes(1);
					RakNetGUID oldHost;
					bs.Read(oldHost);
					// If oldHost is different then the current host, then we lost connection to the host
					if (oldHost!=UNASSIGNED_RAKNET_GUID)
						printf(". Oldhost Guid=%s\n", oldHost.ToString());
					else
						printf(". (First reported host)\n");
				}
				break;

// 			case ID_REMOTE_NEW_INCOMING_CONNECTION:
// 				{
// 					uint32_t count;
// 					RakNet::BitStream bsIn(packet->data, packet->length,false);
// 					bsIn.IgnoreBytes(1);
// 					bsIn.Read(count);
// 					SystemAddress sa;
// 					RakNetGUID guid;
// 					printf("ID_REMOTE_NEW_INCOMING_CONNECTION from %s\n", packet->systemAddress.ToString(true));
// 					for (uint32_t i=0; i < count; i++)
// 					{
// 						bsIn.Read(sa);
// 						bsIn.Read(guid);
// 
// 						printf("%s ", sa.ToString(true));
// 					}
// 					printf("\n");
// 				}
			}
		}

		if (kbhit())
		{
			ch=getch();
			if (ch==' ')
			{

				DataStructures::List<RakNetGUID> participantList;
				fcm2.GetParticipantList(participantList);
				printf("%i participants\n", participantList.Size());
				for (int i=0; i < participantList.Size(); i++)
				{
					BitStream userContext;
					fcm2.GetParticipantContext(participantList[i], &userContext);
					RakString str;
					userContext.Read(str);
					printf("%i. %s: %s", i+1, participantList[i].ToString(), str.C_String());
				}
			}
			if (ch=='q' || ch=='Q')
			{
				printf("Quitting.\n");
				quit=true;
			}
		}

		RakSleep(30);
		for (int i=0; i < 32; i++)
		{
			if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=60000+i)
				rakPeer->AdvertiseSystem("255.255.255.255", 60000+i, 0,0,0);
		}
	}

	RakNet::RakPeerInterface::DestroyInstance(rakPeer);
	return 0;
}
int main(void)
{
    printf("This project demonstrates an in-game lobby using the team manager plugin.\n");
    printf("Difficulty: Intermediate\n\n");

    rakPeer=RakNet::RakPeerInterface::GetInstance();
    fullyConnectedMesh2=FullyConnectedMesh2::GetInstance();
    teamManager=TeamManager::GetInstance();
    networkIDManager = NetworkIDManager::GetInstance();
    replicaManager3=new SampleRM3;

    // test offline mode
    /*
    TM_TeamMember tmTeamMember;
    TM_Team tmTeam;
    teamManager->AddWorld(0);
    teamManager->GetWorldAtIndex(0)->ReferenceTeam(&tmTeam,1,false);
    teamManager->GetWorldAtIndex(0)->ReferenceTeamMember(&tmTeamMember,0);
    tmTeamMember.RequestTeam(TeamSelection::AnyAvailable());
    RakAssert(tmTeam.GetTeamMembersCount()==1);
    tmTeam.LeaveTeam(&tmTeamMember, 255);
    RakAssert(tmTeam.GetTeamMembersCount()==0);
    */

    rakPeer->AttachPlugin(fullyConnectedMesh2);
    rakPeer->AttachPlugin(teamManager);
    rakPeer->AttachPlugin(replicaManager3);
    rakPeer->AttachPlugin(fullyConnectedMesh2);

    // Make it so all new connections are registered with FullyConnectedMesh2
    fullyConnectedMesh2->SetAutoparticipateConnections(true);
    // Allocate a world instance to be used for team operations
    teamManager->AddWorld(0);
    // Tell ReplicaManager3 which networkIDManager to use for object lookup, used for automatic serialization
    replicaManager3->SetNetworkIDManager(networkIDManager);
    // Tell ReplicaManager3 and TeamManager to not automatically add new connections, because we wait for host calculation to complete from FullyConnectedMesh2 first
    replicaManager3->SetAutoManageConnections(false,true);
    teamManager->SetAutoManageConnections(false);

    // Just setup user data as an example
    Team teams[TEAM_TYPES_COUNT];
    teams[(int)PLAYER_TEAM_1].teamName="Player_Team_1";
    teams[(int)PLAYER_TEAM_2].teamName="Player_Team 2";
    teams[(int)REFEREE_TEAM].teamName="Referee_Team";

    for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++)
    {
        // Static objects require additional setup before calling reference.
        teams[i].SetNetworkIDManager(networkIDManager);
        teams[i].SetNetworkID(i); // NetworkID value doesn't matter, just needs to be unique
        // We serialize teams before team members, this is required by TeamManager during remote object construction. Serialization occurs in the order that Reference() is called on the object
        replicaManager3->Reference(&teams[i]);

        // Register the team with the teamManager plugin
        // Do not apply team balancing to the referee team
        bool balancingAppliesToThisTeam = i!=REFEREE_TEAM;
        teamManager->GetWorldAtIndex(0)->ReferenceTeam(&teams[i].tmTeam,teams[i].GetNetworkID(),balancingAppliesToThisTeam);
        if (i==REFEREE_TEAM)
            teams[i].tmTeam.SetMemberLimit(1,0);
        else
            teams[i].tmTeam.SetMemberLimit(2,0);
    }

    // Only join the referee team on specific request
    teams[REFEREE_TEAM].tmTeam.SetJoinPermissions(ALLOW_JOIN_SPECIFIC_TEAM);

    // Setup my own
    User *user = new User;
    user->userName = rakPeer->GetMyGUID().ToString();

    // Inform ReplicaManager3 of my user
    replicaManager3->Reference(user);
    // Inform TeamManager of my user's team member info
    teamManager->GetWorldAtIndex(0)->ReferenceTeamMember(&user->tmTeamMember,user->GetNetworkID());

    // Startup RakNet
    RakNet::SocketDescriptor sd;
    sd.socketFamily=AF_INET; // Only IPV4 supports broadcast on 255.255.255.255
    sd.port=60000;
    while (SocketLayer::IsPortInUse(sd.port, sd.hostAddress, sd.socketFamily)==true)
        sd.port++;
    StartupResult sr = rakPeer->Startup(8,&sd,1);
    RakAssert(sr==RAKNET_STARTED);
    rakPeer->SetMaximumIncomingConnections(8);
    rakPeer->SetTimeoutTime(30000,RakNet::UNASSIGNED_SYSTEM_ADDRESS);
    printf("Our guid is %s\n", rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS).ToString());
    printf("Started on %s\n", rakPeer->GetMyBoundAddress().ToString(true));

    for (int i=0; i < 32; i++)
    {
        if (rakPeer->GetInternalID(RakNet::UNASSIGNED_SYSTEM_ADDRESS,0).GetPort()!=60000+i)
            rakPeer->AdvertiseSystem("255.255.255.255", 60000+i, 0,0,0);
    }

    PrintCommands();

    bool success;
    bool quit=false;
    char ch;
    Packet *packet;
    while (!quit)
    {
        for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet = rakPeer->Receive())
        {
            switch (packet->data[0])
            {
            case ID_DISCONNECTION_NOTIFICATION:
                printf("ID_DISCONNECTION_NOTIFICATION\n");
                break;
            case ID_NEW_INCOMING_CONNECTION:
            {
                printf("ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString());
                // Add mid-game joins to ReplicaManager3 as long as we know who the host is
                if (fullyConnectedMesh2->GetConnectedHost()!=UNASSIGNED_RAKNET_GUID)
                {
                    bool success = replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid));
                    RakAssert(success);
                    teamManager->GetWorldAtIndex(0)->AddParticipant(packet->guid);
                }
            }
            break;
            case ID_CONNECTION_REQUEST_ACCEPTED:
            {
                printf("ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", packet->systemAddress.ToString(true), packet->guid.ToString());
                // Add mid-game joins to ReplicaManager3 as long as we know who the host is
                if (fullyConnectedMesh2->GetConnectedHost()!=UNASSIGNED_RAKNET_GUID)
                {
                    bool success = replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid));
                    RakAssert(success);
                    teamManager->GetWorldAtIndex(0)->AddParticipant(packet->guid);
                }
            }
            break;
            case ID_CONNECTION_LOST:
                printf("ID_CONNECTION_LOST\n");
                break;
            case ID_ADVERTISE_SYSTEM:
                if (packet->guid!=rakPeer->GetMyGUID())
                    rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(),0,0);
                break;
            case ID_FCM2_NEW_HOST:
            {
                if (packet->guid==rakPeer->GetMyGUID())
                    printf("Got new host (ourselves)");
                else
                    printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
                RakNet::BitStream bs(packet->data,packet->length,false);
                bs.IgnoreBytes(1);
                RakNetGUID oldHost;
                bs.Read(oldHost);
                // If the old host is different, then this message was due to losing connection to the host.
                if (oldHost!=packet->guid)
                    printf(". Oldhost Guid=%s\n", oldHost.ToString());
                else
                    printf("\n");

                if (oldHost==UNASSIGNED_RAKNET_GUID)
                {
                    // First time calculated host. Add existing connections to ReplicaManager3
                    RegisterFCM2Participants();
                }
            }
            break;
            case ID_TEAM_BALANCER_TEAM_ASSIGNED:
            {
                printf("ID_TEAM_BALANCER_TEAM_ASSIGNED for ");
                TM_World *world;
                TM_TeamMember *teamMember;
                teamManager->DecodeTeamAssigned(packet, &world, &teamMember);
                printf("worldId=%i teamMember=%s\n", world->GetWorldId(), ((User*)teamMember->GetOwner())->userName.C_String());
            }
            break;
            case ID_TEAM_BALANCER_REQUESTED_TEAM_FULL:
            {
                printf("ID_TEAM_BALANCER_REQUESTED_TEAM_FULL\n");
            }
            break;
            case ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED:
            {
                printf("ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED\n");
            }
            break;
            case ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED:
            {
                printf("ID_TEAM_BALANCER_TEAM_REQUESTED_CANCELLED\n");
            }
            break;
            }
        }

        if (kbhit())
        {
            ch=getch();

            if (ch=='A' || ch=='a')
            {
                printf("Request any team\n");
                success = user->tmTeamMember.RequestTeam(TeamSelection::AnyAvailable());
                printf("Success=%i\n", success);
            }
            if (ch=='B' || ch=='b')
            {
                printf("Request specific team\n");
                char buff1[256];
                printf("Enter team index (0-2): ");
                gets(buff1);
                if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2')
                {
                    success = user->tmTeamMember.RequestTeam(TeamSelection::SpecificTeam(&(teams[buff1[0]-'0'].tmTeam)));
                    printf("Success=%i\n", success);
                }
                else
                {
                    printf("Aborted\n");
                }
            }
            if (ch=='C' || ch=='c')
            {
                printf("Request team switch\n");
                char buff1[256];
                printf("Enter team index to join (0-2): ");
                gets(buff1);
                char buff2[256];
                printf("Enter team index to leave (0-2) or leave empty for all: ");
                gets(buff2);
                if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2' &&
                        (buff2[0]==0 || (buff2[0]>='0' && buff2[0]<='2')))
                {
                    if (buff2[0])
                        success = user->tmTeamMember.RequestTeamSwitch(&(teams[buff1[0]-'0'].tmTeam), &teams[buff2[0]-'0'].tmTeam);
                    else
                        success = user->tmTeamMember.RequestTeamSwitch(&(teams[buff1[0]-'0'].tmTeam), 0);
                    printf("Success=%i\n", success);
                }
                else
                {
                    printf("Aborted\n");
                }
            }
            if (ch=='D' || ch=='d')
            {
                printf("Cancel request team\n");
                char buff1[256];
                printf("Enter team index to cancel (0-2) or leave empty for all: ");
                gets(buff1);
                if ((buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2') || buff1[0]==0)
                {
                    if (buff1[0])
                        success = user->tmTeamMember.CancelTeamRequest(&(teams[buff1[0]-'0'].tmTeam));
                    else
                        success = user->tmTeamMember.CancelTeamRequest(0);
                    printf("Success=%i\n", success);
                }
                else
                {
                    printf("Aborted\n");
                }
            }
            if (ch=='E' || ch=='e')
            {
                printf("Leave specific team\n");
                char buff1[256];
                printf("Enter team index to leave (0-2): ");
                gets(buff1);
                if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2')
                {
                    success = user->tmTeamMember.LeaveTeam(&(teams[buff1[0]-'0'].tmTeam),0);
                    printf("Success=%i\n", success);
                }
                else
                {
                    printf("Aborted\n");
                }

            }
            if (ch=='F' || ch=='f')
            {
                printf("Leave all teams\n");
                success = user->tmTeamMember.LeaveAllTeams(0);
                printf("Success=%i\n", success);

            }
            if (ch=='G' || ch=='g')
            {
                printf("Set team member limit\n");
                char buff1[256];
                printf("Enter team index to operate on (0-2): ");
                gets(buff1);
                char buff2[256];
                printf("Enter limit (0-9): ");
                gets(buff2);
                if (buff1[0]!=0 && buff1[0]>='0' && buff1[0]<='2' &&
                        buff2[0]!=0 && buff2[0]>='0' && buff2[0]<='9')
                {
                    success = teams[buff1[0]-'0'].tmTeam.SetMemberLimit(buff2[0]-'0',0);
                    printf("Success=%i\n", success);
                }
                else
                {
                    printf("Aborted\n");
                }
            }
            if (ch=='H' || ch=='h')
            {
                printf("Turn on balance teams setting\n");
                success = teamManager->GetWorldAtIndex(0)->SetBalanceTeams(true,0);
                printf("Success=%i\n", success);
            }
            if (ch=='I' || ch=='i')
            {
                printf("Turn off balance teams setting\n");
                success = teamManager->GetWorldAtIndex(0)->SetBalanceTeams(false,0);
                printf("Success=%i\n", success);
            }

            if (ch==' ')
            {
                if (teamManager->GetWorldAtIndex(0)->GetBalanceTeams())
                    printf("Team balancing is on\n");
                else
                    printf("Team balancing is off\n");

                for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++)
                {
                    printf("Team %i. %s %i/%i members ", i+1, teams[i].teamName.C_String(), teams[i].tmTeam.GetTeamMembersCount(), teams[i].tmTeam.GetMemberLimit());
                    for (unsigned int j=0; j < teams[i].tmTeam.GetTeamMembersCount(); j++)
                    {
                        User *u = (User *) teams[i].tmTeam.GetTeamMemberByIndex(j)->GetOwner();
                        printf("%s ", u->userName.C_String());
                    }
                    printf("\n");
                }

                unsigned int numUsers = teamManager->GetWorldAtIndex(0)->GetTeamMemberCount();
                for (unsigned int i=0; i < numUsers; i++)
                {
                    User *u = (User *) teamManager->GetWorldAtIndex(0)->GetTeamMemberByIndex(i)->GetOwner();
                    printf("User %i/%i. %s ", i+1, numUsers, u->userName.C_String());
                    u->PrintTeamStatus();
                    printf("\n");
                }
                printf("\n");
            }
            else if (ch=='q' || ch=='Q')
            {
                printf("Quitting.\n");
                quit=true;
            }
        }

        RakSleep(30);
    }

    rakPeer->Shutdown(100);
    replicaManager3->Clear();
    RakNet::RakPeerInterface::DestroyInstance(rakPeer);
    delete replicaManager3;
    RakNet::FullyConnectedMesh2::DestroyInstance(fullyConnectedMesh2);
    RakNet::TeamManager::DestroyInstance(teamManager);
    RakNet::NetworkIDManager::DestroyInstance(networkIDManager);

    for (unsigned int i=0; i < TEAM_TYPES_COUNT; i++)
    {
        // Teams are globally deallocated after NetworkIDManager, so prevent crash on automatic dereference
        teams[i].SetNetworkIDManager(0);
    }

    return 1;
}
int main()
{
	FullyConnectedMesh2 fcm2[NUM_PEERS];
	ConnectionGraph2 cg2[NUM_PEERS];

	for (int i=0; i < NUM_PEERS; i++)
	{
		rakPeer[i]=RakNetworkFactory::GetRakPeerInterface();
		rakPeer[i]->AttachPlugin(&fcm2[i]);
		rakPeer[i]->AttachPlugin(&cg2[i]);
		fcm2[i].SetAutoparticipateConnections(true);
		SocketDescriptor sd;
		sd.port=60000+i;
		rakPeer[i]->Startup(NUM_PEERS,0,&sd,1);
		rakPeer[i]->SetMaximumIncomingConnections(NUM_PEERS);
		rakPeer[i]->SetTimeoutTime(1000,UNASSIGNED_SYSTEM_ADDRESS);
		printf("Our guid is %s\n", rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString());
	}

	for (int i=0; i < NUM_PEERS; i++)
	{
		for (int j=0; j < NUM_PEERS; j++)
		{
			if (i==j)
				continue;
			rakPeer[i]->Connect("127.0.0.1", 60000+j, 0, 0 );
		}
	}

	bool quit=false;
	Packet *packet;
	char ch;
	while (!quit)
	{
		for (int i=0; i < NUM_PEERS; i++)
		{
			for (packet = rakPeer[i]->Receive(); packet; rakPeer[i]->DeallocatePacket(packet), packet = rakPeer[i]->Receive())
			{
				switch (packet->data[0])
				{
				case ID_DISCONNECTION_NOTIFICATION:
					// Connection lost normally
					printf("%i. ID_DISCONNECTION_NOTIFICATION\n", i);
					break;


				case ID_NEW_INCOMING_CONNECTION:
					// Somebody connected.  We have their IP now
					printf("%i. ID_NEW_INCOMING_CONNECTION from %s. guid=%s.\n", i, packet->systemAddress.ToString(true), packet->guid.ToString());
					break;

				case ID_CONNECTION_REQUEST_ACCEPTED:
					// Somebody connected.  We have their IP now
					printf("%i. ID_CONNECTION_REQUEST_ACCEPTED from %s. guid=%s.\n", i, packet->systemAddress.ToString(true), packet->guid.ToString());
					break;


				case ID_CONNECTION_LOST:
					// Couldn't deliver a reliable packet - i.e. the other system was abnormally
					// terminated
					printf("%i. ID_CONNECTION_LOST\n", i);
					break;


				case ID_FCM2_NEW_HOST:
					if (packet->systemAddress==UNASSIGNED_SYSTEM_ADDRESS)
						printf("%i. Got new host (ourselves)\n", i);
					else
						printf("%i. Got new host %s\n", i, packet->systemAddress.ToString(true));
					break;
				}
			}
		}

		if (kbhit())
		{
			ch=getch();
			if (ch==' ')
			{
				DataStructures::DefaultIndexType participantList;
				RakNetGUID hostGuid;
				bool weAreHost;
				for (int i=0; i < NUM_PEERS; i++)
				{
					if (rakPeer[i]->IsActive()==false)
						continue;

					fcm2[i].GetParticipantCount(&participantList);
					weAreHost=fcm2[i].IsHostSystem();
					hostGuid=fcm2[i].GetHostSystem();
					if (weAreHost)
						printf("%i. %iP myGuid=%s, hostGuid=%s (Y)\n",i, participantList, rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString(), hostGuid.ToString());
					else
						printf("%i. %iP myGuid=%s, hostGuid=%s (N)\n",i, participantList, rakPeer[i]->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString(), hostGuid.ToString());
				}
			}
			if (ch=='d' || ch=='D')
			{
				char str[32];
				printf("Enter system index to disconnect.\n");
				gets(str);
				rakPeer[atoi(str)]->Shutdown(100);
				printf("Done.\n");
			}
			if (ch=='q' || ch=='Q')
			{
				printf("Quitting.\n");
				quit=true;
			}
		}


		RakSleep(30);
	}

	for (int i=0; i < NUM_PEERS; i++)
	{
		RakNetworkFactory::DestroyRakPeerInterface(rakPeer[i]);
	}
	return 0;
}
Beispiel #9
0
int main(int argc, char **argv)
{
	if (argc>1)
	{
		printf("Command arguments:\n");
		for (int i=1; i < argc; i++)
		{
			printf("%i. %s\n", i, argv[i]);
		}
	}

	SteamResults steamResults;
	rakPeer = RakNet::RakPeerInterface::GetInstance();
	fcm2 = RakNet::FullyConnectedMesh2::GetInstance();
	messageFactory = new Lobby2MessageFactory_Steam;
	lobby2Client = Lobby2Client_Steam::GetInstance();
	lobby2Client->AddCallbackInterface(&steamResults);
	lobby2Client->SetMessageFactory(messageFactory);
	SocketDescriptor sd(1234,0);
	rakPeer->Startup(32,&sd,1);
	rakPeer->SetMaximumIncomingConnections(32);
	rakPeer->AttachPlugin(fcm2);
	rakPeer->AttachPlugin(lobby2Client);
	// Connect manually in Notification_Console_MemberJoinedRoom
	fcm2->SetConnectOnNewRemoteConnection(false, "");
	RakNet::Lobby2Message* msg = messageFactory->Alloc(RakNet::L2MID_Client_Login);
	lobby2Client->SendMsg(msg);
	if (msg->resultCode!=L2RC_PROCESSING && msg->resultCode!=L2RC_SUCCESS)
	{
		printf("Steam must be running to play this game (SteamAPI_Init() failed).\n");
		printf("If this fails, steam_appid.txt was probably not in the working directory.\n");
		messageFactory->Dealloc(msg);
		return -1;
	}
	messageFactory->Dealloc(msg);
	
	PrintCommands();

	bool quit=false;
	char ch;
	while(!quit)
	{
		RakNet::Packet *packet;
		for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive())
		{
			switch (packet->data[0])
			{
			case ID_DISCONNECTION_NOTIFICATION:
				// Connection lost normally
				printf("ID_DISCONNECTION_NOTIFICATION\n");
				break;
			case ID_ALREADY_CONNECTED:
				// Connection lost normally
				printf("ID_ALREADY_CONNECTED\n");
				break;
			case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully.  You can manually broadcast this in a peer to peer enviroment if you want.
				printf("ID_REMOTE_DISCONNECTION_NOTIFICATION\n");
				break;
			case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully.  You can manually broadcast this in a peer to peer enviroment if you want.
				printf("ID_REMOTE_CONNECTION_LOST\n");
				break;
			case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting.  You can manually broadcast this in a peer to peer enviroment if you want.
				printf("ID_REMOTE_NEW_INCOMING_CONNECTION\n");
				break;
			case ID_CONNECTION_BANNED: // Banned from this server
				printf("We are banned from this server.\n");
				break;			
			case ID_CONNECTION_ATTEMPT_FAILED:
				printf("Connection attempt failed\n");
				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				// Sorry, the server is full.  I don't do anything here but
				// A real app should tell the user
				printf("ID_NO_FREE_INCOMING_CONNECTIONS\n");
				break;
			case ID_INVALID_PASSWORD:
				printf("ID_INVALID_PASSWORD\n");
				break;

			case ID_CONNECTION_LOST:
				// Couldn't deliver a reliable packet - i.e. the other system was abnormally
				// terminated
				printf("ID_CONNECTION_LOST\n");
				break;

			case ID_CONNECTION_REQUEST_ACCEPTED:
				// This tells the client they have connected
				printf("ID_CONNECTION_REQUEST_ACCEPTED to %s with GUID %s\n", packet->systemAddress.ToString(), packet->guid.ToString());
				break;

			case ID_NEW_INCOMING_CONNECTION:
				printf("ID_NEW_INCOMING_CONNECTION\n");
				break;

			case ID_FCM2_NEW_HOST:
				{
					if (packet->systemAddress==RakNet::UNASSIGNED_SYSTEM_ADDRESS)
						printf("Got new host (ourselves)");
					else
						printf("Got new host %s, GUID=%s", packet->systemAddress.ToString(true), packet->guid.ToString());
					RakNet::BitStream bs(packet->data,packet->length,false);
					bs.IgnoreBytes(1);
					RakNetGUID oldHost;
					bs.Read(oldHost);
					// If the old host is different, then this message was due to losing connection to the host.
					if (oldHost!=packet->guid)
						printf(". Oldhost Guid=%s\n", oldHost.ToString());
					else
						printf("\n");
				}
				break;

			default:
				// It's a client, so just show the message
				printf("Unknown Message ID %i\n", packet->data[0]);
				break;
			}

		}
		if (kbhit())
		{
			ch=(char)getch();

			switch (ch)
			{
			case 'a':
				{

					RakNet::Lobby2Message* logoffMsg = messageFactory->Alloc(RakNet::L2MID_Console_SearchRooms);
					lobby2Client->SendMsg(logoffMsg);
					messageFactory->Dealloc(logoffMsg);
				}
				break;

			case 'b':
				{
					if (lobby2Client->GetRoomID()==0)
					{
						printf("Not in a room\n");
						break;
					}
					RakNet::Console_LeaveRoom_Steam* msg = (RakNet::Console_LeaveRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_LeaveRoom);
					msg->roomId=lobby2Client->GetRoomID();
					lobby2Client->SendMsg(msg);
					messageFactory->Dealloc(msg);
				}
				break;

			case 'c':
				{
					if (lobby2Client->GetRoomID()!=0)
					{
						printf("Already in a room\n");
						break;
					}

					RakNet::Console_CreateRoom_Steam* msg = (RakNet::Console_CreateRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_CreateRoom);
					// set the name of the lobby if it's ours
					char rgchLobbyName[256];
					msg->roomIsPublic=true;
					_snprintf( rgchLobbyName, sizeof( rgchLobbyName ), "%s's lobby", SteamFriends()->GetPersonaName() );
					msg->roomName=rgchLobbyName;
					msg->publicSlots=8;
					lobby2Client->SendMsg(msg);
					messageFactory->Dealloc(msg);

				}
				break;

			case 'd':
				{
					if (lobby2Client->GetRoomID()!=0)
					{
						printf("Already in a room\n");
						break;
					}

					RakNet::Console_JoinRoom_Steam* msg = (RakNet::Console_JoinRoom_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_JoinRoom);
					printf("Enter room id, or enter for %" PRINTF_64_BIT_MODIFIER "u: ", lastRoom);
					char str[256];
					Gets(str, sizeof(str));
					if (str[0]==0)
					{
						msg->roomId=lastRoom;
					}
					else
					{
						msg->roomId=_atoi64(str);
					}
					lobby2Client->SendMsg(msg);
					messageFactory->Dealloc(msg);
				}
				break;

			case 'e':
				{
					if (lobby2Client->GetRoomID()==0)
					{
						printf("Not in a room\n");
						break;
					}

					RakNet::Console_GetRoomDetails_Steam* msg = (RakNet::Console_GetRoomDetails_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_GetRoomDetails);
					msg->roomId=lobby2Client->GetRoomID();
					lobby2Client->SendMsg(msg);
					messageFactory->Dealloc(msg);
				}
				break;

			case 'f':
				{
					if (lobby2Client->GetRoomID()==0)
					{
						printf("Not in a room\n");
						break;

					}
					RakNet::Console_SendRoomChatMessage_Steam* msg = (RakNet::Console_SendRoomChatMessage_Steam*) messageFactory->Alloc(RakNet::L2MID_Console_SendRoomChatMessage);
					msg->message="Test chat message.";
					msg->roomId=lobby2Client->GetRoomID();
					lobby2Client->SendMsg(msg);
					messageFactory->Dealloc(msg);

				}
				break;

			case 'g':
				{
					DataStructures::OrderedList<uint64_t, uint64_t> roomMembers;
					lobby2Client->GetRoomMembers(roomMembers);
					for (unsigned int i=0; i < roomMembers.Size(); i++)
					{
						printf("%i. %s ID=%" PRINTF_64_BIT_MODIFIER "u\n", i+1, lobby2Client->GetRoomMemberName(roomMembers[i]), roomMembers[i]);
					}
				}
				break;


			case '?':
				{
					PrintCommands();

				}
				break;

			case 27:
				{
					quit=true;
				}
				break;
			}
		}

		RakSleep(30);
	}
	
	RakNet::Lobby2Message* logoffMsg = messageFactory->Alloc(RakNet::L2MID_Client_Logoff);
	lobby2Client->SendMsg(logoffMsg);
	messageFactory->Dealloc(logoffMsg);
	rakPeer->DetachPlugin(lobby2Client);
	rakPeer->DetachPlugin(fcm2);
	RakNet::RakPeerInterface::DestroyInstance(rakPeer);
	Lobby2Client_Steam::DestroyInstance(lobby2Client);
	RakNet::FullyConnectedMesh2::DestroyInstance(fcm2);

	return 1;
}
Beispiel #10
0
void ReadAllPackets(void)
{
	char str[64], str2[64];
	Packet *packet;
	for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive())
	{
		packet->guid.ToString(str);
		packet->systemAddress.ToString(true,str2);
		if (packet->data[0]==ID_NEW_INCOMING_CONNECTION)
		{
			printf("ID_NEW_INCOMING_CONNECTION from %s on %s\n", str, str2);
		}
		else if (packet->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
		{
			printf("ID_CONNECTION_REQUEST_ACCEPTED from %s on %s\n", str, str2);
		}
		else if (packet->data[0]==ID_ROUTER_2_FORWARDING_NO_PATH)
		{
			printf("No path to endpoint exists. Routing failed.\n");
		}
		else if (packet->data[0]==ID_CONNECTION_LOST)
		{
			printf("ID_CONNECTION_LOST from %s\n", str);
		}
		else if (packet->data[0]==ID_USER_PACKET_ENUM+1)
		{
			printf("Got ID_USER_PACKET_ENUM from %s\n", str);
		}
		else if (packet->data[0]==ID_ROUTER_2_FORWARDING_ESTABLISHED)
		{
			RakNet::BitStream bs(packet->data, packet->length, false);
			bs.IgnoreBytes(sizeof(MessageID));
			bs.Read(endpointGuid);
			printf("Routing through %s to %s successful. Connecting.\n", str, endpointGuid.ToString());
			unsigned short sourceToDestPort;
			bs.Read(sourceToDestPort);
			char ipAddressString[32];
			packet->systemAddress.ToString(false, ipAddressString);
			rakPeer->Connect(ipAddressString, sourceToDestPort, 0,0);
		}
		else if (packet->data[0]==ID_ROUTER_2_REROUTED)
		{
			// You could read the endpointGuid and sourceToDestPoint if you wanted to
			RakNet::BitStream bs(packet->data, packet->length, false);
			bs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID endpointGuid2;
			bs.Read(endpointGuid2);
			endpointGuid2.ToString(str);
			unsigned short sourceToDestPort;
			SystemAddress intermediateAddress=packet->systemAddress;
			bs.Read(intermediateAddress.port);

			char str2[32];
			intermediateAddress.ToString(true, str2);
			printf("Connection to %s rerouted through %s\n", str, str2);

			// Test sending a message to the endpoint
			RakNet::BitStream bsOut;
			MessageID id = ID_USER_PACKET_ENUM+1;
			bsOut.Write(id);
			rakPeer->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,endpointGuid2,false);
		}
	}
}
Beispiel #11
0
int main(void)
{
	PortAudioStream *stream;
	PaError    err;
	mute=false;

	bool quit;
	char ch;

	printf("A sample on how to use RakVoice. You need a microphone for this sample.\n");
	printf("RakVoice relies on Speex for voice encoding and decoding.\n");
	printf("See DependentExtensions/RakVoice/speex-1.1.12 for speex projects.\n");
	printf("For windows, I had to define HAVE_CONFIG_H, include win32/config.h,\n");
	printf("and include the files under libspeex, except those that start with test.\n");
	printf("PortAudio is also included and is used to read and write audio data.  You\n");
	printf("can substitute whatever you want if you do not want to use portaudio.\n");
	printf("Difficulty: Advanced\n\n");

	// Since voice is peer to peer, we give the option to use the nat punchthrough client if desired.
	NatPunchthroughClient natPunchthroughClient;
	char port[256];
	rakPeer = RakNetworkFactory::GetRakPeerInterface();
	printf("Enter local port (enter for default): ");
	gets(port);
	if (port[0]==0)
		strcpy(port, "60000");
	SocketDescriptor socketDescriptor(atoi(port),0);
	rakPeer->Startup(4, 30, &socketDescriptor, 1);
	rakPeer->SetMaximumIncomingConnections(4);
	rakPeer->AttachPlugin(&rakVoice);
	rakPeer->AttachPlugin(&natPunchthroughClient);
	rakVoice.Init(SAMPLE_RATE, FRAMES_PER_BUFFER*sizeof(SAMPLE));

	err = Pa_Initialize();
	if( err != paNoError ) goto error;
	
	err = Pa_OpenStream(
		&stream,
		Pa_GetDefaultInputDeviceID(),
		1, // Num channels, whatever that means
		PA_SAMPLE_TYPE,
		NULL,
		Pa_GetDefaultOutputDeviceID(),
		1, // Num channels
		PA_SAMPLE_TYPE,
		NULL,
		SAMPLE_RATE,
		FRAMES_PER_BUFFER,            /* frames per buffer */
		0,               /* number of buffers, if zero then use default minimum */
		0, /* paDitherOff, // flags */
		PACallback,
		0 );

	if( err != paNoError ) goto error;

	err = Pa_StartStream( stream );
	if( err != paNoError ) goto error;

	printf("Support NAT punchthrough? (y/n)? ");
	bool useNatPunchthrough;
	useNatPunchthrough=(getche()=='y');
	printf("\n");
	char facilitatorIP[256];
	{//Linux fix. Won't compile without it. Because of the goto error above, the scope is ambigious. Make it a block to define that it will not be used after the jump.
	//Doesn't change current logic
	SystemAddress facilitator;
	if (useNatPunchthrough)
	{
		printf("My GUID is %s\n", rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString());

		printf("Enter IP of facilitator (enter for default): ");
		gets(facilitatorIP);
		if (facilitatorIP[0]==0)
			strcpy(facilitatorIP, "94.198.81.195");
		facilitator.SetBinaryAddress(facilitatorIP);
		facilitator.port=NAT_PUNCHTHROUGH_FACILITATOR_PORT;
		rakPeer->Connect(facilitatorIP, NAT_PUNCHTHROUGH_FACILITATOR_PORT, 0, 0);
		printf("Connecting to facilitator...\n");
	}
	else
	{
		printf("Not supporting NAT punchthrough.\n");
	}


    
	Packet *p;
	quit=false;
	if (useNatPunchthrough==false)
		printf("(Q)uit. (C)onnect. (D)isconnect. C(l)ose voice channels. (M)ute. ' ' for stats.\n");

	while (!quit)
	{
		if (kbhit())
		{
			ch=getch();
			if (ch=='y')
			{
				quit=true;
			}
			else if (ch=='c')
			{
				if (useNatPunchthrough)
				{
					RakNetGUID destination;
					printf("Enter GUID of destination: ");
					char guidStr[256];
					while (1)
					{
						gets(guidStr);
						if (!destination.FromString(guidStr))
							printf("Invalid GUID format. Try again.\nEnter GUID of destination: ");
						else
							break;
					}
					printf("Starting NAT punch. Please wait...\n");
					natPunchthroughClient.OpenNAT(destination,facilitator);
				}
				else
				{
					char ip[256];
					printf("Enter IP of remote system: ");
					gets(ip);
					if (ip[0]==0)
						strcpy(ip, "127.0.0.1");
					printf("Enter port of remote system: ");
					gets(port);
					if (port[0]==0)
						strcpy(port, "60000");
					rakPeer->Connect(ip, atoi(port), 0,0);

				}
			}
			else if (ch=='m')
			{
				mute=!mute;
				if (mute)
					printf("Now muted.\n");
				else
					printf("No longer muted.\n");
			}
			else if (ch=='d')
			{
				rakPeer->Shutdown(100,0);
			}
			else if (ch=='l')
			{
				rakVoice.CloseAllChannels();
			}
			else if (ch==' ')
			{
				char message[2048];
				RakNetStatistics *rss=rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0));
				StatisticsToString(rss, message, 2);
				printf("%s", message);
			}
			else if (ch=='q')
				quit=true;
			ch=0;
		}

		p=rakPeer->Receive();
		while (p)
		{
			if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
			{
				if (p->systemAddress==facilitator)
				{
					printf("Connection to facilitator completed\n");
					printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n");
				}
				else
				{
					printf("ID_CONNECTION_REQUEST_ACCEPTED from %s\n", p->systemAddress.ToString());
					rakVoice.RequestVoiceChannel(p->guid);
				}
			}
			else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED)
			{
				if (p->systemAddress==facilitator)
				{
					printf("Connection to facilitator failed. Using direct connections\n");
					useNatPunchthrough=false;
					printf("(Q)uit. (C)onnect. (D)isconnect. (M)ute. ' ' for stats.\n");
				}
				else
				{
					printf("ID_CONNECTION_ATTEMPT_FAILED\n");
				}
			}
			else if (p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REQUEST || p->data[0]==ID_RAKVOICE_OPEN_CHANNEL_REPLY)
			{
				printf("Got new channel from %s\n", p->systemAddress.ToString());
			}
			else if (p->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
			{
				RakNetGUID g;
				RakNet::BitStream b(p->data, p->length, false);
				b.IgnoreBits(8); // Ignore the ID_...
				b.Read(g);
				printf("ID_NAT_TARGET_NOT_CONNECTED for %s\n", g.ToString());
			}
			else if (p->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
			{
				RakNetGUID g;
				RakNet::BitStream b(p->data, p->length, false);
				b.IgnoreBits(8); // Ignore the ID_...
				b.Read(g);
				printf("ID_NAT_TARGET_UNRESPONSIVE for %s\n", g.ToString());
			}
			else if (p->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
			{
				RakNetGUID g;
				RakNet::BitStream b(p->data, p->length, false);
				b.IgnoreBits(8); // Ignore the ID_...
				b.Read(g);
				printf("ID_NAT_CONNECTION_TO_TARGET_LOST for %s\n", g.ToString());
			}
			else if (p->data[0]==ID_NAT_ALREADY_IN_PROGRESS)
			{
				RakNetGUID g;
				RakNet::BitStream b(p->data, p->length, false);
				b.IgnoreBits(8); // Ignore the ID_...
				b.Read(g);
				printf("ID_NAT_ALREADY_IN_PROGRESS for %s\n", g.ToString());
			}
			else if (p->data[0]==ID_NAT_PUNCHTHROUGH_FAILED)
			{
				printf("ID_NAT_PUNCHTHROUGH_FAILED for %s\n", p->guid.ToString());
			}
			else if (p->data[0]==ID_NAT_PUNCHTHROUGH_SUCCEEDED)
			{
				printf("ID_NAT_PUNCHTHROUGH_SUCCEEDED for %s. Connecting...\n", p->guid.ToString());
				rakPeer->Connect(p->systemAddress.ToString(false),p->systemAddress.port,0,0);
			}
			else if (p->data[0]==ID_ALREADY_CONNECTED)
			{
				printf("ID_ALREADY_CONNECTED\n");
			}
			else if (p->data[0]==ID_RAKVOICE_CLOSE_CHANNEL)
			{
				printf("ID_RAKVOICE_CLOSE_CHANNEL\n");
			}
			else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
			{
				printf("ID_DISCONNECTION_NOTIFICATION\n");
			}
			else if (p->data[0]==ID_NEW_INCOMING_CONNECTION)
			{
				printf("ID_NEW_INCOMING_CONNECTION\n");
			}
			else
			{
				printf("Unknown packet ID %i\n", p->data[0]);
			}


			rakPeer->DeallocatePacket(p);
			p=rakPeer->Receive();
		}


		Pa_Sleep( 30 );
	}
	}

	err = Pa_CloseStream( stream );
	if( err != paNoError ) goto error;

	Pa_Terminate();

	rakPeer->Shutdown(300);
	RakNetworkFactory::DestroyRakPeerInterface(rakPeer);

	return 0;

error:
	Pa_Terminate();
	fprintf( stderr, "An error occured while using the portaudio stream\n" );
	fprintf( stderr, "Error number: %d\n", err );
	fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
	return -1;
}
PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet)
{
	switch (packet->data[0])
	{
	case ID_NAT_GET_MOST_RECENT_PORT:
		{
			OnGetMostRecentPort(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
	case ID_OUT_OF_BAND_INTERNAL:
		if (packet->length>=2 &&
			(packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) &&
			sp.nextActionTime!=0)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(2);
			uint16_t sessionId;
			bs.Read(sessionId);
//			RakAssert(sessionId<100);
			if (sessionId!=sp.sessionId)
				break;

			char ipAddressString[32];
			packet->systemAddress.ToString(true,ipAddressString);
			if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL)
			{
				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString));
				}
				if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT)
				{
					sp.testMode=SendPing::PUNCHING_FIXED_PORT;
					sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL;
					sp.targetAddress=packet->systemAddress;
					// Keeps trying until the other side gives up too, in case it is unidirectional
					sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*pc.MAX_PREDICTIVE_PORT_RANGE;
				}

				SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
			}
			else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL &&
				sp.targetGuid==packet->guid)
			{
				// They send back our port
				bs.Read(mostRecentNewExternalPort);

				SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);

				// Tell the user about the success
				sp.targetAddress=packet->systemAddress;
				PushSuccess();
				OnReadyForNextPunchthrough();
				bool removedFromFailureQueue=RemoveFromFailureQueue();

				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					if (removedFromFailureQueue)
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString));
					else
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString));
				}
			}

	//		mostRecentNewExternalPort=packet->systemAddress.port;
		}
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_ALREADY_IN_PROGRESS:
		{
			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString));
			}

		}
		break;
	case ID_NAT_TARGET_NOT_CONNECTED:
	case ID_NAT_CONNECTION_TO_TARGET_LOST:
	case ID_NAT_TARGET_UNRESPONSIVE:
		{
			char *reason;
			if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
				reason=(char *)"ID_NAT_TARGET_NOT_CONNECTED";
			else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
				reason=(char *)"ID_NAT_CONNECTION_TO_TARGET_LOST";
			else
				reason=(char *)"ID_NAT_TARGET_UNRESPONSIVE";

			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));

			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST ||
				packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
			{
				uint16_t sessionId;
				incomingBs.Read(sessionId);
				if (sessionId!=sp.sessionId)
					break;
			}

			unsigned int i;
			for (i=0; i < failedAttemptList.Size(); i++)
			{
				if (failedAttemptList[i].guid==targetGuid)
				{
					if (natPunchthroughDebugInterface)
					{
						char guidString[128];
						targetGuid.ToString(guidString);
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason));

					}

					// If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried.

					// Don't need to return failed, the other messages indicate failure anyway
					/*
					Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID));
					p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED;
					p->systemAddress=failedAttemptList[i].addr;
					p->systemAddress.systemIndex=(SystemIndex)-1;
					p->guid=failedAttemptList[i].guid;
					rakPeerInterface->PushBackPacket(p, false);
					*/

					failedAttemptList.RemoveAtIndexFast(i);
					break;
				}
			}

			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason));
			}

			// Stop trying punchthrough
			sp.nextActionTime=0;

			/*
			RakNet::BitStream bs(packet->data, packet->length, false);
			bs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID failedSystem;
			bs.Read(failedSystem);
			bool deletedFirst=false;
			unsigned int i=0;
			while (i < pendingOpenNAT.Size())
			{
				if (pendingOpenNAT[i].destination==failedSystem)
				{
					if (i==0)
						deletedFirst=true;
					pendingOpenNAT.RemoveAtIndex(i);
				}
				else
					i++;
			}
			// Failed while in progress. Go to next in attempt queue
			if (deletedFirst && pendingOpenNAT.Size())
			{
				SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
				sp.nextActionTime=0;
			}
			*/
		}
		break;
	case ID_TIMESTAMP:
		if (packet->data[sizeof(MessageID)+sizeof(RakNet::Time)]==ID_NAT_CONNECT_AT_TIME)
		{
			OnConnectAtTime(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
		break;
	}
	return RR_CONTINUE_PROCESSING;
}
Beispiel #13
0
/// RakNet stuff
void CDemo::UpdateRakNet(void)
{
	SystemAddress facilitatorSystemAddress(DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP, DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_PORT);
	Packet *packet;
	RakNetTime curTime = RakNet::GetTime();
	RakNet::RakString targetName;
	for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive())
	{
		if (strcmp(packet->systemAddress.ToString(false),DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP)==0)
		{
			targetName="NATPunchthroughServer";
		}
		else
		{
			targetName=packet->systemAddress.ToString(true);
		}

		switch (packet->data[0])
		{
		case ID_IP_RECENTLY_CONNECTED:
			{
				PushMessage(RakNet::RakString("This IP address recently connected from ") + targetName + RakNet::RakString("."));
				if (packet->systemAddress==facilitatorSystemAddress)
					PushMessage("Multiplayer will not work without the NAT punchthrough server!");
			}
			break;
		case ID_INCOMPATIBLE_PROTOCOL_VERSION:
			{
				PushMessage(RakNet::RakString("Incompatible protocol version from ") + targetName + RakNet::RakString("."));
				if (packet->systemAddress==facilitatorSystemAddress)
					PushMessage("Multiplayer will not work without the NAT punchthrough server!");
			}
			break;
		case ID_DISCONNECTION_NOTIFICATION:
			{
				PushMessage(RakNet::RakString("Disconnected from ") + targetName + RakNet::RakString("."));
				if (packet->systemAddress==facilitatorSystemAddress)
					isConnectedToNATPunchthroughServer=false;
			}
			break;
		case ID_CONNECTION_LOST:
			{
				PushMessage(RakNet::RakString("Connection to ") + targetName + RakNet::RakString(" lost."));
				if (packet->systemAddress==facilitatorSystemAddress)
					isConnectedToNATPunchthroughServer=false;
			}
			break;
		case ID_NO_FREE_INCOMING_CONNECTIONS:
			{
				PushMessage(RakNet::RakString("No free incoming connections to ") + targetName + RakNet::RakString("."));
				if (packet->systemAddress==facilitatorSystemAddress)
					PushMessage("Multiplayer will not work without the NAT punchthrough server!");
			}
			break;
		case ID_NEW_INCOMING_CONNECTION:
			{
				PushMessage(RakNet::RakString("New incoming connection from ") + targetName + RakNet::RakString("."));
				
				// Add this system as a new player
				replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid));
			}
			break;
		case ID_CONNECTION_REQUEST_ACCEPTED:
			{
				PushMessage(RakNet::RakString("Connection request to ") + targetName + RakNet::RakString(" accepted."));
				if (packet->systemAddress==facilitatorSystemAddress)
				{
					isConnectedToNATPunchthroughServer=true;
				}
				else
				{
					// Add this system as a new player
					replicaManager3->PushConnection(replicaManager3->AllocConnection(packet->systemAddress, packet->guid));
				}
			}
			break;
		case ID_CONNECTION_ATTEMPT_FAILED:
			{
				PushMessage(RakNet::RakString("Connection attempt to ") + targetName + RakNet::RakString(" failed."));
				if (packet->systemAddress==facilitatorSystemAddress)
					PushMessage("Multiplayer will not work without the NAT punchthrough server!");
			}
			break;
		case ID_NAT_TARGET_NOT_CONNECTED:
			{
				RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" not connected."));
			}
			break;
		case ID_NAT_TARGET_UNRESPONSIVE:
			{
				RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" unresponsive."));
			}
			break;
		case ID_NAT_CONNECTION_TO_TARGET_LOST:
			{
				RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT target connection to ") + targetName + RakNet::RakString(" lost."));
			}
			break;
		case ID_NAT_ALREADY_IN_PROGRESS:
			{
				RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT punchthrough to ") + targetName + RakNet::RakString(" in progress (skipping)."));
			}
			break;
		case ID_NAT_PUNCHTHROUGH_FAILED:
			{
				targetName=packet->guid.ToString();
				unsigned char weAreSender=packet->data[1];
				if (weAreSender)
				{
					PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" failed. Using proxy."));
					udpProxyClient->RequestForwarding(facilitatorSystemAddress, UNASSIGNED_SYSTEM_ADDRESS, packet->guid, 7000);
				}
				else
				{
					PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" failed. Remote system should connect via proxy."));
				}
			}
			break;
		case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
			{
				unsigned char weAreSender=packet->data[1];
				if (weAreSender)
				{
					PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" succeeded. Connecting."));
					rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.port,0,0);
				}
				else
				{
					PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" succeeded."));
				}
			}
			break;
		case ID_ADVERTISE_SYSTEM:
			if (packet->guid!=rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
			{
				char hostIP[32];
				packet->systemAddress.ToString(false,hostIP);
				rakPeer->Connect(hostIP,packet->systemAddress.port,0,0);
			}
			break;
		}
	}
	for (packet=tcpInterface->Receive(); packet; tcpInterface->DeallocatePacket(packet), packet=tcpInterface->Receive())
	{
		httpConnection->ProcessTCPPacket(packet);
	}
	if (httpConnection->HasRead())
	{
		RakNet::RakString httpResult = httpConnection->Read();
		// Good response, let the PHPDirectoryServer2 class handle the data
		// If resultCode is not an empty string, then we got something other than a table
		// (such as delete row success notification, or the message is for HTTP only and not for this class).
		HTTPReadResult readResult = phpDirectoryServer2->ProcessHTTPRead(httpResult);

		if (readResult==HTTP_RESULT_GOT_TABLE)
		{
			/// Got a table which was stored internally. Print it out
			const DataStructures::Table *games = phpDirectoryServer2->GetLastDownloadedTable();
			// __GAME_NAME is an automatic column passed to PHPDirectoryServer::UploadTable
			unsigned int gameNameIndex = games->ColumnIndex("__GAME_NAME");
			// RakNetGUID is a column we manually added using our own GUID with PHPDirectoryServer::SetField
			// We need to use RakNetGUID because NAT punchthrough refers to systems by RakNetGUID, rather than by SystemAddress
			unsigned int guidIndex = games->ColumnIndex("RakNetGUID");
			DataStructures::Table::Row *row;
			unsigned int i;
			unsigned int tableSize=0, connectionCount=0;
			DataStructures::Page<unsigned, DataStructures::Table::Row*, _TABLE_BPLUS_TREE_ORDER> *cur = games->GetRows().GetListHead();
			while (cur)
			{
				for (i=0; i < (unsigned)cur->size; i++)
				{
					RakAssert(gameNameIndex!=-1);
					row = cur->data[i];
					// Make sure it's the same game, since the PHPDirectoryServer can return other games too
					if (gameNameIndex!=-1 && strcmp(row->cells[gameNameIndex]->c, "IrrlichtDemo")==0)
					{
						tableSize++;
						RakNet::RakString guidStr = row->cells[guidIndex]->c;
						RakNetGUID guid;
						guid.FromString(guidStr.C_String());
						// Connect as long as I'm not connecting to myself
						if (guid!=rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS))
						{
							connectionCount++;
							systemsToConnectTo.Push(guid);
						}
					}
				}
				cur=cur->next;
			}
			PushMessage(RakNet::RakString("DirectoryServer returned %i rows, of which we are connecting to %i",tableSize,connectionCount));
		}
	}

	// Update our two classes so they can do time-based updates
	httpConnection->Update();
	phpDirectoryServer2->Update();

	// Start punchthrough to all pending systems, which we got from the PHP directory server code about 20 lines above
	if (isConnectedToNATPunchthroughServer)
	{
		while (systemsToConnectTo.GetSize()>0)
		{
			RakNetGUID g = systemsToConnectTo.Pop(__FILE__,__LINE__);
			natPunchthroughClient->OpenNAT(g, facilitatorSystemAddress);
			targetName=g.ToString();
			PushMessage(RakNet::RakString("Punchthrough to ") + targetName + RakNet::RakString(" started."));
		}
	}
	
	// Update non-plugin helper classes.
	// This keeps our system listed on the PHP directory server
	httpConnection->Update();
	phpDirectoryServer2->Update();

	// Call the Update function for networked game objects added to BaseIrrlichtReplica once the game is ready
	if (currentScene>=1)
	{
		DataStructures::DefaultIndexType idx;
		for (idx=0; idx < replicaManager3->GetReplicaCount(); idx++)
			((BaseIrrlichtReplica*)(replicaManager3->GetReplicaAtIndex(idx)))->Update(curTime);;
	}	
}