Exemple #1
0
/// RakNet stuff
void CDemo::UpdateRakNet(void)
{
	RakNet::SystemAddress facilitatorSystemAddress(DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_IP, DEFAULT_NAT_PUNCHTHROUGH_FACILITATOR_PORT);
	RakNet::Packet *packet;
	RakNet::TimeMS curTime = RakNet::GetTimeMS();
	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:
			{
				if (fullyConnectedMesh2->IsHostSystem())
				{
					PushMessage(RakNet::RakString("Sending player list to new connection"));
					fullyConnectedMesh2->StartVerifiedJoin(packet->guid);
				}
			}
			break;
		case ID_FCM2_VERIFIED_JOIN_START:
			{
				DataStructures::List<RakNet::SystemAddress> addresses;
				DataStructures::List<RakNet::RakNetGUID> guids;
				fullyConnectedMesh2->GetVerifiedJoinRequiredProcessingList(packet->guid, addresses, guids);
				for (unsigned int i=0; i < guids.Size(); i++)
					natPunchthroughClient->OpenNAT(guids[i], facilitatorSystemAddress);
			}
			break;
		case ID_FCM2_VERIFIED_JOIN_FAILED:
			{
				PushMessage(RakNet::RakString("Failed to join game session"));
			}
			break;
		case ID_FCM2_VERIFIED_JOIN_CAPABLE:
			{
				fullyConnectedMesh2->RespondOnVerifiedJoinCapable(packet, true, 0);
			}
			break;
		case ID_FCM2_VERIFIED_JOIN_ACCEPTED:
			{
				DataStructures::List<RakNet::RakNetGUID> systemsAccepted;
				bool thisSystemAccepted;
				fullyConnectedMesh2->GetVerifiedJoinAcceptedAdditionalData(packet, &thisSystemAccepted, systemsAccepted, 0);
				if (thisSystemAccepted)
					PushMessage("Game join request accepted\n");
				else
					PushMessage(RakNet::RakString("System %s joined the mesh\n", systemsAccepted[0].ToString()));
				
				// DataStructures::List<RakNetGUID> participantList;
				// fullyConnectedMesh2->GetParticipantList(participantList);

				for (unsigned int i=0; i < systemsAccepted.Size(); i++)
					replicaManager3->PushConnection(replicaManager3->AllocConnection(rakPeer->GetSystemAddressFromGuid(systemsAccepted[i]), systemsAccepted[i]));
			}
			break;
		case ID_CONNECTION_REQUEST_ACCEPTED:
			{
				PushMessage(RakNet::RakString("Connection request to ") + targetName + RakNet::RakString(" accepted."));
				if (packet->systemAddress==facilitatorSystemAddress)
				{
					isConnectedToNATPunchthroughServer=true;

					// Open UPNP.
					struct UPNPDev * devlist = 0;
					devlist = upnpDiscover(1000, 0, 0, 0);
					if (devlist)
					{
						char lanaddr[64];	/* my ip address on the LAN */
						struct UPNPUrls urls;
						struct IGDdatas data;
						if (UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))==1)
						{
							// External port is the port people will be connecting to us on. This is our port as seen by the directory server
							// Internal port is the port RakNet was internally started on
							char eport[32], iport[32];
							natPunchthroughClient->GetUPNPPortMappings(eport, iport, facilitatorSystemAddress);

							int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype,
								eport, iport, lanaddr, 0, "UDP", 0);

							if(r==UPNPCOMMAND_SUCCESS)
							{
								// UPNP done
							}

						}
					}
					
					// Query cloud for other running game instances
					RakNet::CloudQuery cloudQuery;
					cloudQuery.keys.Push(RakNet::CloudKey("IrrlichtDemo",0),_FILE_AND_LINE_);
					cloudClient->Get(&cloudQuery, packet->guid);
				}
			}
			break;
		case ID_FCM2_NEW_HOST:
			{
				if (packet->guid==rakPeer->GetMyGUID())
				{
					// Original host dropped. I am the new session host. Upload to the cloud so new players join this system.
					RakNet::CloudKey cloudKey("IrrlichtDemo",0);
					cloudClient->Post(&cloudKey, 0, 0, rakPeer->GetGuidFromSystemAddress(facilitatorSystemAddress));
				}
			}
			break;
		case ID_CLOUD_GET_RESPONSE:
			{
				RakNet::CloudQueryResult cloudQueryResult;
				cloudClient->OnGetReponse(&cloudQueryResult, packet);
				if (cloudQueryResult.rowsReturned.Size()>0)
				{	
					PushMessage(RakNet::RakString("NAT punch to existing game instance"));
					natPunchthroughClient->OpenNAT(cloudQueryResult.rowsReturned[0]->clientGUID, facilitatorSystemAddress);
				}
				else
				{
					PushMessage(RakNet::RakString("Publishing new game instance"));

					// Start as a new game instance because no other games are running
					RakNet::CloudKey cloudKey("IrrlichtDemo",0);
					cloudClient->Post(&cloudKey, 0, 0, packet->guid);
				}

				cloudClient->DeallocateWithDefaultAllocator(&cloudQueryResult);
			}
			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:
			{
				RakNet::RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(RakNet::MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" not connected."));
			}
			break;
		case ID_NAT_TARGET_UNRESPONSIVE:
			{
				RakNet::RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(RakNet::MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT target ") + targetName + RakNet::RakString(" unresponsive."));
			}
			break;
		case ID_NAT_CONNECTION_TO_TARGET_LOST:
			{
				RakNet::RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(RakNet::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:
			{
				RakNet::RakNetGUID recipientGuid;
				RakNet::BitStream bs(packet->data,packet->length,false);
				bs.IgnoreBytes(sizeof(RakNet::MessageID));
				bs.Read(recipientGuid);
				targetName=recipientGuid.ToString();
				PushMessage(RakNet::RakString("NAT punchthrough to ") + targetName + RakNet::RakString(" in progress (skipping)."));
			}
			break;

		case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
			{
				if (packet->data[1]==1)
				{
					PushMessage(RakNet::RakString("Connecting to existing game instance"));
					RakNet::ConnectionAttemptResult car = rakPeer->Connect(packet->systemAddress.ToString(false), packet->systemAddress.GetPort(), 0, 0);
					RakAssert(car==RakNet::CONNECTION_ATTEMPT_STARTED);
				}
			}
			break;

		case ID_ADVERTISE_SYSTEM:
			if (packet->guid!=rakPeer->GetGuidFromSystemAddress(RakNet::UNASSIGNED_SYSTEM_ADDRESS))
			{
				char hostIP[32];
				packet->systemAddress.ToString(false,hostIP);
				RakNet::ConnectionAttemptResult car = rakPeer->Connect(hostIP,packet->systemAddress.GetPort(),0,0);
				RakAssert(car==RakNet::CONNECTION_ATTEMPT_STARTED);
			}
			break;
		}
	}

	// Call the Update function for networked game objects added to BaseIrrlichtReplica once the game is ready
	if (currentScene>=1)
	{
		unsigned int idx;
		for (idx=0; idx < replicaManager3->GetReplicaCount(); idx++)
			((BaseIrrlichtReplica*)(replicaManager3->GetReplicaAtIndex(idx)))->Update(curTime);;
	}	
}
Exemple #2
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);;
	}	
}