- Home /
What are the options to distribute a final version of a multiplayer game?
Hi, my name is andys and i have a question, currently i'm working on a multiplayer game, i'm using php to store all the host data of the players and the match, everything is working fine, but now it says NAT target 2147483647 not connected to NAT facilitator 67.225.180.24:50005, i suppose that the ip shown there is the unity3d master server but i'm not sure, if that's the unity 3d master server ip it means that i'm using a kind of testing tool, so i'd like to know what way i have to host a server, can i just take some of my computers and keep them on and use them as servers or are there any other option, Actually im just using the unity networking, any answer will be appreciated and sorry, im noob ;)
this is the connection script
import System.Collections.Generic;
///////////////////Connetion to server
var portString = "25565";
///////////////////////////////////////////////////////////new version php
public var masterSeverURL : String;
private var hostData : HostData[] = null;
///////////////////////////////////////////////////////////new version php
var playerName : String;
var battleName : String;
public static var cManager : ConnectionScript;
public var playerList = new List.();
var myOnlinePlayer : onlinePlayers;
var myPlayer : GameObject;
private var startedGame;
private var createdPlayer : boolean = false;
private var gameName : String = "";
private var gameType : String = "";
private var Comment : String = "";
var updateDelayTime : float = 10.0;
var playerBio : playerInfo;
var myPlayerID : NetworkView;
function Awake() {
DontDestroyOnLoad(gameObject);
playerBio = this.GetComponent.<playerInfo>();
cManager = this;
}
public function PollHostList() : HostData[] {
return hostData;
}
public function getServers(type : String) {
var url = masterSeverURL + "/Ms/getMs.php?gameType=" + type;
Debug.Log("checando url " + url);
var www = new WWW (url);
yield www;
if (www.text == "") {
hostData = null;
return;
}
Debug.Log(www.text);
var hosts = www.text.Split(";"[0]);
hostData = new HostData[hosts.length];
var index = 0;
for (var host in hosts) {
data = host.Split(","[0]);
hostData[index] = new HostData();
hostData[index].ip = new String[1];
hostData[index].ip[0] = data[0];
hostData[index].port = parseInt(data[1]);
hostData[index].useNat = (data[2] == "1");
hostData[index].guid = data[3];
hostData[index].gameType = data[4];
hostData[index].gameName = data[5];
hostData[index].connectedPlayers = parseInt( data[6]);
hostData[index].playerLimit = parseInt(data[7]);
hostData[index].passwordProtected = (data[8] == "1");
hostData[index].comment = data[9];
index ++;
}
}
function Start(){
startedGame = false;
}
function Update(){
playerName = PlayerPrefs.GetString("MainPlayerName");
}
function initiateServer(Rcomment : String, RgameType : String, RgameName : String, RmaxPlayers : int){
gameName = RgameName;
gameType = RgameType;
Comment = Rcomment;
Network.InitializeServer(RmaxPlayers, parseInt(portString), true);
MasterServer.RegisterHost(RgameType, RgameName, Rcomment);
}
function registrationLoop() {
while (Network.isServer) {
var url = masterSeverURL + "/Ms/updateHost.php?";
url += "gameName=" + gameName;
url += "gameType=" + gameType;
Debug.Log(url);
var www = new WWW(url);
yield www;
yield WaitForSeconds(updateDelayTime);
}
}
public function registerHost() {
while (Network.player.externalPort == 65535) {
yield WaitForSeconds(1);
}
var url = masterSeverURL + "/Ms/registerG.php?";
url += "gameType=" + gameType;
url += "&gameName=" + WWW.EscapeURL(gameName);
url += "&comment=" + Comment;
url += "&useNat=" + !Network.HavePublicAddress();
url += "&connectedPlayers=" + (Network.connections.length+1);
url += "&playerLimit=" + Network.maxConnections;
url += "&internalIp=" + Network.player.ipAddress;
url += "&internalPort=" + Network.player.port;
url += "&externalIp=" + Network.player.externalIP;
url += "&externalPort=" + Network.player.externalPort;
url += "&guid=" + Network.player.guid;
url += "&password=" + (Network.incomingPassword != "" ? 1 : 0);
Debug.Log(url);
var www = new WWW (url);
yield www;
Debug.Log(www.text);
StartCoroutine(registrationLoop());
}
function OnPlayerConnected(id : NetworkPlayer) {
var url = masterSeverURL + "/Ms/updatePlayers.php?";
url += "gameType=" + gameType;
url += "&gameName=" + gameName;
url += "&connectedPlayers=" + (Network.connections.length + 1);
Debug.Log("url " + url );
var www = new WWW (url);
for (var pl : onlinePlayers in playerList) {
GetComponent.<NetworkView>().RPC("updateList",id,pl.playerName,pl.onlinePlayer);
}
}
function OnConnectedToServer() {
GetComponent.<NetworkView>().RPC("setServer",RPCMode.Server,playerName, Network.player);
}
function OnServerInitialized(){
Debug.Log("Servidor iniciado");
registerHost();
setServer(playerName, Network.player);
}
function OnPlayerDisconnected(id : NetworkPlayer) {
var url = masterSeverURL + "/Ms/updatePlayers.php?";
url += "gameName=" + gameName;
url += "&gameType=" + gameType;
url += "&connectedPlayers=" + Network.connections.length;
Debug.Log(url);
var www = new WWW(url);
GetComponent.<NetworkView>().RPC("clean", RPCMode.All,id);
Network.RemoveRPCs(id);
Network.DestroyPlayerObjects(id);
}
function OnDisconnectedFromServer() {
if (Network.isServer) {
var url = masterSeverURL + "/Ms/unregisterG.php?";
url += "gameName=" + gameName;
url += "&gameType=" + gameType;
var www = new WWW(url);
yield www;
}
playerList.Clear();
Application.LoadLevel(0);
Destroy(this.gameObject);
}
function OnGUI() {
if(startedGame){
if (GUI.Button(new Rect(Screen.width - 100, Screen.height - 50, 100, 25), "Entrar") && !createdPlayer) {
playerBio.spawn();
myPlayer = playerBio.myPlayer;
GetComponent.<NetworkView>().RPC("addPlayer", RPCMode.All, Network.player);
createdPlayer = true;
}
if (GUI.Button(new Rect(Screen.width - 100, Screen.height - 25, 100, 25), "Desconectarse")) {
DisconnectNow();
}
}
GUI.Label(new Rect(0,Screen.height-25,Screen.width,25),"Current Status: " + testStatus);
GUI.Label(new Rect(0,Screen.height-50,Screen.width,25),"Test result : " + testMessage);
GUI.Label(new Rect(0,Screen.height-75,Screen.width,25),shouldEnableNatMessage);
if (!doneTesting)
TestConnection();
}
@RPC
function setServer(Pname : String, id : NetworkPlayer) {
GetComponent.<NetworkView>().RPC("updateList",RPCMode.All,Pname, id);
}
@RPC
function updateList(newPlayerName : String, player : NetworkPlayer)
{
var temp : onlinePlayers = new onlinePlayers();
temp.playerName = newPlayerName;
temp.onlinePlayer = player;
playerList.Add(temp);
if(Network.player == player){
myOnlinePlayer = temp;
}
}
@RPC
function clean(id : NetworkPlayer) {
var temp : onlinePlayers = new onlinePlayers();
for (var pl :onlinePlayers in playerList) {
if (pl.onlinePlayer == id) {
temp = pl;
}
}
if (temp != null) {
playerList.Remove(temp);
}
}
@RPC
function startGame(level : String, levelPrefix : int) {
startedGame = true;
Network.SetSendingEnabled(0, false);
Network.isMessageQueueRunning = false;
Application.LoadLevel(level);
yield;
Network.isMessageQueueRunning = true;
Network.SetSendingEnabled(0, true);
this.GetComponent.<NetworkMenu>().enabled = false;
}
@RPC
function addPlayer(id : NetworkPlayer) {
for (var pl : onlinePlayers in playerList ) {
if (pl.onlinePlayer == id) {
pl.playerMesh = playerBio.myPlayer;
myPlayerID = pl.playerMesh.GetComponent.<NetworkView>();
pl.playerMesh.name = pl.playerName;
}
}
}
class onlinePlayers extends System.Object{
var playerName : String;
var onlinePlayer : NetworkPlayer;
var playerMesh : GameObject;
}
function DisconnectNow() {
if (Network.isServer) {
var url = masterSeverURL + "/Ms/unregisterG.php?";
url += "gameName=" + gameName;
url += "&gameType=" + gameType;
var www = new WWW(url);
yield www;
}
Network.Disconnect(200);
}
//////////////////////////////////////////////////////////////////////////////////////////test connection
var testStatus = "Testing network connection capabilities.";
var testMessage = "Test in progress";
var shouldEnableNatMessage : String = "";
var doneTesting = false;
var probingPublicIP = false;
var serverPort = 9999;
var connectionTestResult = ConnectionTesterStatus.Undetermined;
// Indicates if the useNat parameter be enabled when starting a server
var useNat = false;
function TestConnection() {
// Start/Poll the connection test, report the results in a label and
// react to the results accordingly
connectionTestResult = Network.TestConnection();
switch (connectionTestResult) {
case ConnectionTesterStatus.Error:
testMessage = "Problem determining NAT capabilities";
doneTesting = true;
break;
case ConnectionTesterStatus.Undetermined:
testMessage = "Undetermined NAT capabilities";
doneTesting = false;
break;
case ConnectionTesterStatus.PublicIPIsConnectable:
testMessage = "Directly connectable public IP address.";
useNat = false;
doneTesting = true;
break;
// This case is a bit special as we now need to check if we can
// circumvent the blocking by using NAT punchthrough
case ConnectionTesterStatus.PublicIPPortBlocked:
testMessage = "Non-connectable public IP address (port " +
serverPort +" blocked), running a server is impossible.";
useNat = false;
// If no NAT punchthrough test has been performed on this public
// IP, force a test
if (!probingPublicIP) {
connectionTestResult = Network.TestConnectionNAT();
probingPublicIP = true;
testStatus = "Testing if blocked public IP can be circumvented";
timer = Time.time + 10;
}
// NAT punchthrough test was performed but we still get blocked
else if (Time.time > timer) {
probingPublicIP = false; // reset
useNat = true;
doneTesting = true;
}
break;
case ConnectionTesterStatus.PublicIPNoServerStarted:
testMessage = "Public IP address but server not initialized, "+
"it must be started to check server accessibility. Restart "+
"connection test when ready.";
break;
case ConnectionTesterStatus.LimitedNATPunchthroughPortRestricted:
testMessage = "Limited NAT punchthrough capabilities. Cannot "+
"connect to all types of NAT servers. Running a server "+
"is ill advised as not everyone can connect.";
useNat = true;
doneTesting = true;
break;
case ConnectionTesterStatus.LimitedNATPunchthroughSymmetric:
testMessage = "Limited NAT punchthrough capabilities. Cannot "+
"connect to all types of NAT servers. Running a server "+
"is ill advised as not everyone can connect.";
useNat = true;
doneTesting = true;
break;
case ConnectionTesterStatus.NATpunchthroughAddressRestrictedCone:
case ConnectionTesterStatus.NATpunchthroughFullCone:
testMessage = "NAT punchthrough capable. Can connect to all "+
"servers and receive connections from all clients. Enabling "+
"NAT punchthrough functionality.";
useNat = true;
doneTesting = true;
break;
default:
testMessage = "Error in test routine, got " + connectionTestResult;
}
if (doneTesting) {
if (useNat)
shouldEnableNatMessage = "When starting a server the NAT "+
"punchthrough feature should be enabled (useNat parameter)";
else
shouldEnableNatMessage = "NAT punchthrough not needed";
testStatus = "Done testing";
}
}
and this is the menu
///////////////////////////////////connection menu script
private var menu :String;
/*
Menus
1- main_menu
2- host_menu
3-join_menu
prefs
1-MainPlayerName
*/
public var playerName : String; //// the name of the player
public var battleName : String ; ///////////////////////name of the round
public var playersLimit : int; //// the max number of players in a round
private var serverManager : ConnectionScript;
//////////////////////////////////////////php new
public var gameType : String;
public var gameName : String;
public var comment :String = "";
public var updatesDelay : float = 10.0;
//////////////////////////////////////////level loading
var supportedNetworkLevel : String[];
var disconnectedLevel : String;
private var lastLevelPrefix = 0;
//////////////////////////////////////////level loading
function Awake() {
GetComponent.<NetworkView>().group = 1;
serverManager = this.GetComponent.<ConnectionScript>();
}
function Start(){
menu = "main_menu";
playerName = PlayerPrefs.GetString("MainPlayerName");
}
function moveToMenu(menuName : String){
menu = menuName;
}
function OnGUI(){
if(menu == "main_menu"){
mainMenu();
}
if(menu == "host_menu"){
hostMenu();
}
if(menu == "lobby_menu"){
lobbyMenu();
}
if(menu == "list_menu"){
listMenu();
}
}
private function mainMenu(){
if(GUI.Button(new Rect(0,0,120,32),"Crear Sala")){
moveToMenu("host_menu");
}
playerName = GUI.TextField(new Rect(0,35,120,32),playerName);
if(GUI.Button(new Rect(0,73,120,32),"Guardar Nombre")){
PlayerPrefs.SetString("MainPlayerName",playerName);
}
if(GUI.Button(new Rect(125,0,120,32),"Unirse a sala")){
serverManager.getServers(gameType);
moveToMenu("list_menu");
}
}
private function hostMenu(){
if(GUI.Button(new Rect(225,0,120,32),"Iniciar")){
ConnectionScript.cManager.initiateServer("",gameType, gameName,playersLimit);
moveToMenu("lobby_menu");
}
gameName = GUI.TextField(new Rect(0,0,120,32), gameName);
if (GUI.Button(new Rect(125, 0, 30, 30), "-") && playersLimit > 0) {
playersLimit--;
}
if (GUI.Button(new Rect(185, 0, 30, 30), "+") && playersLimit < 16) {
playersLimit++;
}
GUI.Label(new Rect(155,0,30,30),playersLimit.ToString());
if(GUI.Button(new Rect(0,33,120,32),"Volver")){
moveToMenu("main_menu");
}
}
function listMenu(){
if(GUI.Button(new Rect(0,0,120,32),"Refrescar")){
serverManager.getServers(gameType);
serverManager.PollHostList();
}
if (GUI.Button(new Rect(125, 0, 120, 23), "Volver")) {
moveToMenu("main_menu");
}
GUILayout.BeginArea(new Rect(Screen.width / 2, 0, Screen.width / 2, Screen.height), "Lista de servers", "box");
var hostDataList : HostData[] = serverManager.PollHostList();
if(hostDataList != null && hostDataList.length >0 ){
for (var hostData in hostDataList ) {
GUILayout.BeginHorizontal();
GUILayout.Label(hostData.gameName);
if (GUILayout.Button("Entrar"))
{
Network.Connect(hostData.guid);
moveToMenu("lobby_menu");
}
GUILayout.EndHorizontal();
}
}
GUILayout.EndArea();
}
function lobbyMenu(){
if(Network.isServer){
if (GUI.Button(new Rect(0, 0, 120, 30), "Iniciar juego")) {
ConnectionScript.cManager.GetComponent.<NetworkView>().RPC("startGame", RPCMode.AllBuffered, supportedNetworkLevel[0], 1);
}
var curIPAdrres = Network.player.ipAddress;
var curPort = Network.player.port;
GUI.Label(new Rect(0,90,500,20),"IP: "+curIPAdrres+" Port: "+curPort);
}
if (GUI.Button(new Rect(0, 35, 120, 25), "Salir")) {
serverManager.DisconnectNow();
moveToMenu("main_menu");
}
}
and when i change the the connection function to
Network.Connect(hostData.guid);
i receive this error NAT target 2147483647 not connected to NAT facilitator 67.225.180.24:5000
You could just use your own computer ipAddress for testing, use 127.0.0.1
Answer by Bunny83 · Apr 26, 2015 at 03:57 AM
Uhm you don't seem to use the built-in MasterServer functionality as you seem you use your own webserver instead to manage running games. The connect-by-GUID only works in combination with Unity's built-in masterserver. The "nat facilitator" is a part of the masterserver and is actually a seperate server (but part of the masterserver application) which just acts as nat-punch-through helper.
If you host your own masterserver application you have to set the public IP and port of the masterserver with the MasterServer class ("ipAddress" and "port").
The masterserver already does the bookkeeping of running servers which you register at the master server with MasterServer.RegisterHost(). You actually register your game server but you don't use MasterServer.RequestHostList nor MasterServer.PollHostList.
If you don't set your own masterserver IP and port Unity uses a public masterserver which is hosted by Unity itself. This masterserver is ment for testing / development. In a finished game you probably want to host your own masterserver.
You seem to use Network.player.guid. However this is only available when you're connected to the masterserver. "2147483647" is actually "int.MaxValue" which most likely indicates the guid isn't set (yet?). Also i wouldn't simply assume that the player's guid will equal a game's guid that has been started by this player.
In the end you seem to mix a lot of different concepts in strange ways. Registering the server at Unity's masterserver is pointless when you don't use it. If you want to roll your own way to connect players with a server that's fine, but in this case you can't use the nat-punch-through feature. So players who host a game server might have to setup a port forwarding in their router settings (like in the "old" days).
Thanks for your answer, i'm more awared of the situation, so what i have to do is set my own masterserver downloading the files from the unty 3d website and build my own or what other way do i have to keep the running games in a php server, i do apologize, but i'm new and i'm just practicing, thanks