Unity Networking + Mysql, communication questions

Hi !

I am working on a small but persistant multiplayer game. I am not a total programming newbie, but I began Unity and C# a few weeks ago :wink: (I am more a 3D artist, and I program generally for graphic things like shaders, tools for 3D softwares and website)

So far I have managed to create my own network using C# (thanks to tutorials and posts on this forum :slight_smile: ). There is a small login system that checks if the login and password entered by the player on the GUI match my database. If so, the client connects itself to the network, a generic player is spawned. If this player moves, it is seen by other players. Quite cool actually :smile:

But (there is always a but :wink: ), I would like to attach to my player the id corresponding to the login in my database (so I can ask my database about other player’s stored informations).

I managed to get the id from php, so I have it in my login script (it is an int variable ^^). Just after retrieving this id, I connect to the network (using a regular : Network.Connect(connectToIP,connectPort,password);). This is certainly stupid, but I absolutely don’t see how can I attach this id to the player that is connecting.

I appreciate any clue to help me transfer this data to the player !

Connecting to mysql through php is the best way to go if you want to contact the database from the client for security reasons.

This is what I do, I don’t have problem for this (maybe I wasn’t clear). The problem for me is to send the variable I have retrieved thanks to php through the network :
I have a login script where I have an int called “userId” and a spawn script where there is a spawning function that is call after connecting. I don’t know how to get my userId here and to attach here to my new player.

Thanks for taking the time to answer.

When the client connects, send your userid to the server with a RPC call.

http://unity3d.com/support/documentation/Components/net-RPCDetails.html

I will try that, thanks a lot :slight_smile:

http://forum.unity3d.com/threads/65551-PHP-Master-Server?highlight=PHP+Master+Server here’s a great example

I am not using a MasterServer now ^^ (already complicated enough for me)
I tried to use RPC calls, but I am still stuck. I have read that thread (http://forum.unity3d.com/threads/10948-RPC-and-networkview) and now I am wondering if I understood anything at all… :cry:

For my game project, I planned to have a server independant from the players : different interface, the server will be online all the time, it cannot control any player, etc.

So I have created two scene : one for the client, one for the server. So far, they both have a spawnscript (that creates players, I tried to have it only on server but it didn’t work) . The only difference now is that there is only a script to launch the server and a script to lauch the player. Only the client get a player (prefab with playerScript attached to it). Does it make sense ? Was I wrong from the very beginning ? ^^

I posted the link to the master server because it shows a working example of unity sending and receiving info from a mysql server…

grab Leepo’s tutorial and the pdf that comes with it, it will be clear to you after you went through it.

It has been two weeks since I began to make this all works, and I am still stuck (I read all tutorials listed here, it is ok, but when I am not good enought to apply it to my own projet). I am pretty desperate now. Without help directly on my project, I will stay stuck for months. I perfectly understand that helping a newbie like me takes a lot of time !

As I’m a 3D artist, I am offering to exchange skills here : http://forum.unity3d.com/threads/75221-Skills-exchange-looking-for-help-on-Unity-Network-programming-offering-2D-3D-art?p=481678#post481678

If any one is interested to help me, please contact me !

If you already have the player’s ID from the database stored in an int in your login script, why can’t you use that reference to get whatever info you need about the player from the database?

I imagine a workflow like this:

-using a login script on a login object, player logs in via database, player id is pulled from db upon login and stored in “playerId” int
-playerprefab spawns for player
-playerprefab has a status script that access the login script of the login object, gets the playerId, then pulls relevant status information from db based on playerId

Are you destroying the login object upon login? Or loading a new scene, and therefore the login object doesn’t exist anymore? In that case, you could use DontDestroyOnLoad().

Actually, an even simpler solution would be to set a playerpref for the player ID upon login, then retrieve it whenever you need it. PlayerPrefs get stored in the windows registry, and can be accessed from any scene:

I managed to do this.

The difficulty is to attach the playerId to the Unity Player. :

I tried to store the database id in a PlayerInfo Class, but I did it wrong (I only managed to send this information to all players :stuck_out_tongue: not only to the player that just logged in) and then I don’t know how to get from a script inside unity the datas inside this class :stuck_out_tongue:

PlayersPrefs looks promising, I will try that ! Thanks a lot :slight_smile:

Edit : I am wondering how to test this easily : now I am testing it all in a local network on the same computer. I guess there will be only one user prefs then ?

Edwige,
did you got your code calling the php ? or still stuck on this ?

I found solutions. It works. I think it is very dirty, but it works so I am happy :wink:

Here is my spawnscript code (feel free to correct or reuse that, I reused myself a lot of the networking example and also of this : http://forum.unity3d.com/threads/24721-Tutorial-Unity-and-PHP-login-script-simple-but-useful), I didn’t changed much the other scripts. (I comment in French, I know it is not right, but it helps me see what are my comments and what are the original comments :wink: and also it is my mother tongue :stuck_out_tongue: I’ll be glad to translate, though )

//prefab à instancier pour générer le personnage joueur
private var playerPrefab : GameObject;

// Local player information when one is instantiated
private var localPlayer : NetworkPlayer;
private var localTransformViewID : NetworkViewID;
private var localAnimationViewID : NetworkViewID;
private var localidbdd : int=0;
private var isInstantiated : boolean = false;
private var isIdentified : boolean = false;
// The server uses this to track all instantiated player
private var playerInfo : Array = new Array();

//identification BDD
private var login = "";
private var formPassword = ""; //mot de passe perso des cliens
private var textrect : Rect = Rect(0, 150, 200, 20); //just make a GUI object rectangle
private var messErreurConnex ="";
private var formText = ""; //variable pour stocker les messages de php
private var scriptConnexion = "http://127.0.0.1/testReseau/connexion.php"; //script php permettant de se connecter
private var hash = "liv3"; //code secret d'accès à la BDD, si modifié, modifier aussi dans le script php
private var idBDDtemp : int;

//choix du personnage à instantier à partir de la bdd
private var scriptGetNumPerso = "http://127.0.0.1/testReseau/getNumPerso.php"; //script php permettant de se connecter
private var num_personnage : int = 0;
private var tableau_perso : Array = new Array("truc","NetworkPersonPlayer","Cube","Elise");//liste des personnages en fonction de leur position dans la BDD


//classe qui sert à stocker les infos des joueurs sur le serveur, essentiellement utile pour les détruire quand ils déco
class PlayerInfo {
	var transformViewID : NetworkViewID;
	var animationViewID : NetworkViewID;
	var player : NetworkPlayer;
	var idBDD : int;
}

function OnGUI () 
{
	if (Network.isClient  localPlayer.ToString() != 0  !isInstantiated) 
	{
		if (isIdentified) 
		{
			if (GUI.Button(new Rect(20,Screen.height-60, 90, 20),"SpawnPlayer"))
			{
				// Spawn the player on all machines
				networkView.RPC("SpawnPlayer", RPCMode.AllBuffered, localPlayer, localTransformViewID, localAnimationViewID,localidbdd);
				isInstantiated = true;
			}
		}
		else
		{
			login = GUILayout.TextField(login, GUILayout.MinWidth(100));
			formPassword = GUILayout.PasswordField(formPassword,"*"[0], GUILayout.MinWidth(100));
			GUI.TextArea( textrect, messErreurConnex );
			
			GUILayout.BeginVertical();
			if (GUILayout.Button ("Se Connecter"))
			{
				if(login!="")
				{
					Login(localPlayer);
				}	
				else
				{
					messErreurConnex="Vous n'avez pas indiqué d'identifiant";
				}		
			}

			GUILayout.EndVertical();
			
		
		}
	}
}

// Create a networked player in the game. Instantiate a local copy of the player, set the view IDs
// accordingly. 
@RPC
function SpawnPlayer (playerIdentifier : NetworkPlayer, transformViewID : NetworkViewID, animationViewID : NetworkViewID, idbdd : int) 
{
	var instantiatedPlayer : GameObject ;
	var networkViews;	
	
	networkView.RPC("GetNumPerso", RPCMode.AllBuffered, localidbdd);
	
	yield WaitForSeconds (1);
	
	var nom_prefab : String = "";
	nom_prefab = tableau_perso[num_personnage] as String;
	playerPrefab = Resources.Load(nom_prefab, GameObject);
		
	instantiatedPlayer = Instantiate(playerPrefab, transform.position, transform.rotation);
	networkViews = instantiatedPlayer.GetComponents(NetworkView);
	
	// Assign view IDs to player object 
	if (networkViews.Length != 2) {
		Debug.Log("Error while spawning player, prefab should have 2 network views, has "+networkViews.Length);
		return;
	} else {
		networkViews[0].viewID = transformViewID;
		networkViews[1].viewID = animationViewID;
	}

	// Initialize local player
	if (playerIdentifier == localPlayer) 
	{
		Debug.Log("Enabling user input as this is the local player");
		// W are doing client prediction and thus enable the controller script + user input processing
		instantiatedPlayer.GetComponent(ThirdPersonController).enabled = true;
		instantiatedPlayer.GetComponent(ThirdPersonController).getUserInput = true;
		// Enable input network synchronization (server gets input)
		instantiatedPlayer.GetComponent(NetworkController).enabled = true;
		instantiatedPlayer.SendMessage("SetOwnership");		
		instantiatedPlayer.SendMessage("SetPersoActuel",localidbdd);//pas utile, il suffit que localidbdd soit publique
		return;
	// Initialize player on server
	} 
	else if (Network.isServer) 
	{
	
		instantiatedPlayer.GetComponent(ThirdPersonController).enabled = true;
		instantiatedPlayer.GetComponent(PersonAnimation).enabled = true;
		// Record player info so he can be destroyed properly
		var playerInstance : PlayerInfo = new PlayerInfo();
		playerInstance.transformViewID = transformViewID;
		playerInstance.animationViewID = animationViewID;
		playerInstance.player = playerIdentifier;
		playerInstance.idBDD=localidbdd;
		playerInfo.Add(playerInstance);
		//networkView.RPC("MajPlayer", playerIdentifier, localidbdd);
	}
}

@RPC
function Login(localPlayer : NetworkPlayer)
{	
	var form = new WWWForm(); //nouveau formulaire
	form.AddField( "myform_hash", hash );
	form.AddField( "myform_nick", login );
	form.AddField( "myform_pass", formPassword );
	var requete = WWW(scriptConnexion, form); //creation de la requete que va envoyer unity à php (qui lui va se connecter a mysql)
		
	yield requete;	//yield return en c#
			
	if (requete.error != null) 
	{
		Debug.Log(requete.error); //if there is an error, tell us
	} 
	else 
	{
		formText = requete.text; //here we return the data our PHP told us
		requete.Dispose(); //clear our form in game
		if(formText!=""&formText!="passno"&formText!="loginno")
		{
			idBDDtemp = int.Parse(formText);
			localidbdd=0;
			networkView.RPC("MajPlayer", RPCMode.AllBuffered, idBDDtemp);
			isIdentified=true;
			
		}
		else if(formText=="passno")
		{
			messErreurConnex = "Mauvais mot de passe";
		}
		else if(formText=="loginno")
		{
			messErreurConnex = "Utilisateur inconnu";
		}			
			
	}

	login = ""; //just clean our variables
	formPassword = "";	
}

@RPC
function MajPlayer (idbdd : int) {
	if (Network.isServer)
	{
		localidbdd = idbdd;
	}
	else
	{
		if (localidbdd == 0)
		{
			localidbdd = idbdd;
		}

	}
	
}

@RPC
function GetNumPerso(id : int)
{	
	Debug.Log("fonction GetNumPerso");
	var form = new WWWForm(); //nouveau formulaire
	form.AddField( "myform_hash", hash );
	var idstr = id.ToString();
	form.AddField( "myform_id", idstr );
	var requete = WWW(scriptGetNumPerso, form); //creation de la requete que va envoyer unity à php (qui lui va se connecter a mysql)
		
	yield requete;	//yield return en c#
			
	if (requete.error != null) 
	{
		Debug.Log(requete.error); //if there is an error, tell us
	} 
	else 
	{
		formText = requete.text; //here we return the data our PHP told us
		requete.Dispose(); //clear our form in game
		if(formText!="")
		{
			var numPerso : int = int.Parse(formText);
			Debug.Log("on est dans GetNumPerso et on va lancer MajNumPerso");
			networkView.RPC("MajNumPerso", RPCMode.AllBuffered, numPerso);//pose soucis parce que du coup on écrase les infos chez tous les clients
		}
	}

	idstr = ""; //just clean our variables
	id = 0;
}

@RPC
function MajNumPerso(i : int) 
{
	if (Network.isServer)
	{
		num_personnage =i;
		Debug.Log("serveur : fonction MajNumPerso");
	}
	else
	{
		num_personnage =i;
		Debug.Log("client : fonction MajNumPerso");
	}

	
}	
	
// Receive server initialization, record own identifier as seen by the server.
// This is later used to recognize if a network spawned player is the local player.
// Also record assigned view IDs so the server can synch the player correctly.
@RPC
function InitPlayer (player : NetworkPlayer, tViewID : NetworkViewID, aViewID : NetworkViewID) {
	Debug.Log("Received player init "+ player +". ViewIDs " + tViewID + " and " + aViewID);
	localPlayer = player;
	localTransformViewID = tViewID;
	localAnimationViewID = aViewID;
}

// Send initalization info to the new player, before that he cannot spawn himself
function OnPlayerConnected (player : NetworkPlayer) {
	Debug.Log("Sending player init to "+player);
	var transformViewID : NetworkViewID = Network.AllocateViewID();
	var	animationViewID : NetworkViewID = Network.AllocateViewID();
	Debug.Log("Player given view IDs "+ transformViewID + " and " + animationViewID);
	networkView.RPC("InitPlayer", player, player, transformViewID, animationViewID);
}

function OnPlayerDisconnected (player : NetworkPlayer) {
	Debug.Log("Cleaning up player " + player);
	// Destroy the player object this network player spawned
	var deletePlayer : PlayerInfo;
	for (var playerInstance : PlayerInfo in playerInfo) {
		if (player == playerInstance.player) {
			Debug.Log("Destroying objects belonging to view ID " + playerInstance.transformViewID);
			Network.Destroy(playerInstance.transformViewID);
			deletePlayer = playerInstance;
		}
	}
	playerInfo.Remove(deletePlayer);
	Network.RemoveRPCs(player, 0);
	Network.DestroyPlayerObjects(player);
}