Duplicating Terrain at run-time

Hello everyone,

I'm trying here, unsuccessfully, to duplicate terrains in real-time.

I have 2 GameObjects, named "Terrain00" and "Terrain01". Each of them have a Terrain object, created dynamically from resources I get from a socket stream. I want now to, at certain event in my application, to remove Terrain00 terrain (but keeping the GameObject) and duplicate, or move, the terrain inside Terrain01.

I managed to get a instance of each terrain, managed to make a copy of the terrain with Instantiate, and even managed to delete the terrain in Terrain00, but I didn't found a way so far to insert the copied terrain in Terrain00.... All I could do so far is to create a new blank terrain with GameObject.AddComponent.... I'm trying to avoid to create a new terrain in Terrain00 and then export everything to my new terrain, as terrainData, terrainCollider, and so on.

Is there any way to do this?

Eric is correct, but I too enjoy being lazy.

I am setting up my height map and my splat map via code. Therefore, all I really need is a shallow copy of all the TerrainData properties that I setup in the designer.

I threw together this prototype and tested that it works.

To my fellow lazy coders, enjoy:

// this is garbage test code, but you get the idea
public class TerrainSpawner : MonoBehaviour {

	public GameObject terrainPrefab;

	// Use this for initialization
	IEnumerator Start () {
	
		GameObject terrainGameObject = (GameObject) Instantiate (terrainPrefab, new Vector3 (-1000.0F, 0.0F, -1000.0F), terrainPrefab.transform.rotation);

		yield return new WaitForSeconds (5.0F);  // waiting for 5 seconds so I can watch it spawn the 2nd terrain in the scene view while it's running
		
		Terrain terrain = terrainPrefab.GetComponent<Terrain> ();
		TerrainData terrainData = new TerrainData ();
		CopyFrom (terrainData, terrain.terrainData);  // copy the basic getable/setable properties

		GameObject newTerrainGameObject = (GameObject) Instantiate (terrainPrefab, new Vector3 (-3000.0F, 0.0F, -1000.0F), terrainPrefab.transform.rotation);
		Terrain newTerrain = newTerrainGameObject.GetComponent<Terrain> ();
		newTerrain.terrainData = terrainData;
	}

	// previously an extension method
	public static void CopyFrom<T1, T2>(T1 obj, T2 otherObject)
		where T1: class
		where T2: class
	{
		PropertyInfo[] srcFields = otherObject.GetType().GetProperties(
			BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
		
		PropertyInfo[] destFields = obj.GetType().GetProperties(
			BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty);
		
		foreach (var property in srcFields) {
			var dest = destFields.FirstOrDefault(x => x.Name == property.Name);
			if (dest != null && dest.CanWrite)
				dest.SetValue(obj, property.GetValue(otherObject, null), null);
		}
	}
}

There's no point trying to avoid copying everything over, because that's what you have to do. There isn't a Terrain.Copy function, but you can make one yourself fairly easily. (Terrain.CreateTerrainGameObject just links to an existing TerrainData, so it's not helpful here.)