can someone fix this script

Can someone fix this mass tree placement script so it will work on newer unity versions (e.g. 2019 etc)

using UnityEngine;

namespace UnityContrib.UnityEngine
{
    /// <summary>
    /// Values for placing random trees.
    /// </summary>
    /// <remarks>
    /// <see cref="T:UnityContrib.UnityEditor.MassTreePlacementEditor"/> does the actual work.
    /// </remarks>
    [AddComponentMenu("Terrain/Mass Tree Placement")]
    [RequireComponent(typeof(Terrain))]
    public class MassTreePlacement : MonoBehaviour
    {
#pragma warning disable 0414 // The field 'XYZ' is assigned but never used

        /// <summary>
        /// The number of trees to place.
        /// </summary>
        [Tooltip("The number of trees to place.")]
        [SerializeField]
        private int count = 70000;

        /// <summary>
        /// The lowest point to position a tree.
        /// </summary>
        [Tooltip("The lowest point to position a tree.")]
        [SerializeField]
        private float minWorldY = 1.0f;

        /// <summary>
        /// The highest point to position a tree.
        /// </summary>
        [Tooltip("The highest point to position a tree.")]
        [SerializeField]
        private float maxWorldY = 5200.0f;

        /// <summary>
        /// The minimum allowed slope of the ground to position a tree.
        /// </summary>
        [Tooltip("The minimum allowed slope of the ground to position a tree.")]
        [SerializeField]
        private float minSlope = 0.0f;

        /// <summary>
        /// The maximum allowed slope of the ground to position a tree.
        /// </summary>
        [Tooltip("The maximum allowed slope of the ground to position a tree.")]
        [SerializeField]
        private float maxSlope = 40.0f;

        /// <summary>
        /// The minimum value to scale the width of a tree.
        /// </summary>
        [Tooltip("The minimum value to scale the width of a tree.")]
        [SerializeField]
        private float minWidthScale = 0.9f;

        /// <summary>
        /// The maximum value to scale the width of a tree.
        /// </summary>
        [Tooltip("The maximum value to scale the width of a tree.")]
        [SerializeField]
        private float maxWidthScale = 2.0f;

        /// <summary>
        /// The minimum value to scale the height of a tree.
        /// </summary>
        [Tooltip("The minimum value to scale the height of a tree.")]
        [SerializeField]
        private float minHeightScale = 0.8f;

        /// <summary>
        /// The maximum value to scale the height of a tree.
        /// </summary>
        [Tooltip("The maximum value to scale the height of a tree.")]
        [SerializeField]
        private float maxHeightScale = 3.5f;

        /// <summary>
        /// The maximum number of seconds for the placement process to take.
        /// The process is aborted if it takes any longer.
        /// </summary>
        [Tooltip("The maximum number of seconds for the placement process to take. The process is aborted if it takes any longer.")]
        [SerializeField]
        private double maxTime = 30.0d;

#pragma warning restore 0414 // The field 'XYZ' is assigned but never used

        /// <summary>
        /// Gets or sets the number of trees to place.
        /// </summary>
        public int Count
        {
            get
            {
                return count;
            }

            set
            {
                count = value;
            }
        }

        /// <summary>
        /// Gets or sets the lowest point to position a tree.
        /// </summary>
        public float MinWorldY
        {
            get
            {
                return minWorldY;
            }

            set
            {
                minWorldY = value;
            }
        }

        /// <summary>
        /// Gets or sets the highest point to position a tree.
        /// </summary>
        public float MaxWorldY
        {
            get
            {
                return maxWorldY;
            }

            set
            {
                maxWorldY = value;
            }
        }

        /// <summary>
        /// Gets or sets the minimum allowed slope of the ground to position a tree.
        /// </summary>
        public float MinSlope
        {
            get
            {
                return minSlope;
            }

            set
            {
                minSlope = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum allowed slope of the ground to position a tree.
        /// </summary>
        public float MaxSlope
        {
            get
            {
                return maxSlope;
            }

            set
            {
                maxSlope = value;
            }
        }

        /// <summary>
        /// Gets or sets the minimum value to scale the width of a tree.
        /// </summary>
        public float MinWidthScale
        {
            get
            {
                return minWidthScale;
            }

            set
            {
                minWidthScale = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum value to scale the width of a tree.
        /// </summary>
        public float MaxWidthScale
        {
            get
            {
                return maxWidthScale;
            }

            set
            {
                maxWidthScale = value;
            }
        }

        /// <summary>
        /// Gets or sets the minimum value to scale the height of a tree.
        /// </summary>
        public float MinHeightScale
        {
            get
            {
                return minHeightScale;
            }

            set
            {
                minHeightScale = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum value to scale the height of a tree.
        /// </summary>
        public float MaxHeightScale
        {
            get
            {
                return maxHeightScale;
            }

            set
            {
                maxHeightScale = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum number of seconds for the placement process to take.
        /// The process is aborted if it takes any longer.
        /// </summary>
        public double MaxTime
        {
            get
            {
                return maxTime;
            }

            set
            {
                maxTime = value;
            }
        }
    }
}

and this is for the editor…

using System;
using System.Reflection;
using UnityContrib.UnityEngine;
using UnityEditor;
using UnityEngine;
using Random = UnityEngine.Random;

namespace UnityContrib.UnityEditor
{
    /// <summary>
    /// Places random trees on a terrain.
    /// </summary>
    [CanEditMultipleObjects]
    [CustomEditor(typeof(MassTreePlacement))]
    public class MassTreePlacementEditor : Editor
    {
        /// <summary>
        /// Reference to the <see cref="T:UnityEngine.TerrainData"/> type
        /// for later invocation using reflection.
        /// </summary>
        private static readonly Type terrainDataType = typeof(TerrainData);

        /// <summary>
        /// Draws the "Place" and "Clear" buttons.
        /// </summary>
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var mtp = this.target as MassTreePlacement;
            var terrain = mtp.GetComponent<Terrain>();

            if (GUILayout.Button("Place"))
            {
                PlaceRandomTrees(terrain, mtp);
            }
            if (GUILayout.Button("Clear"))
            {
                Clear(terrain);
            }
        }

        /// <summary>
        /// Clears the terrain of all trees.
        /// </summary>
        /// <param name="terrain">
        /// The terrain who's trees to remove.
        /// </param>
        public static void Clear(Terrain terrain)
        {
            terrain.terrainData.treeInstances = new TreeInstance[0];
            RecalculateTreePositions(terrain.terrainData);
            terrain.Flush();
        }

        /// <summary>
        /// Places random trees on the terrain.
        /// </summary>
        /// <param name="terrain">
        /// The terrain to place trees on.
        /// </param>
        /// <param name="mtp">
        /// The settings for the tree placement.
        /// </param>
        public static void PlaceRandomTrees(Terrain terrain, MassTreePlacement mtp)
        {
            var data = terrain.terrainData;

            var num = data.treePrototypes.Length;
            if (num == 0)
            {
                Debug.LogWarning("Can't place trees because no prototypes are defined. Process aborted.");
                return;
            }

            Undo.RegisterCompleteObjectUndo(data, "Mass Place Trees");

            var start = DateTime.Now;

            var array = new TreeInstance[mtp.Count];
            var i = 0;
            while (i < array.Length)
            {
                // stop if process have run for over X seconds
                var delta = DateTime.Now - start;
                if (delta.TotalSeconds >= mtp.MaxTime)
                {
                    Debug.LogWarning("Process was taking too much time to run");
                    return;
                }

                var position = new Vector3(Random.value, 0.0f, Random.value);

                // don't allow placement of trees below minWorldY and above maxWorldY
                var y = data.GetInterpolatedHeight(position.x, position.z);
                var worldY = y + terrain.transform.position.y;
                if (worldY < mtp.MinWorldY || worldY > mtp.MaxWorldY)
                {
                    continue;
                }

                // don't allow placement of trees on surfaces flatter than minSlope and steeper than maxSlope
                var steepness = data.GetSteepness(position.x, position.z);
                if (steepness < mtp.MinSlope || steepness > mtp.MaxSlope)
                {
                    continue;
                }

                var color = Color.Lerp(Color.white, Color.gray * 0.7f, Random.value);
                color.a = 1f;

                var treeInstance = default(TreeInstance);
                treeInstance.position = position;
                treeInstance.color = color;
                treeInstance.lightmapColor = Color.white;
                treeInstance.prototypeIndex = Random.Range(0, num);
                treeInstance.widthScale = Random.Range(mtp.MinWidthScale, mtp.MaxWidthScale);
                treeInstance.heightScale = Random.Range(mtp.MinHeightScale, mtp.MaxHeightScale);
                array[i] = treeInstance;
                i++;
            }
            data.treeInstances = array;
            RecalculateTreePositions(data);
            terrain.Flush();
        }

        /// <summary>
        /// Invokes <see cref="M:UnityEngine.TerrainData.RecalculateTreePositions"/> using reflection.
        /// </summary>
        /// <param name="data">
        /// The instance to invoke the method on.
        /// </param>
        /// <remarks>
        /// Some say it is enough to simply call <see cref="M:UnityEngine.Terrain.Flush"/>
        /// however I'm not sure what the difference is, so I'm calling this just to be on the safe side.
        /// </remarks>
        private static void RecalculateTreePositions(TerrainData data)
        {
            terrainDataType.InvokeMember(
                "RecalculateTreePositions",
                BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
                null,
                data,
                null
                );
        }
    }
}

This is NOT a support forum.

Please post your question in relevant forum section.
Scripting
with properly described problem.
That is including any error messages and what doesn’t work.

1 Like

Never use code that has this high comment to code ratio, its a code smell

Moved to Scripting.

1 Like