11
\$\begingroup\$

When you create a script via the Unity editor, it generates a script with some pre-formatted code.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericClass : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}

When I create a script, I am generally guaranteed to use additional code, such as a namespace or a custom editor. Furthermore, I almost always delete content from the automatically-generated script. Is there a way to change the automatic code generated by Unity?

\$\endgroup\$
  • 1
    \$\begingroup\$ I never even thought about doing this. Thanks for asking! Now to combine the two answers to have a template and then parse it to insert extra information, like namespace... \$\endgroup\$ – Draco18s May 17 '17 at 15:25
4
\$\begingroup\$

In addition you can also

  1. Add an editor script in Assets/Editor folder that subscribes to OnWillCreateAsset where you can parse the output and modify it. For example script that would automatically insert namespace could look like following:

    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    
    using UnityEditor;
    
    public class InsertNS : UnityEditor.AssetModificationProcessor
    {
        public static void OnWillCreateAsset(string path)
        {
            string assetPath = Regex.Replace(path, @".meta$", string.Empty);
            if (!assetPath.EndsWith(".cs")) return;
    
            var code = File.ReadAllLines(assetPath).ToList();
            if (code.Any(line => line.Contains("namespace"))) return;//already added by IDE
    
            //insert namespace
            int idx = code.FindIndex(line => line
                .Contains("class " + Path.GetFileNameWithoutExtension(assetPath)));
            code.Insert(idx, Regex.Replace(
            assetPath.Replace('/','.'), @"^([\w+.]+)\.\w+\.cs$", "namespace $1 {\n"));
            code.Add("}");
    
            //correct indentation
            for (int i = idx + 1; i < code.Count - 1; i++) code[i] = '\t' + code[i];
    
            var finalCode = string.Join("\n", code.ToArray());
            File.WriteAllText(assetPath, finalCode);
            AssetDatabase.Refresh();
        }
    }
    
  2. Insert own control sequences into templates for easy replacing in OnWillCreateAsset, e.g.

    finalCode = finalCode.Replace(@"#date#", DateTime.Now);
    
  3. Add more templates to the template folder, for example one for Singleton pattern - Unity is not limited to single script template.

  4. The visual studio code snippets are way to customizing creating new scripts (...and even further - new script parts). For example, a code snippet for private SerializeField might come in handy. After importing privateField.snippet:

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <Title>
            Serialized private field
          </Title>
          <Author>Myself</Author>
          <Description>Adds private serializable field visible to Unity editor</Description>
          <Shortcut>pf</Shortcut>
        </Header>
        <Snippet>
          <Imports>
            <Import>
              <Namespace>UnityEngine</Namespace>
            </Import>
          </Imports>
          <Declarations>
            <Literal>
              <ID>FieldName</ID>
              <ToolTip>Replace with field name.</ToolTip>
              <Default>myField</Default>
            </Literal>
          </Declarations>
          <Code Language="CSharp">
            <![CDATA[[SerializeField] float _$FieldName$;]]>
          </Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>
    

    to Tools/Code Snippet Manager/My Code Snippets you can just type "pf" double tab and type the field's name. E.g.:

    //"pf" tab tab "speed" produces
    [SerializeField] float _speed;
    

    Even more convenient would be snippets for often repeated longer sequences, e.g. readonly property backed by SerializeField field.

  5. Visual studio also offer very powerful code generation tool, the T4 Text Templates(EF is using T4), though I personally find the practical use for Unity projects doubtful - they are overkill, quite complicated and the compilation of project would likely become dependent on Visual Studio.

\$\endgroup\$
  • \$\begingroup\$ This has worked like a charm! I have added relevant namespaces for future users. I also had one more problem, though I think it might be one unique to me; I can not use Path.GetFileWithoutExtension. It tells me it is trying to access a MonoBehaviour, which seems odd. I include the namespace using Path = System.IO.Path.GetFileWithoutExtension, and I lose Path all together. In the end, I had to fully fledge the line, itself (.Contains("class " + System.IO.Path.GetFileNameWithoutExtension(assetPath)));). \$\endgroup\$ – Gnemlock May 19 '17 at 2:45
  • \$\begingroup\$ What's the simplest way to ensure files are created with LF and UTF-8 rather than CRLF and UTF-8 with BOM? \$\endgroup\$ – Aaron Franke Jun 28 at 18:07
  • \$\begingroup\$ @AaronFranke well... thats rather specific request. I would try asking on stackoverflow.com how to make string/File.Write output LF-only with BOM. As far as I know '\n' should be just LF, you can also try Environment.Newline instead but it should be CRLF. There might also an option to use git hooks if everything else fails. BOM should be easy with this stackoverflow question. \$\endgroup\$ – wondra Jun 30 at 9:07
15
\$\begingroup\$

You can find the script templates for automatically generating code in your Unity installation folder. I find the templates under "Unity/Editor/Data/Resources/ScriptTemplates", while other sources have found it under "Unity/Editor/Data/Resources".

The generic UnityScript and C# templates are identified as the files "82-Javascript-NewBehaviourScript.js.txt" and "81-C# Script-NewBehaviourScript.cs.txt", respectively. You can directly edit these files to change the way in which Unity auto generates script.

You can also include additional templates, which will appear when you select "Create" from the "Project" window. Templates do not appear to require unique numbering, and use the initial string to determine the menu hierarchy, where "__" denotes a submenu. For example, having a file named "81-C# Script__Editor Script-NewBehaviourScript.cs.txt" will give you an additional "C# Script" menu, with the sub option to create an "Editor Script" using this template.

Do not rename the original templates; these are used more directly, by the engine. For example, renaming "81-C# Script-NewBehaviourScript.cs.txt" will prevent you from adding new C# scripts as components, directly through the inspector.


Below is my own example, though it demonstrates particular practices that I am most custom to. For example, I prefer to have my custom editor script in the same file as the target class, so I encapsulate it in #if UNITY_EDITOR .. #endif, instead of placing it in a generic "do not compile in build" editor folder.

I am not sure if it is even possible to provide the context of a custom namespace; I simply use "NAMESPACE", as this allows me to provide the correct namespace post-creation, using the commonly-inbuilt "find..replace all" function.


The Template:

/* Created by Gnemlock */

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace NAMESPACE
{
    public class #SCRIPTNAME# : MonoBehaviour 
    {
        /// <summary>This method will be called at the start of each frame where this 
        /// instance of <see cref="NAMESPACE.#SCRIPTNAME#"/> is enabled.</summary>
        void Update ()
        {
            #NOTRIM#
        }
    }
}

namespace NAMESPACE.UTILITY
{
    #if UNITY_EDITOR
    [CustomEditor(typeof(#SCRIPTNAME#))] public class #SCRIPTNAME#Editor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            #SCRIPTNAME# s#SCRIPTNAME# = target as #SCRIPTNAME#;
        }
    }
    #endif
}

The Output:

/* Created by Gnemlock */

using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace MyNamespace
{

    public class UpdatedClass : MonoBehaviour 
    {
        /// <summary>This method will be called at the start of each frame where this 
        /// instance of <see cref="MyNamespace.UpdatedClass"/> is enabled.</summary>
        void Update ()
        {

        }
    }
}

namespace MyNamespace.UTILITY
{
    #if UNITY_EDITOR
    [CustomEditor(typeof(UpdatedClass))] public class UpdatedClassEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            DrawDefaultInspector();

            UpdatedClass sUpdatedClass = target as UpdatedClass;
        }
    }
    #endif
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.