Can somone please fix this script

Is it possible for someone to to fix this mass tree placement script to work in newer versions of unity? (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 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
                );
        }
    }
}

What problems are you encountering with the current code?

It’s not really fair on us to dump hundreds of lines of C# into a post and say “fix it”

Sorry, there are a few errors…

Assets\MassTreePlacementEditor.cs(3,20): error CS0234: The type or namespace name ‘UnityEngine’ does not exist in the namespace ‘UnityContrib’ (are you missing an assembly reference?)

Assets\MassTreePlacementEditor1.cs(3,20): error CS0234: The type or namespace name ‘UnityEngine’ does not exist in the namespace ‘UnityContrib’ (are you missing an assembly reference?)

Assets\MassTreePlacementEditor1.cs(15,18): error CS0101: The namespace ‘UnityContrib.UnityEditor’ already contains a definition for ‘MassTreePlacementEditor’

Assets\MassTreePlacementEditor.cs(14,26): error CS0246: The type or namespace name ‘MassTreePlacement’ could not be found (are you missing a using directive or an assembly reference?)

Assets\MassTreePlacementEditor1.cs(13,6): error CS0579: Duplicate ‘CanEditMultipleObjects’ attribute

Assets\MassTreePlacementEditor.cs(65,62): error CS0246: The type or namespace name ‘MassTreePlacement’ could not be found (are you missing a using directive or an assembly reference?)

Assets\MassTreePlacementEditor1.cs(26,30): error CS0111: Type ‘MassTreePlacementEditor’ already defines a member called ‘OnInspectorGUI’ with the same parameter types

Assets\MassTreePlacementEditor1.cs(49,28): error CS0111: Type ‘MassTreePlacementEditor’ already defines a member called ‘Clear’ with the same parameter types

Assets\MassTreePlacementEditor1.cs(65,28): error CS0111: Type ‘MassTreePlacementEditor’ already defines a member called ‘PlaceRandomTrees’ with the same parameter types

Assets\MassTreePlacementEditor1.cs(137,29): error CS0111: Type ‘MassTreePlacementEditor’ already defines a member called ‘RecalculateTreePositions’ with the same parameter types

What is “MassTreePlacementEditor1.cs” and how is it different from “MassTreePlacementEditor.cs”

These are a pair of scripts that work together from here…

Script used to be in asset store

There is no script in that repo called “MassTreePlacementEditor1.cs”. I am pretty sure that you have accidentally duplicated MassTreePlacementEditor.cs, hence all the “duplicate” and “already contains a definition for” errors you are getting.

This script i was using in unity 5.6 no problem. i just upgraded to 2019 and these are errors it reports

Is there actually any difference between those scripts?

one is 7 kb large the other is 6. from what i can gather, the ‘editor’ script merely places a selection in the menu so i can access script from it.

What do you mean the “Editor” script? You have 2 editor scripts. I don’t think you understand what is happening with the files in your own project.

What you should have (and what you seem to think you have):

What you seem to actually have, at least as far as I can tell from your errors:

  1. Does your project actually contain a file called “MassTreePlacement.cs”?
  2. Does your project contain both a file called “MassTreePlacementEditor.cs” as well as a file called “MassTreePlacementEditor1.cs”?

i have two scripts, “MassTreePlacement.cs” and “MassTreePlacementEditor.cs”.

This is inconsistent with the error messages you posted, which reference a script called “MassTreePlacementEditor1.cs”

Assuming you are using source control (or at least have made a backup), try deleting the Library folder, and letting Unity rebuild it. It might take some time depending on the size of the project. Possibly something in there has gotten messed up somehow.

What file does your IDE open when you double click the error referencing the “MassTreePlacementEditor1.cs” script?

i noticed the “1” on the editor script and scratched my head. I have taken both scrpts from the github link I showed you and installed them in unity 2019 just now. Now, there is no access to the script either from "scripts’ in the menu on the top, or in the ‘terrain’ toggle under componant it would place. The script just doesnt show up even though if I open them in visual studio they show no errors or problems.

So you did have a “MassTreePlacementEditor1.cs” this whole time? I’m completely lost.

In a new project?

yep. Ive installed both scripts from github. now i get one error…

Assets\MassTreePlacement.cs(250,6): error CS1513: } expected

i looked it up and it says its missing a curly colon but i checked script and its exact from github

Thanks bud for pointing me in right direction. There is a missing colon on script on github page that stops it from loading in the componant menu, Fixed now, thx

I can almost guarantee you that you are mistaken and it is not.

I am glad to see that you got it working, but you need to pay closer attention to things in the future when dealing with scripts. There is absolutely no tolerance for errors, and a stray 1 or a missing } can stop the entire project from functioning.

your right. Its not working correctly. The scripts i got were from the github pages. There is some kind of error that only places trees at zero height. Im using the code. it allows me too now, and its placing trees but only at zero height no matter what settings are. Ive coppied code and made new scripts a couple times and am recieving this error…

MissingMethodException: UnityEngine.TerrainData.RecalculateTreePositions Due to: Attempted to access a missing member.
System.RuntimeType.InvokeMember (System.String name, System.Reflection.BindingFlags bindingFlags, System.Reflection.Binder binder, System.Object target, System.Object[ ] providedArgs, System.Reflection.ParameterModifier[ ] modifiers, System.Globalization.CultureInfo culture, System.String[ ] namedParams) (at :0)
System.Type.InvokeMember (System.String name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object target, System.Object[ ] args) (at :0)
UnityContrib.UnityEditor.MassTreePlacementEditor.RecalculateTreePositions (UnityEngine.TerrainData data) (at Assets/MassTreePlacementEditor.cs:139)

bob…no, i dont know where the “1” came up. I dont see it in either script or in the error code. Like I said, im using those two scripts on github. The scripts will load and it will place trees but only at zero height or rather no y axis.