Ejemplo n.º 1
0
        /// <summary>
        /// Creates the new type of the variable based on the given parameters.
        /// After getting all of the correct templates, they will be copied
        /// into the folder specified by targetPath.
        ///
        /// Some templates must be placed in an Editor folder. If one does not
        /// exist, one might be created. However, this function will avoid
        /// overwriting files. Once it is done, it will refresh the project.
        ///
        /// Note that not all of the listen exceptions may get thrown. There
        /// are others which may get thrown by the file IO methods.
        /// </summary>
        ///
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Thrown if any of the arguments are invalid. (See each argument
        /// for details.)
        /// </exception>
        ///
        /// <exception cref="System.IO.DirectoryNotFoundException">
        /// If the targetPath is invalid.
        /// </exception>
        ///
        /// <exception cref="System.IO.IOException">
        /// Thrown if the Editor folder cannot be created. Also thrown if any
        /// of the files we run into a pre-existing file.
        /// </exception>
        ///
        /// <param name="metaData">
        /// All of the data to use for the new scripts.
        ///
        /// metaData.name: Must be a legal C# name, and must be legal
        /// when used as a filename. The first character should be uppercase.
        /// If any of the checks fail or if the name is already taken
        /// by another variable object, then an ArgumentOutOfRangeException is
        /// thrown.
        ///
        /// metaData.type: The name of the pre-existing C# type to be represtented. If
        /// the string fails the checks, then an ArgumentOutOfRangeException is thrown.
        ///
        /// metaData.ParsedReferability: Whether the C# type refered to by typeName is
        /// a class or a struct. If ReferabilityMode.Unknown is passed,
        /// ArgumentOutOfRangeException is thrown.
        /// </param>
        ///
        /// <param name="targetPath">
        /// Path used when attempting to create the new files. If this isn't a
        /// valid path, a DirectoryNotFoundException is thrown. If the
        /// target folder is nested in an Editor folder (or is an Editor folder
        /// itself), a ArgumentOutOfRangeException is thrown instead.
        /// </param>
        ///
        /// <param name="overrideExisting">
        /// If true, this will NOT check for scripts which already exist, and will
        /// happilly override whatever it finds. This will NOT change GUIDs.
        /// </param>
        ///
        /// <returns>A list of all the files created.</returns>
        public static List <string> CreateNewVariableType(
            ScriptMetaData metaData,
            string targetPath,
            bool overrideExisting = false
            )
        {
            // This is the path of the editor folder we'll use to dump our
            // editor scripts into.
            string editorPath = UnityPathUtils.GetEditorFolder(targetPath);

            #region Error checking
            if (!IsValidName(metaData.name))
            {
                throw new System.ArgumentOutOfRangeException(
                          "readableName",
                          "Either contains invalid characters or could conflict with" +
                          " a C# keyword."
                          );
            }
            else if (ScriptSetManager.IsNameTaken(metaData.name) && !overrideExisting)
            {
                throw new System.ArgumentOutOfRangeException(
                          "readableName",
                          "Is already taken by another VariableObject type."
                          );
            }
            else if (!IsValidName(metaData.type))
            {
                throw new System.ArgumentOutOfRangeException(
                          "typeName",
                          "Either contains invalid characters or could conflict with" +
                          " a C# keyword."
                          );
            }
            else if (metaData.ParsedReferability == ReferabilityMode.Unknown)
            {
                throw new System.ArgumentOutOfRangeException(
                          "referability",
                          "Must be something other than ReferabilityMode.unknown."
                          );
            }
            else if (!AssetDatabase.IsValidFolder(targetPath) && !Directory.Exists(targetPath))
            {
                // TODO This seems mildly buggy on Windows. I created a folder
                //      inside the folder-select prompt and it complained about
                //      it. Maybe, instead of using AssetDatabase, we should use
                //      normal C# checks?
                throw new DirectoryNotFoundException(
                          "targetPath must be pointing to a pre-existing folder. If" +
                          " you want to create a new folder to put the scripts in," +
                          " you must do it before calling CreateNewVariableType." +
                          "(Trying to use: " + targetPath + ")"
                          );
            }
            else if (UnityPathUtils.IsInEditorAssembly(targetPath))
            {
                // If we tried putting all of our scripts in an Editor folder,
                // it would be mostly pointless because then we cannot use our
                // variable objects in the final build.
                throw new System.ArgumentOutOfRangeException(
                          "targetPath",
                          "Must not be nested in an Editor folder."
                          );
            }
            else if (File.Exists(editorPath) && !AssetDatabase.IsValidFolder(editorPath))
            {
                throw new IOException(
                          editorPath + " exists as a file, so we cannot make a folder there!"
                          );
            }
            #endregion



            /*
             * At this point, everything is valid. Barring some kind of error
             * when writting to the disk, everything should be good to go.
             *
             * The only thing we are not going to check is if the files already
             * exist. We could check this before-hand, but this makes it a bit
             * more complex overall. We don't even gain very much in doing this;
             * we still need to handle an exception thrown by the file-writing
             * code, which may require cleaning up files.
             *
             * We shall build a list (see newFIlePaths, below) of all of the
             * files which we create. That way, we can delete them if something
             * goes wrong.
             *
             *
             * Until calling AssetDatabase.Refresh in the finally block,
             * we cannot rely on Unity's AssetDatabase class without risking
             * the stability of Unity.
             *
             * If Unity begins a refresh (on its own accord), this process
             * occurs asynchroniously. In other words, it may start refreshing
             * right in the middle of this function execution.
             *
             * This is normally okay, but if we catch an exception, we need
             * to delete all of the files we created. Deleting files during a
             * refresh is risky, and may lead to errors and even lock up
             * Unity's reloading mechanisms, halting the Unity Editor.
             *
             * Fortunately, C# has enough tools to get the job done. Still,
             * it's a bit less robust than using the AssetDatabase. Also, we
             * cannot set labels until the very end of the process.
             *
             * (Again, we can't just check ahead of time. There's always risk
             * of an exception getting thrown while doing file IO.)
             */


            // Used to track the new files we add so that we can clean them up
            // if necessary. This is a stack so that the first most recent
            // things we create get deleted first.
            Stack <string> newFilePaths = new Stack <string>();

            try {
                // It's still possible that the editor folder doesn't exist.
                // However, we are sure that there isn't a file with that name,
                // so we can go ahead and create it if necessary.
                //
                // Note that we're doing this BEFORE locking the assemblies so
                // we can still use the AssetDatabase class.
                if (!AssetDatabase.IsValidFolder(editorPath))
                {
                    editorPath = AssetDatabase.GUIDToAssetPath(
                        AssetDatabase.CreateFolder(targetPath, "Editor")
                        );

                    // We've created the folder, so it's one of the things
                    // we'll want to clean up if things go wrong.
                    newFilePaths.Push(editorPath);
                }


                EditorApplication.LockReloadAssemblies();

                foreach (TemplateInfo template in TemplateFileManager.Templates)
                {
                    string newScriptPath = CreateScriptFromTemplate(
                        metaData, template, targetPath, editorPath, overrideExisting
                        );

                    // CreateScriptFromTemplate CAN return an empty string if
                    // it chooses not to create a script, so we have to watch for this.
                    if (!string.IsNullOrEmpty(newScriptPath))
                    {
                        newFilePaths.Push(newScriptPath);
                    }
                }         // End foreach(TemplateInfo template in Files.Templates)
            }             // End try
            catch (System.Exception e) {
                foreach (string path in newFilePaths)
                {
                    if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
                    {
                        Directory.Delete(path);

                        // Possible Unity created a meta file already.
                        if (File.Exists(path + ".meta"))
                        {
                            File.Delete(path + ".meta");
                        }
                    }
                    else
                    {
                        File.Delete(path);
                    }
                }

                throw e;
            }
            finally {
                EditorApplication.UnlockReloadAssemblies();
                AssetDatabase.Refresh();
            }

            string label = metaData.builtin ? ScriptSetManager.UnityLabel : ScriptSetManager.CustomLabel;
            SetFileLabels(newFilePaths.ToArray(), label);

            return(new List <string>(newFilePaths));
        }         // End CreateNewVariableType
Ejemplo n.º 2
0
        private void OnWizardUpdate()
        {
            string errorMsg = "";
            string helpMsg  = "";

            bool validName = false;
            bool validType = false;

            // We need to check for null, because the string is occasionally
            // null upon wizard's creation
            if (string.IsNullOrEmpty(humanReadableName))
            {
                helpMsg += "Please enter the Human Readable Name.";
            }
            else if (!VariableTypeBuilder.IsValidName(humanReadableName))
            {
                errorMsg +=
                    "The Human Readable Name is not a valid C# variable" +
                    " name!\n";
            }
            else if (ScriptSetManager.IsNameTaken(humanReadableName) &&
                     !(InEditMode && humanReadableName == editTarget.Name)
                     )
            {
                errorMsg +=
                    "The Human Readable Name conflicts with another," +
                    " already existing variable type!\n";
            }
            else
            {
                validName = true;
            }

            helpMsg += '\n';                    // Force push the next line into a blank field.


            if (string.IsNullOrEmpty(dataType))
            {
                helpMsg += "Please enter the Data Type.";
            }
            else if (!VariableTypeBuilder.IsValidName(dataType))
            {
                errorMsg += "The Data Type is not a valid C# variable name!";
            }
            else
            {
                validType = true;
            }


            helpMsg += '\n';                    // Force push the next line into a blank field.


            if (referability == ReferabilityMode.Unknown)
            {
                helpMsg += "Please choose a referability mode.";
            }


            // We use Trim here because having extra newlines looks ugly.
            errorString = errorMsg.Trim();
            helpString  = helpMsg;

            isValid = (
                validName &&
                validType &&
                referability != ReferabilityMode.Unknown
                );
        }