public void FindIncludedFiles()
 {
     includes.Clear();
     foreach (string includePath in includePaths)
     {
         string       localIncludePath     = InkEditorUtils.CombinePaths(Path.GetDirectoryName(inkFile.filePath), includePath);
         DefaultAsset includedInkFileAsset = AssetDatabase.LoadAssetAtPath <DefaultAsset>(localIncludePath);
         if (includedInkFileAsset == null)
         {
             Debug.LogError(inkFile.filePath + " expected child .ink asset at " + localIncludePath + " but file was not found.");
         }
         InkFile includedInkFile = InkLibrary.GetInkFileWithFile(includedInkFileAsset);
         if (includedInkFile == null)
         {
             Debug.LogError(inkFile.filePath + " expected child InkFile from .ink asset at " + localIncludePath + " but file was not found.");
         }
         else if (includedInkFile.metaInfo.includes.Contains(inkAsset))
         {
             Debug.LogError("Circular INCLUDE reference between " + inkFile.filePath + " and " + includedInkFile.metaInfo.inkFile.filePath + ".");
         }
         else
         {
             includes.Add(includedInkFileAsset);
         }
     }
 }
Esempio n. 2
0
 public void FindIncludedFiles(bool addMissing = false)
 {
     includes.Clear();
     foreach (string includePath in includePaths)
     {
         string localIncludePath = InkEditorUtils.CombinePaths(Path.GetDirectoryName(filePath), includePath);
         // This enables parsing ..\ and the like. Can we use Path.GetFullPath instead?
         var fullIncludePath = new FileInfo(localIncludePath).FullName;
         localIncludePath = InkEditorUtils.AbsoluteToUnityRelativePath(fullIncludePath);
         DefaultAsset includedInkFileAsset = AssetDatabase.LoadAssetAtPath <DefaultAsset>(localIncludePath);
         if (includedInkFileAsset == null)
         {
             Debug.LogError(filePath + " expected child .ink asset at '" + localIncludePath + "' but file was not found.", inkAsset);
         }
         else
         {
             InkFile includedInkFile = InkLibrary.GetInkFileWithFile(includedInkFileAsset, addMissing);
             if (includedInkFile == null)
             {
                 Debug.LogError(filePath + " expected child InkFile from .ink asset at '" + localIncludePath + "' but file was not found.", inkAsset);
             }
             else if (includedInkFile.includes.Contains(inkAsset))
             {
                 Debug.LogError("Circular INCLUDE reference between '" + filePath + "' and '" + includedInkFile.filePath + "'.", inkAsset);
             }
             else
             {
                 includes.Add(includedInkFileAsset);
             }
         }
     }
 }
Esempio n. 3
0
        void DrawEditAndCompileDates(InkFile masterInkFile)
        {
            string   editAndCompileDateString = "";
            DateTime lastEditDate             = File.GetLastWriteTime(inkFile.absoluteFilePath);

            editAndCompileDateString += "Last edit date " + lastEditDate.ToString();
            if (masterInkFile.jsonAsset != null)
            {
                DateTime lastCompileDate =
                    File.GetLastWriteTime(InkEditorUtils.CombinePaths(Application.dataPath, AssetDatabase.GetAssetPath(masterInkFile.jsonAsset).Substring(7)));
                editAndCompileDateString += "\nLast compile date " + lastCompileDate.ToString();
                if (lastEditDate > lastCompileDate)
                {
                    EditorGUILayout.HelpBox(editAndCompileDateString, MessageType.Warning);
                }
                else
                {
                    EditorGUILayout.HelpBox(editAndCompileDateString, MessageType.None);
                }
            }
            else
            {
                EditorGUILayout.HelpBox(editAndCompileDateString, MessageType.None);
            }
        }
        public static void CompileInk(InkFile inkFile)
        {
            if (inkFile == null)
            {
                Debug.LogError("Tried to compile ink file " + inkFile.filePath + ", but input was null.");
                return;
            }
            if (!inkFile.isMaster)
            {
                Debug.LogWarning("Compiling InkFile which is an include. Any file created is likely to be invalid. Did you mean to call CompileInk on inkFile.master?");
            }
            if (InkLibrary.GetCompilationStackItem(inkFile) != null)
            {
                UnityEngine.Debug.LogWarning("Tried compiling ink file, but file is already compiling. " + inkFile.filePath);
                return;
            }

            string inklecatePath = InkEditorUtils.GetInklecateFilePath();

            if (inklecatePath == null)
            {
                UnityEngine.Debug.LogWarning("Inklecate (the ink compiler) not found in assets. This will prevent automatic building of JSON TextAsset files from ink story files.");
                return;
            }
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                SetInklecateFilePermissions(inklecatePath);
            }

            string inputPath    = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileName(inkFile.filePath));
            string outputPath   = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileNameWithoutExtension(Path.GetFileName(inkFile.filePath))) + ".json";
            string inkArguments = "-c -o " + "\"" + outputPath + "\" \"" + inputPath + "\"";

            CompilationStackItem pendingFile = new CompilationStackItem();

            pendingFile.inkFile              = InkLibrary.GetInkFileWithAbsolutePath(inputPath);
            pendingFile.inkAbsoluteFilePath  = inputPath;
            pendingFile.jsonAbsoluteFilePath = outputPath;
            pendingFile.state = CompilationStackItem.State.Compiling;
            InkLibrary.Instance.compilationStack.Add(pendingFile);

            Process process = new Process();

            process.StartInfo.WorkingDirectory       = inkFile.absoluteFolderPath;
            process.StartInfo.FileName               = inklecatePath;
            process.StartInfo.Arguments              = inkArguments;
            process.StartInfo.RedirectStandardError  = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.UseShellExecute        = false;
            process.EnableRaisingEvents              = true;
            process.StartInfo.EnvironmentVariables["inkAbsoluteFilePath"] = inputPath;
            process.ErrorDataReceived += OnProcessError;
            process.Exited            += OnCompileProcessComplete;
            process.Start();
        }
        /// <summary>
        /// Starts a System.Process that compiles a master ink file, creating a playable JSON file that can be parsed by the Ink.Story class
        /// </summary>
        /// <param name="inkFile">Ink file.</param>
        private static void CompileInkInternal(InkFile inkFile, bool immediate)
        {
            // If we've not yet locked C# compilation do so now
            if (!hasLockedUnityCompilation)
            {
                hasLockedUnityCompilation = true;
                EditorApplication.LockReloadAssemblies();
            }

            RemoveFromPendingCompilationStack(inkFile);

            if (inkFile == null)
            {
                Debug.LogError("Tried to compile ink file but input was null.");
                return;
            }
            if (!inkFile.metaInfo.isMaster)
            {
                Debug.LogWarning("Compiling InkFile which is an include. Any file created is likely to be invalid. Did you mean to call CompileInk on inkFile.master?");
            }
            if (InkLibrary.GetCompilationStackItem(inkFile) != null)
            {
                UnityEngine.Debug.LogWarning("Tried compiling ink file, but file is already compiling. " + inkFile.filePath);
                return;
            }

            string inputPath = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileName(inkFile.filePath));

            Debug.Assert(inkFile.absoluteFilePath == inputPath);

            CompilationStackItem pendingFile = new CompilationStackItem
            {
                inkFile              = InkLibrary.GetInkFileWithAbsolutePath(inputPath),
                inkAbsoluteFilePath  = inputPath,
                jsonAbsoluteFilePath = inkFile.jsonPath,
                state = CompilationStackItem.State.Compiling
            };

            InkLibrary.Instance.compilationStack.Add(pendingFile);
            //InkLibrary.Save();
            if (immediate)
            {
                CompileInkThreaded(pendingFile);
                Update();
            }
            else
            {
                if (EditorApplication.isCompiling)
                {
                    Debug.LogWarning("Was compiling scripts when ink compilation started! This seems to cause the thread to cancel and complete, but the work isn't done. It may cause a timeout.");
                }
                ThreadPool.QueueUserWorkItem(CompileInkThreaded, pendingFile);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Starts a System.Process that compiles a master ink file, creating a playable JSON file that can be parsed by the Ink.Story class
        /// </summary>
        /// <param name="inkFile">Ink file.</param>
        private static void CompileInkInternal(InkFile inkFile, bool immediate)
        {
            if (inkFile == null)
            {
                Debug.LogError("Tried to compile ink file but input was null.");
                return;
            }
            if (!inkFile.metaInfo.isMaster)
            {
                Debug.LogWarning("Compiling InkFile which is an include. Any file created is likely to be invalid. Did you mean to call CompileInk on inkFile.master?");
            }

            // If we've not yet locked C# compilation do so now
            if (!hasLockedUnityCompilation)
            {
                hasLockedUnityCompilation = true;
                EditorApplication.LockReloadAssemblies();
            }

            RemoveFromPendingCompilationStack(inkFile);
            if (InkLibrary.GetCompilationStackItem(inkFile) != null)
            {
                UnityEngine.Debug.LogWarning("Tried compiling ink file, but file is already compiling. " + inkFile.filePath);
                return;
            }

            string inputPath = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileName(inkFile.filePath));

            Debug.Assert(inkFile.absoluteFilePath == inputPath);

            CompilationStackItem pendingFile = new CompilationStackItem
            {
                inkFile              = InkLibrary.GetInkFileWithAbsolutePath(inputPath),
                inkAbsoluteFilePath  = inputPath,
                jsonAbsoluteFilePath = inkFile.absoluteJSONPath,
                state     = CompilationStackItem.State.Queued,
                immediate = immediate
            };

            InkLibrary.Instance.compilationStack.Add(pendingFile);
            InkLibrary.SaveToFile();

            TryCompileNextFileInStack();
        }
Esempio n. 7
0
        private static void OnMoveAssets(string[] movedAssets)
        {
            if (!InkLibrary.Instance.handleJSONFilesAutomatically)
            {
                return;
            }
            for (var i = 0; i < movedAssets.Length; i++)
            {
                if (Path.GetExtension(movedAssets[i]) != InkEditorUtils.inkFileExtension)
                {
                    continue;
                }
                InkFile inkFile = InkLibrary.GetInkFileWithPath(movedAssets[i]);
                if (inkFile != null)
                {
                    string jsonAssetPath = AssetDatabase.GetAssetPath(inkFile.jsonAsset);

                    string movedAssetDir  = Path.GetDirectoryName(movedAssets[i]);
                    string movedAssetFile = Path.GetFileName(movedAssets[i]);
                    string newPath        = InkEditorUtils.CombinePaths(movedAssetDir, Path.GetFileNameWithoutExtension(movedAssetFile)) + ".json";
                    AssetDatabase.MoveAsset(jsonAssetPath, newPath);
                }
            }
        }
Esempio n. 8
0
 public static string UnityRelativeToAbsolutePath(string filePath)
 {
     return(InkEditorUtils.CombinePaths(Application.dataPath, filePath.Substring(7)));
 }
        private static void OnMoveAssets(string[] movedAssets)
        {
            if (!InkSettings.Instance.handleJSONFilesAutomatically)
            {
                return;
            }

            List <string> validMovedAssets = new List <string>();

            for (var i = 0; i < movedAssets.Length; i++)
            {
                if (!InkEditorUtils.IsInkFile(movedAssets[i]))
                {
                    continue;
                }
                validMovedAssets.Add(movedAssets[i]);
                queuedMovedAssets.Add(movedAssets[i]);
            }
            // Move compiled JSON files.
            // This can cause Unity to postprocess assets again.
            bool assetMoved = false;

            foreach (var inkFilePath in validMovedAssets)
            {
                InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                if (inkFile == null)
                {
                    continue;
                }
                if (inkFile.jsonAsset == null)
                {
                    continue;
                }

                string jsonAssetPath = AssetDatabase.GetAssetPath(inkFile.jsonAsset);

                string movedAssetDir  = Path.GetDirectoryName(inkFilePath);
                string movedAssetFile = Path.GetFileName(inkFilePath);
                string newPath        = InkEditorUtils.CombinePaths(movedAssetDir, Path.GetFileNameWithoutExtension(movedAssetFile)) + ".json";
                AssetDatabase.MoveAsset(jsonAssetPath, newPath);
                assetMoved = true;
            }

            // Check if no JSON assets were moved (as a result of none needing to move, or this function being called as a result of JSON files being moved)
            if (!assetMoved && queuedMovedAssets.Count > 0)
            {
                List <InkFile> filesToCompile = new List <InkFile>();

                // Add the old master file to the files to be recompiled
                foreach (var inkFilePath in queuedMovedAssets)
                {
                    InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                    if (inkFile == null)
                    {
                        continue;
                    }
                    foreach (var masterInkFile in inkFile.masterInkFilesIncludingSelf)
                    {
                        if (!filesToCompile.Contains(inkFile))
                        {
                            filesToCompile.Add(inkFile);
                        }
                    }
                }

                InkLibrary.RebuildInkFileConnections();

                // Add the new file to be recompiled
                foreach (var inkFilePath in queuedMovedAssets)
                {
                    InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                    if (inkFile == null)
                    {
                        continue;
                    }

                    foreach (var masterInkFile in inkFile.masterInkFilesIncludingSelf)
                    {
                        if (!filesToCompile.Contains(inkFile))
                        {
                            filesToCompile.Add(inkFile);
                        }
                    }
                }

                queuedMovedAssets.Clear();

                // Compile any ink files that are deemed master files a rebuild
                foreach (var inkFile in filesToCompile)
                {
                    if (inkFile.isMaster)
                    {
                        if (InkSettings.Instance.compileAutomatically || inkFile.compileAutomatically)
                        {
                            InkCompiler.CompileInk(inkFile);
                        }
                    }
                }
            }
        }
Esempio n. 10
0
        private static void SetOutputLog(CompilationStackItem pendingFile)
        {
            pendingFile.inkFile.metaInfo.errors.Clear();
            pendingFile.inkFile.metaInfo.warnings.Clear();
            pendingFile.inkFile.metaInfo.todos.Clear();

            foreach (var childInkFile in pendingFile.inkFile.metaInfo.inkFilesInIncludeHierarchy)
            {
                childInkFile.metaInfo.compileErrors.Clear();
                childInkFile.metaInfo.errors.Clear();
                childInkFile.metaInfo.warnings.Clear();
                childInkFile.metaInfo.todos.Clear();
            }

            foreach (string output in pendingFile.output)
            {
                var match = _errorRegex.Match(output);
                if (match.Success)
                {
                    string errorType = null;
                    string filename  = null;
                    int    lineNo    = -1;
                    string message   = null;

                    var errorTypeCapture = match.Groups["errorType"];
                    if (errorTypeCapture != null)
                    {
                        errorType = errorTypeCapture.Value;
                    }

                    var filenameCapture = match.Groups["filename"];
                    if (filenameCapture != null)
                    {
                        filename = filenameCapture.Value;
                    }

                    var lineNoCapture = match.Groups["lineNo"];
                    if (lineNoCapture != null)
                    {
                        lineNo = int.Parse(lineNoCapture.Value);
                    }

                    var messageCapture = match.Groups["message"];
                    if (messageCapture != null)
                    {
                        message = messageCapture.Value.Trim();
                    }


                    string  logFilePath = InkEditorUtils.CombinePaths(Path.GetDirectoryName(pendingFile.inkFile.filePath), filename);
                    InkFile inkFile     = InkLibrary.GetInkFileWithPath(logFilePath);
                    if (inkFile == null)
                    {
                        inkFile = pendingFile.inkFile;
                    }

                    string pathAndLineNumberString = "\n" + inkFile.filePath + ":" + lineNo;
                    if (errorType == "ERROR")
                    {
                        inkFile.metaInfo.errors.Add(new InkMetaFile.InkFileLog(message, lineNo));
                        Debug.LogError("INK " + errorType + ": " + message + pathAndLineNumberString);
                    }
                    else if (errorType == "WARNING")
                    {
                        inkFile.metaInfo.warnings.Add(new InkMetaFile.InkFileLog(message, lineNo));
                        Debug.LogWarning("INK " + errorType + ": " + message + pathAndLineNumberString);
                    }
                    else if (errorType == "TODO")
                    {
                        inkFile.metaInfo.todos.Add(new InkMetaFile.InkFileLog(message, lineNo));
                        Debug.Log("INK " + errorType + ": " + message + pathAndLineNumberString);
                    }
                }
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Starts a System.Process that compiles a master ink file, creating a playable JSON file that can be parsed by the Ink.Story class
        /// </summary>
        /// <param name="inkFile">Ink file.</param>
        public static void CompileInk(InkFile inkFile)
        {
            if (inkFile == null)
            {
                Debug.LogError("Tried to compile ink file " + inkFile.filePath + ", but input was null.");
                return;
            }
            if (!inkFile.metaInfo.isMaster)
            {
                Debug.LogWarning("Compiling InkFile which is an include. Any file created is likely to be invalid. Did you mean to call CompileInk on inkFile.master?");
            }
            if (InkLibrary.GetCompilationStackItem(inkFile) != null)
            {
                UnityEngine.Debug.LogWarning("Tried compiling ink file, but file is already compiling. " + inkFile.filePath);
                return;
            }

            string inklecatePath = InkEditorUtils.GetInklecateFilePath();

            if (inklecatePath == null)
            {
                UnityEngine.Debug.LogWarning("Inklecate (the ink compiler) not found in assets. This will prevent automatic building of JSON TextAsset files from ink story files.");
                return;
            }
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                SetInklecateFilePermissions(inklecatePath);
            }
            if (inklecatePath.Contains("'"))
            {
                Debug.LogError("Due to a Unity bug, Inklecate path cannot contain an apostrophe. Ink will not compile until this is resolved. Path is '" + inklecatePath + "'");
                return;
            }
            // This hasn't been affecting us lately. Left it in so we can easily restore it in case of future bugs.

            /* else if(inklecatePath.Contains(" ")){
             *      Debug.LogWarning("Inklecate path should not contain a space. This might lead to compilation failing. Path is '"+inklecatePath+"'. If you don't see any compilation errors, you can ignore this warning.");
             * }*/
            string inputPath    = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileName(inkFile.filePath));
            string outputPath   = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileNameWithoutExtension(Path.GetFileName(inkFile.filePath))) + ".json";
            string inkArguments = InkSettings.Instance.customInklecateOptions.additionalCompilerOptions + " -c -o " + "\"" + outputPath + "\" \"" + inputPath + "\"";

            CompilationStackItem pendingFile = new CompilationStackItem();

            pendingFile.inkFile              = InkLibrary.GetInkFileWithAbsolutePath(inputPath);
            pendingFile.inkAbsoluteFilePath  = inputPath;
            pendingFile.jsonAbsoluteFilePath = outputPath;
            pendingFile.state = CompilationStackItem.State.Compiling;
            InkLibrary.Instance.compilationStack.Add(pendingFile);
            InkLibrary.Save();

            Process process = new Process();

            if (InkSettings.Instance.customInklecateOptions.runInklecateWithMono && Application.platform != RuntimePlatform.WindowsEditor)
            {
                if (File.Exists(_libraryMono))
                {
                    process.StartInfo.FileName = _libraryMono;
                }
                else if (File.Exists(_usrMono))
                {
                    process.StartInfo.FileName = _usrMono;
                }
                else
                {
                    Debug.LogError("Mono was not found on machine");
                    return;
                }
                process.StartInfo.Arguments = inklecatePath + " " + inkArguments;
            }
            else
            {
                process.StartInfo.FileName  = inklecatePath;
                process.StartInfo.Arguments = inkArguments;
            }

            process.StartInfo.RedirectStandardError  = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.UseShellExecute        = false;
            process.StartInfo.CreateNoWindow         = true;
            process.EnableRaisingEvents = true;
            process.OutputDataReceived += OnProcessOutput;
            // For some reason having this line enabled spams the output and error streams with null and "???" (only on OSX?)
            // Rather than removing unhandled error detection I thought it'd be best to just catch those messages and ignore them instead.
            process.ErrorDataReceived += OnProcessError;
            process.Exited            += OnCompileProcessComplete;
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            pendingFile.process = process;
            // If you'd like to run this command outside of unity, you could instead run process.StartInfo.Arguments in the command line.
        }
Esempio n. 12
0
        public void FindCompiledJSONAsset()
        {
            string jsonAssetPath = InkEditorUtils.CombinePaths(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)) + ".json";

            jsonAsset = AssetDatabase.LoadAssetAtPath <TextAsset>(jsonAssetPath);
        }
Esempio n. 13
0
        public static void CompileInk(InkFile inkFile)
        {
            if (inkFile == null)
            {
                Debug.LogError("Tried to compile ink file " + inkFile.filePath + ", but input was null.");
                return;
            }
            if (!inkFile.isMaster)
            {
                Debug.LogWarning("Compiling InkFile which is an include. Any file created is likely to be invalid. Did you mean to call CompileInk on inkFile.master?");
            }
            if (InkLibrary.GetCompilationStackItem(inkFile) != null)
            {
                UnityEngine.Debug.LogWarning("Tried compiling ink file, but file is already compiling. " + inkFile.filePath);
                return;
            }

            string inklecatePath = InkEditorUtils.GetInklecateFilePath();

            if (inklecatePath == null)
            {
                UnityEngine.Debug.LogWarning("Inklecate (the ink compiler) not found in assets. This will prevent automatic building of JSON TextAsset files from ink story files.");
                return;
            }
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                SetInklecateFilePermissions(inklecatePath);
            }
            if (inklecatePath.Contains("'"))
            {
                Debug.LogError("Due to a Unity bug, Inklecate path cannot contain an apostrophe. Ink will not compile until this is resolved. Path is '" + inklecatePath + "'");
                return;
            }
            else if (inklecatePath.Contains(" "))
            {
                Debug.LogWarning("Inklecate path should not contain a space. This might lead to compilation failing. Path is '" + inklecatePath + "'. If you don't see any compilation errors, you can ignore this warning.");
            }
            string inputPath    = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileName(inkFile.filePath));
            string outputPath   = InkEditorUtils.CombinePaths(inkFile.absoluteFolderPath, Path.GetFileNameWithoutExtension(Path.GetFileName(inkFile.filePath))) + ".json";
            string inkArguments = InkLibrary.Instance.additionalCompilerOptions + " -c -o " + "\"" + outputPath + "\" \"" + inputPath + "\"";

            CompilationStackItem pendingFile = new CompilationStackItem();

            pendingFile.inkFile              = InkLibrary.GetInkFileWithAbsolutePath(inputPath);
            pendingFile.inkAbsoluteFilePath  = inputPath;
            pendingFile.jsonAbsoluteFilePath = outputPath;
            pendingFile.state = CompilationStackItem.State.Compiling;
            InkLibrary.Instance.compilationStack.Add(pendingFile);

            Process process = new Process();

            if (InkLibrary.Instance.runInklecateWithMono)
            {
                process.StartInfo.FileName  = "/usr/local/bin/mono";
                process.StartInfo.Arguments = inklecatePath + " " + inkArguments;
            }
            else
            {
                process.StartInfo.FileName  = inklecatePath;
                process.StartInfo.Arguments = inkArguments;
            }

            process.StartInfo.RedirectStandardError  = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.UseShellExecute        = false;
            process.EnableRaisingEvents = true;
            process.StartInfo.EnvironmentVariables["inkAbsoluteFilePath"] = inputPath;
            process.ErrorDataReceived += OnProcessError;
            process.Exited            += OnCompileProcessComplete;
            process.Start();
        }
        private static void OnMoveAssets(string[] movedAssets)
        {
            if (!InkSettings.instance.handleJSONFilesAutomatically)
            {
                return;
            }

            List <string> validMovedAssets = new List <string>();

            for (var i = 0; i < movedAssets.Length; i++)
            {
                if (!InkEditorUtils.IsInkFile(movedAssets[i]))
                {
                    continue;
                }
                validMovedAssets.Add(movedAssets[i]);
                queuedMovedInkFileAssets.Add(movedAssets[i]);
            }
            // Move compiled JSON files.
            // This can cause Unity to postprocess assets again.
            foreach (var inkFilePath in validMovedAssets)
            {
                InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                if (inkFile == null)
                {
                    continue;
                }
                if (inkFile.jsonAsset == null)
                {
                    continue;
                }

                string jsonAssetPath = AssetDatabase.GetAssetPath(inkFile.jsonAsset);

                string movedAssetDir  = Path.GetDirectoryName(inkFilePath);
                string movedAssetFile = Path.GetFileName(inkFilePath);
                string newPath        = InkEditorUtils.CombinePaths(movedAssetDir, Path.GetFileNameWithoutExtension(movedAssetFile)) + ".json";

                // On moving an ink file, we either recompile it, creating a new json file in the correct location, or we move the json file.
                if (InkSettings.instance.ShouldCompileInkFileAutomatically(inkFile))
                {
                    // We have to delay this, or it doesn't properly inform unity (there's no version of "ImportAsset" for delete); I guess it doesn't want OnPostprocessAllAssets to fire recursively.
                    EditorApplication.delayCall += () => {
                        AssetDatabase.DeleteAsset(jsonAssetPath);
                        AssetDatabase.Refresh();
                    };
                }
                else
                {
                    if (string.IsNullOrEmpty(AssetDatabase.ValidateMoveAsset(jsonAssetPath, newPath)))
                    {
                        Debug.Assert(newPath == inkFile.jsonPath);
                        EditorApplication.delayCall += () => {
                            AssetDatabase.MoveAsset(jsonAssetPath, newPath);
                            AssetDatabase.ImportAsset(newPath);
                            AssetDatabase.Refresh();
                            inkFile.FindCompiledJSONAsset();
                        };
                        // Debug.Log(jsonAssetPath+" to "+newPath);
                    }
                    else
                    {
                        // This will fire if the JSON file is also moved with the ink - in this case the json file will be in movedAssets.
                        // Debug.Log($"Failed to move asset from path '{jsonAssetPath}' to '{newPath}'.");
                    }
                }
            }
            // Check if no JSON assets were moved (as a result of none needing to move, or this function being called as a result of JSON files being moved)
            if (queuedMovedInkFileAssets.Count > 0)
            {
                List <InkFile> filesToCompile = new List <InkFile>();

                // Add the old master file to the files to be recompiled
                foreach (var inkFilePath in queuedMovedInkFileAssets)
                {
                    InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                    if (inkFile == null)
                    {
                        continue;
                    }
                    foreach (var masterInkFile in inkFile.masterInkFilesIncludingSelf)
                    {
                        if (InkSettings.instance.ShouldCompileInkFileAutomatically(masterInkFile) && !filesToCompile.Contains(masterInkFile))
                        {
                            filesToCompile.Add(masterInkFile);
                        }
                    }
                }

                InkLibrary.RebuildInkFileConnections();

                // If rebuilding connections caused a file that was previously considered a master file to no longer be, then we remove it.
                for (int i = filesToCompile.Count - 1; i >= 0; i--)
                {
                    if (!filesToCompile[i].compileAsMasterFile)
                    {
                        filesToCompile.RemoveAt(i);
                    }
                }

                // Add the new file to be recompiled
                foreach (var inkFilePath in queuedMovedInkFileAssets)
                {
                    InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
                    if (inkFile == null)
                    {
                        continue;
                    }

                    foreach (var masterInkFile in inkFile.masterInkFilesIncludingSelf)
                    {
                        if (InkSettings.instance.ShouldCompileInkFileAutomatically(masterInkFile) && !filesToCompile.Contains(masterInkFile))
                        {
                            filesToCompile.Add(masterInkFile);
                        }
                    }
                }

                queuedMovedInkFileAssets.Clear();


                // Compile any ink files that are deemed master files a rebuild
                InkCompiler.CompileInk(filesToCompile.ToArray(), compileImmediatelyOnImport);
            }
        }