MP randomly generated levels, other player see's a different one than server host?

Like the title says, I just added a Mp mode to my game. It works, but the only thing tis that levels are randomly generated so now each player sees a different world. Here’s my generation script:

using System.Collections;

public class LevelGenMP : MonoBehaviour {

	public int MaxObjects;
	public int MaxRange;
	public GameObject[] Objects;
	public Vector3[] VObjects;
	
	
	// Use this for initialization
	void Start () {
	}
	
	void StartingServer(){
		if(Network.isServer){
            if(PlayerPrefs.GetString("World Size") == "Small"){
		        for(int i = 0; i < 35; i++){
	                //Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-MaxRange, MaxRange), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);
			        GameObject newThing = (GameObject) GameObject.Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-150, 150), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);
		            newThing.transform.parent = this.transform;
					VObjects *= newThing.transform.position;* 
  •      }*
    
  •  }*
    
  •  if(PlayerPrefs.GetString("World Size") == "Medium"){*
    
  •       for(int i = 0; i < 70; i++){*
    
  •           //Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-MaxRange, MaxRange), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);*
    
  •  	     GameObject newThing = (GameObject) GameObject.Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-250, 250), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);*
    
  •           newThing.transform.parent = this.transform;*
    

_ VObjects = newThing.transform.position;_
* }*
* }*

* if(PlayerPrefs.GetString(“World Size”) == “Large”){*
* for(int i = 0; i < 70; i++){*
* //Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-MaxRange, MaxRange), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);*
* GameObject newThing = (GameObject) GameObject.Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-250, 250), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);*
* newThing.transform.parent = this.transform;*
_ VObjects = newThing.transform.position;
* }
}else{
for(int i = 0; i < 35; i++){
//Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-MaxRange, MaxRange), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);
GameObject newThing = (GameObject) GameObject.Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(Random.Range(-150, 150), this.transform.position.y, Random.Range(-MaxRange, MaxRange)), Quaternion.identity);
newThing.transform.parent = this.transform;
VObjects = newThing.transform.position;
}
}
}*_

* if(Network.isClient){*
* SetLevelFromMaster(VObjects);*
* }*
* }*

[RPC]
void SetLevelFromMaster(Vector3[] Positions){
* for(int i = 0; i < 35; i++){*
GameObject newThing = (GameObject) GameObject.Instantiate(Objects[Random.Range(0, Objects.Length - 1)], new Vector3(VObjects.x, VObjects_.y, VObjects*.z), Quaternion.identity);
newThing.transform.parent = this.transform;
}
}*_

}
Here’s the connection code(direct connect code)
using UnityEngine;
using System.Collections;

public class ConnectionGUI : MonoBehaviour {

public string remoteIP= “127.0f.0.1f”;
public int remotePort= 25000;
public int listenPort= 25000;
public bool useNAT= true;
public string yourIP= “”;
public string yourPort= “”;
public GameObject Level;

void Awake (){
Level = GameObject.Find(“level”);
if (FindObjectOfType(typeof(MasterServerGUI))){
this.enabled = false;
}

if(FindObjectOfType(typeof(UDPConnectionGUI)))
this.enabled = false;
}

void OnGUI (){
if (Network.peerType == NetworkPeerType.Disconnected){
// If not connected
if (GUI.Button (new Rect(10,10,100,30),“Connect”))
{
// Connecting to the server
Network.Connect(remoteIP, remotePort);
Level.SendMessage(“StartingServer”);
Debug.Log("Server = " + Network.isServer + " Client = " + Network.isClient);

}

if (GUI.Button (new Rect(10,50,100,30),“Start Server”)){
// Creating server
Network.InitializeServer(8 ,listenPort, false);

// Notify our objects that the level and the network is ready
foreach (GameObject go in FindObjectsOfType(typeof(GameObject))){
go.SendMessage(“OnNetworkLoadedLevel”, SendMessageOptions.DontRequireReceiver);
}
* Level.SendMessage(“StartingServer”);*
* Debug.Log("Server = " + Network.isServer + " Client = " + Network.isClient);*
}

remoteIP = GUI.TextField(new Rect(120,10,100,20),remoteIP);
remotePort = int.Parse(GUI.TextField(new Rect(230,10,40,20),remotePort.ToString()));

}else{

// If connected
// Getting your ip address and port
yourIP = Network.player.ipAddress;
yourPort = Network.player.port.ToString();

GUI.Label(new Rect(140,20,250,40),“IP Adress: “+yourIP+”:”+yourPort);
if (GUI.Button (new Rect(10,10,100,50),“Disconnect”)){
// Disconnect from the server
Network.Disconnect(200);
}
}
}

void OnConnectedToServer (){
// Notify our objects that the level and the network is ready
foreach (GameObject go in FindObjectsOfType(typeof(GameObject)))
go.SendMessage(“OnNetworkLoadedLevel”,
SendMessageOptions.DontRequireReceiver);
}
void OnDisconnectedFromServer (){
if (this.enabled != false)
Application.LoadLevel(Application.loadedLevel);
else{
//NetworkLevelLoad _NetworkLevelLoad = FindObjectOfType(typeof(NetworkLevelLoad));
NetworkLevelLoad _NetworkLevelLoad = FindObjectOfType(typeof(NetworkLevelLoad)) as NetworkLevelLoad;
_NetworkLevelLoad.OnDisconnectedFromServer();
}
}

}

and here’s the game:
_*https://dl.dropbox.com/u/85846965/OGAM/january/Webplayer/Webplayer.html*_

Okay. Now, did you try copying the generated level from the host to the clients?

How would I do that? Sorry, just getting into networking.

2 Answers

2

I would think you should be sending a seed for the random generator function, instead of the coordinate of each game object. Since the random functions are basically PRNG which requires an initial seed. This would reduce the network traffic across your clients.

Unity Random Seed

http://gamedev.stackexchange.com/questions/46993/transmit-map-vs-transmit-seed

Use of random seed

What I'm wondering is: 1. How would I use this for the instiate code 2. How would I send the seed to the client from the server

1. All that's saying is that you need to set your random seed before you generate, and send that same seed across. int seed = Random.Range(1, 999999999); Random.seed = seed; 2. By using an RPC call as is demonstrated immediately below this comment, and having a NetworkView attached to the Game Object that you're sending RPCs across to. You'd just send your seed instead of an array of Vec3s. http://docs.unity3d.com/Documentation/Components/net-UnityNetworkElements.html http://docs.unity3d.com/Documentation/Components/net-RPCDetails.html

Tried it, but I need to store the x and position of each object so I'll stick with vector3. Other answer is so close, it's just that the client has a separate script than the server host, making all the vector3 positions 0,0,0. How would I make them share the same script instead?

Scroll down just slightly and it should smack you in the face. if (Network.isServer)...

You’re going to need the server to communicate the placement of objects to it’s clients. I imagine the best way to do this in your case is to cache and send an array of Vector3s to connecting clients. Once they receive them then you can build the level according to the master’s ‘blueprint’.

[RPC]
void SetLevelFromMaster(Vector3[] positions)
{
    foreach (Vector3 v in positions)
    {
        //Instantiate GOs just as your above code shows.
    }
}

If you have several different types of blocks then it’s best to have an enumeration or other index schema that you can use to refer to each one as and send it in the call as an int. Hope that works for ya!

How would I go about only running the generation code for the server host? I'm thinking I do that then use this to generate the level for connecting players.

Wow! You mentioned your game was working, so I assumed that you'd already conquered this step. If you're using Unity Networking the check is 'Network.isServer'. if (Network.isServer) { // do server stuff } else { // do client stuff } EDIT: And you're right; you want the server to generate the level first and provide it to the clients. You should implement a hook for clients to request it from the Server as well as a method that the Clients listen to, as these calls are executed only on the target machine.

new to networking, mostly followed a tutorial. I'll try this when I get home

Was this not working already as a Network Game? I'm confused, because you said it was working. So...if you're converting a working game into a network game then you need to do several things; first of which is probably read a tutorial or download a networked project and look at example code. You need to initialize a server for Network.isServer to return true, e.g., Network.InitializeServer(8,8008, false);

it's working(posted code in the main post). It initializes the server using direct connect (but also dose the same on master server). Only thing is that the server player is now not generating the level at all for some reason. I'll try a few things once I get near my external harddrive