Browse Source

Initial commit; new Unity project plus Ink.

master
Cidney Hamilton 5 months ago
commit
7e1a7db00a
  1. 71
      .gitignore
  2. 21
      Assets/InkLibrary.asset
  3. 8
      Assets/InkLibrary.asset.meta
  4. 28
      Assets/InkSettings.asset
  5. 8
      Assets/InkSettings.asset.meta
  6. 8
      Assets/Plugins.meta
  7. 8
      Assets/Plugins/Ink.meta
  8. 9
      Assets/Plugins/Ink/Core.meta
  9. 8
      Assets/Plugins/Ink/Core/Editor.meta
  10. 9
      Assets/Plugins/Ink/Core/Editor/Compiler.meta
  11. 9
      Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler.meta
  12. 188
      Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler/InkPostProcessor.cs
  13. 12
      Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler/InkPostProcessor.cs.meta
  14. 511
      Assets/Plugins/Ink/Core/Editor/Compiler/InkCompiler.cs
  15. 12
      Assets/Plugins/Ink/Core/Editor/Compiler/InkCompiler.cs.meta
  16. 9
      Assets/Plugins/Ink/Core/Editor/Ink Library.meta
  17. 58
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkCompilerLog.cs
  18. 11
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkCompilerLog.cs.meta
  19. 110
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkFile.cs
  20. 12
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkFile.cs.meta
  21. 342
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibrary.cs
  22. 12
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibrary.cs.meta
  23. 105
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibraryEditor.cs
  24. 12
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibraryEditor.cs.meta
  25. 307
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkMetaFile.cs
  26. 12
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkMetaFile.cs.meta
  27. 176
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkMetaLibrary.cs
  28. 12
      Assets/Plugins/Ink/Core/Editor/Ink Library/InkMetaLibrary.cs.meta
  29. 9
      Assets/Plugins/Ink/Core/Editor/Ink Settings.meta
  30. 83
      Assets/Plugins/Ink/Core/Editor/Ink Settings/InkSettings.cs
  31. 12
      Assets/Plugins/Ink/Core/Editor/Ink Settings/InkSettings.cs.meta
  32. 70
      Assets/Plugins/Ink/Core/Editor/Ink Settings/InkSettingsEditor.cs
  33. 12
      Assets/Plugins/Ink/Core/Editor/Ink Settings/InkSettingsEditor.cs.meta
  34. 329
      Assets/Plugins/Ink/Core/Editor/InkEditorUtils.cs
  35. 12
      Assets/Plugins/Ink/Core/Editor/InkEditorUtils.cs.meta
  36. 8
      Assets/Plugins/Ink/Example.meta
  37. 123
      Assets/Plugins/Ink/Example/Example.unity
  38. 7
      Assets/Plugins/Ink/Example/Example.unity.meta
  39. BIN
      Assets/Plugins/Ink/Example/ExampleSettings.lighting
  40. 8
      Assets/Plugins/Ink/Example/ExampleSettings.lighting.meta
  41. 9
      Assets/Plugins/Ink/Example/Ink.meta
  42. 19
      Assets/Plugins/Ink/Example/Ink/story.ink
  43. 8
      Assets/Plugins/Ink/Example/Ink/story.ink.meta
  44. 1
      Assets/Plugins/Ink/Example/Ink/story.json
  45. 8
      Assets/Plugins/Ink/Example/Ink/story.json.meta
  46. 9
      Assets/Plugins/Ink/Example/Prefabs.meta
  47. 265
      Assets/Plugins/Ink/Example/Prefabs/Button.prefab
  48. 8
      Assets/Plugins/Ink/Example/Prefabs/Button.prefab.meta
  49. 142
      Assets/Plugins/Ink/Example/Prefabs/Text.prefab
  50. 8
      Assets/Plugins/Ink/Example/Prefabs/Text.prefab.meta
  51. 9
      Assets/Plugins/Ink/Example/Scripts.meta
  52. 110
      Assets/Plugins/Ink/Example/Scripts/BasicInkExample.cs
  53. 12
      Assets/Plugins/Ink/Example/Scripts/BasicInkExample.cs.meta
  54. 8
      Assets/Plugins/Ink/Example/Scripts/Editor.meta
  55. 28
      Assets/Plugins/Ink/Example/Scripts/Editor/BasicInkExampleEditor.cs
  56. 11
      Assets/Plugins/Ink/Example/Scripts/Editor/BasicInkExampleEditor.cs.meta
  57. 11
      Assets/Plugins/Ink/Example/Scripts/QuitGameOnKeypress.cs
  58. 11
      Assets/Plugins/Ink/Example/Scripts/QuitGameOnKeypress.cs.meta
  59. 8
      Assets/Plugins/Ink/Extras.meta
  60. BIN
      Assets/Plugins/Ink/Extras/Sublime3Syntax.zip
  61. 8
      Assets/Plugins/Ink/Extras/Sublime3Syntax.zip.meta
  62. 8
      Assets/Plugins/Ink/InkLibs.meta
  63. 6
      Assets/Plugins/Ink/InkLibs/Ink-Libraries.asmdef
  64. 7
      Assets/Plugins/Ink/InkLibs/Ink-Libraries.asmdef.meta
  65. 8
      Assets/Plugins/Ink/InkLibs/InkCompiler.meta
  66. 54
      Assets/Plugins/Ink/InkLibs/InkCompiler/CharacterRange.cs
  67. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/CharacterRange.cs.meta
  68. 53
      Assets/Plugins/Ink/InkLibs/InkCompiler/CharacterSet.cs
  69. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/CharacterSet.cs.meta
  70. 12
      Assets/Plugins/Ink/InkLibs/InkCompiler/CommandLineInput.cs
  71. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/CommandLineInput.cs.meta
  72. 245
      Assets/Plugins/Ink/InkLibs/InkCompiler/Compiler.cs
  73. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/Compiler.cs.meta
  74. 24
      Assets/Plugins/Ink/InkLibs/InkCompiler/FileHandler.cs
  75. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/FileHandler.cs.meta
  76. 8
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser.meta
  77. 93
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/CommentEliminator.cs
  78. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/CommentEliminator.cs.meta
  79. 163
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser.cs
  80. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser.cs.meta
  81. 27
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_AuthorWarning.cs
  82. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_AuthorWarning.cs.meta
  83. 61
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_CharacterRanges.cs
  84. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_CharacterRanges.cs.meta
  85. 225
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Choices.cs
  86. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Choices.cs.meta
  87. 129
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_CommandLineInput.cs
  88. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_CommandLineInput.cs.meta
  89. 288
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Conditional.cs
  90. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Conditional.cs.meta
  91. 217
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Content.cs
  92. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Content.cs.meta
  93. 206
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Divert.cs
  94. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Divert.cs.meta
  95. 511
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Expressions.cs
  96. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Expressions.cs.meta
  97. 76
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Include.cs
  98. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Include.cs.meta
  99. 234
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Knot.cs
  100. 11
      Assets/Plugins/Ink/InkLibs/InkCompiler/InkParser/InkParser_Knot.cs.meta

71
.gitignore

@ -0,0 +1,71 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
#
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*
# Visual Studio cache directory
.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Builds
*.apk
*.aab
*.unitypackage
# Crashlytics generated file
crashlytics-build.properties
# Packed Addressables
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
# Temporary auto-generated Android Assets
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*

21
Assets/InkLibrary.asset

@ -0,0 +1,21 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc234ab28a32840f5adfb84a075bc023, type: 3}
m_Name: InkLibrary
m_EditorClassIdentifier:
inkLibrary:
- compileAutomatically: 0
inkAsset: {fileID: 102900000, guid: 1460e815e969b43b8a83a7caa8b48c27, type: 3}
jsonAssetDirectory: {fileID: 0}
jsonAsset: {fileID: 4900000, guid: 6cf48bb6d89824cc69e35b43f9a1aca6, type: 3}
pendingCompilationStack: []
compilationStack: []

8
Assets/InkLibrary.asset.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4c6f6203a220ebfa6accd8cab9844140
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

28
Assets/InkSettings.asset

@ -0,0 +1,28 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 983af1b6602bf416b9928d40b37a38bd, type: 3}
m_Name: InkSettings
m_EditorClassIdentifier:
templateFile: {fileID: 0}
defaultJsonAssetPath: {fileID: 0}
compileAutomatically: 1
delayInPlayMode: 1
handleJSONFilesAutomatically: 1
compileTimeout: 30
customInklecateOptions:
runInklecateWithMono: 1
monoPaths:
- /usr/bin/mono
- /usr/local/bin/mono
- /Library/Frameworks/Mono.framework/Versions/Current/Commands/mono
additionalCompilerOptions:
inklecate: {fileID: 0}

8
Assets/InkSettings.asset.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3d3165b24902b54f8395c4213f1fbee
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Plugins.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9c7e51e2624eba148ae2c8cf5ff43df1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Plugins/Ink.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 968c97e94558de08f82098d1c2a40a89
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Plugins/Ink/Core.meta

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: df28596461d414a1b9f56cb406a23a3f
folderAsset: yes
timeCreated: 1459882215
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Plugins/Ink/Core/Editor.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7a36b650b668b1f498b79ce8ef27d9d7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Plugins/Ink/Core/Editor/Compiler.meta

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ddef5103d5ce1401da019f7df6c472af
folderAsset: yes
timeCreated: 1459882122
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler.meta

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: e277a78690c74451084fbfbedc0507e8
folderAsset: yes
timeCreated: 1459941651
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

188
Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler/InkPostProcessor.cs

@ -0,0 +1,188 @@
// Automatically creates JSON files from an ink placed within the Assets/Ink folder.
using UnityEngine;
using UnityEditor;
using System.IO;
using Debug = UnityEngine.Debug;
using System.Collections.Generic;
using System.Linq;
namespace Ink.UnityIntegration {
class InkPostProcessor : AssetPostprocessor {
// Several assets moved at the same time can cause unity to call OnPostprocessAllAssets several times as a result of moving additional files, or simply due to minor time differences.
// This queue tells the compiler which files to recompile after moves have completed.
// Not a perfect solution - If Unity doesn't move all the files in the same attempt you can expect some error messages to appear on compile.
private static List<string> queuedMovedAssets = new List<string>();
// Recompiles any ink files as a result of an ink file (re)import
private static void OnPostprocessAllAssets (string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) {
if(deletedAssets.Length > 0) {
OnDeleteAssets(deletedAssets);
}
if(movedAssets.Length > 0) {
OnMoveAssets(movedAssets.Except(importedAssets).ToArray());
}
if(importedAssets.Length > 0) {
OnImportAssets(importedAssets);
}
if(InkLibrary.created)
InkLibrary.Clean();
}
private static void OnDeleteAssets (string[] deletedAssets) {
bool deletedInk = false;
foreach (var deletedAssetPath in deletedAssets) {
if(Path.GetExtension(deletedAssetPath) == InkEditorUtils.inkFileExtension) {
deletedInk = true;
break;
}
}
if(!deletedInk)
return;
// bool alsoDeleteJSON = false;
// alsoDeleteJSON = EditorUtility.DisplayDialog("Deleting .ink file", "Also delete the JSON file associated with the deleted .ink file?", "Yes", "No"));
List<InkFile> masterFilesAffected = new List<InkFile>();
for (int i = InkLibrary.Instance.inkLibrary.Count - 1; i >= 0; i--) {
if(InkLibrary.Instance.inkLibrary [i].inkAsset == null) {
if(!InkLibrary.Instance.inkLibrary[i].metaInfo.isMaster && InkLibrary.Instance.inkLibrary[i].metaInfo.masterInkAsset != null && !masterFilesAffected.Contains(InkLibrary.Instance.inkLibrary[i].metaInfo.masterInkFile)) {
masterFilesAffected.Add(InkLibrary.Instance.inkLibrary[i].metaInfo.masterInkFile);
}
if(InkSettings.Instance.handleJSONFilesAutomatically) {
var assetPath = AssetDatabase.GetAssetPath(InkLibrary.Instance.inkLibrary[i].jsonAsset);
if(assetPath != null && assetPath != string.Empty) {
AssetDatabase.DeleteAsset(assetPath);
}
}
InkLibrary.RemoveAt(i);
}
}
// After deleting files, we might have broken some include references, so we rebuild them. There's probably a faster way to do this, or we could probably just remove any null references, but this is a bit more robust.
foreach(InkFile inkFile in InkLibrary.Instance.inkLibrary) {
inkFile.metaInfo.FindIncludedFiles();
}
foreach(InkFile masterFile in masterFilesAffected) {
if(InkSettings.Instance.compileAutomatically || masterFile.compileAutomatically) {
InkCompiler.CompileInk(masterFile);
}
}
}
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(Path.GetExtension(movedAssets[i]) != InkEditorUtils.inkFileExtension)
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;
InkFile masterInkFile = inkFile;
if(!inkFile.metaInfo.isMaster)
masterInkFile = inkFile.metaInfo.masterInkFile;
if(!filesToCompile.Contains(masterInkFile))
filesToCompile.Add(masterInkFile);
}
InkMetaLibrary.RebuildInkFileConnections();
// Add the new file to be recompiled
foreach(var inkFilePath in queuedMovedAssets) {
InkFile inkFile = InkLibrary.GetInkFileWithPath(inkFilePath);
if(inkFile == null) continue;
InkFile masterInkFile = inkFile;
if(!inkFile.metaInfo.isMaster)
masterInkFile = inkFile.metaInfo.masterInkFile;
if(!filesToCompile.Contains(masterInkFile))
filesToCompile.Add(masterInkFile);
}
queuedMovedAssets.Clear();
// Compile any ink files that are deemed master files a rebuild
foreach(var inkFile in filesToCompile) {
if(inkFile.metaInfo.isMaster) {
if(InkSettings.Instance.compileAutomatically || inkFile.compileAutomatically) {
InkCompiler.CompileInk(inkFile);
}
}
}
}
}
private static void OnImportAssets (string[] importedAssets) {
List<string> importedInkAssets = new List<string>();
string inklecateFileLocation = null;
foreach (var importedAssetPath in importedAssets) {
if(Path.GetExtension(importedAssetPath) == InkEditorUtils.inkFileExtension)
importedInkAssets.Add(importedAssetPath);
else if (Path.GetFileName(importedAssetPath) == "inklecate" && Path.GetExtension(importedAssetPath) == "")
inklecateFileLocation = importedAssetPath;
else if (Path.GetExtension(importedAssetPath) == ".asset") {
var obj = AssetDatabase.LoadAssetAtPath<ScriptableObject>(importedAssetPath);
if(obj is InkSettings) {
InkEditorUtils.DeleteAllButOldestScriptableObjects(AssetDatabase.FindAssets("t:"+typeof(InkSettings).Name), typeof(InkSettings).Name);
} else if(obj is InkLibrary) {
InkEditorUtils.DeleteAllButOldestScriptableObjects(AssetDatabase.FindAssets("t:"+typeof(InkLibrary).Name), typeof(InkLibrary).Name);
}
}
}
if(importedInkAssets.Count > 0)
PostprocessInkFiles(importedInkAssets);
if(inklecateFileLocation != null)
PostprocessInklecate(inklecateFileLocation);
}
private static void PostprocessInklecate (string inklecateFileLocation) {
// This should probably only recompile files marked to compile automatically, but it's such a rare case, and one where you probably do want to compile.
// To fix, one day!
Debug.Log("Inklecate updated. Recompiling all Ink files...");
InkEditorUtils.RecompileAll();
}
private static void PostprocessInkFiles (List<string> importedInkAssets) {
if(EditorApplication.isPlaying && InkSettings.Instance.delayInPlayMode) {
foreach(var fileToImport in importedInkAssets) {
if(!InkLibrary.Instance.pendingCompilationStack.Contains(fileToImport))
InkLibrary.Instance.pendingCompilationStack.Add(fileToImport);
}
} else {
InkLibrary.CreateOrReadUpdatedInkFiles (importedInkAssets);
foreach (var inkAssetToCompile in InkCompiler.GetUniqueMasterInkFilesToCompile (importedInkAssets))
InkCompiler.CompileInk(inkAssetToCompile);
}
}
}
}

12
Assets/Plugins/Ink/Core/Editor/Compiler/Auto Compiler/InkPostProcessor.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 45a9c84618e20498993d11d2bb89946e
timeCreated: 1459667420
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

511
Assets/Plugins/Ink/Core/Editor/Compiler/InkCompiler.cs

@ -0,0 +1,511 @@
using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading;
using Debug = UnityEngine.Debug;
namespace Ink.UnityIntegration {
[InitializeOnLoad]
public static class InkCompiler {
public static bool compiling {
get {
return InkLibrary.Instance.compilationStack.Count > 0;
}
}
public static bool buildBlocked = false;
static bool playModeBlocked = false;
public delegate void OnCompileInkEvent (InkFile inkFile);
public static event OnCompileInkEvent OnCompileInk;
// Track if we've currently locked compilation of Unity C# Scripts
private static bool hasLockedUnityCompilation = false;
private static List<Action> onCompleteActions = new List<Action>();
[Serializable]
public class CompilationStackItem {
public enum State {
// Default state, item is about to be queued for compilation
Queued,
// Item is now owned by the thread pool and being compiled
Compiling,
// Compilation has finished, item to be processed for errors and result handled
Complete,
}
public State state = State.Queued;
public bool immediate;
public InkFile inkFile;
public string compiledJson;
public string inkAbsoluteFilePath;
public string jsonAbsoluteFilePath;
public List<InkCompilerLog> logOutput = new List<InkCompilerLog>();
public List<string> unhandledErrorOutput = new List<string>();
public DateTime startTime;
public DateTime endTime;
public float timeTaken {
get {
if(state == State.Complete) return (float)(endTime - startTime).TotalSeconds;
else return (float)(DateTime.Now - startTime).TotalSeconds;
}
}
public CompilationStackItem () {}
}
static InkCompiler () {
#if UNITY_2017_1_OR_NEWER
EditorApplication.playModeStateChanged += OnPlayModeChange;
#else
EditorApplication.playmodeStateChanged += LegacyOnPlayModeChange;
#endif
EditorApplication.update += Update;
// I really don't know if this can fire, since it assumes that it compiled so can't have been locked. But safety first!
EditorApplication.UnlockReloadAssemblies();
}
private static void Update () {
// If we're not compiling but have locked C# compilation then now is the time to reset
if ((!InkLibrary.created || !compiling) && hasLockedUnityCompilation)
{
hasLockedUnityCompilation = false;
EditorApplication.UnlockReloadAssemblies();
}
if(!InkLibrary.created)
return;
// When all files have compiled, run the complete function.
if(compiling && InkLibrary.NumFilesInCompilingStackInState(CompilationStackItem.State.Queued) == 0 && InkLibrary.NumFilesInCompilingStackInState(CompilationStackItem.State.Compiling) == 0) {
DelayedComplete();
}
for (int i = InkLibrary.Instance.compilationStack.Count - 1; i >= 0; i--) {
var compilingFile = InkLibrary.Instance.compilationStack [i];
if (compilingFile.state == CompilationStackItem.State.Compiling) {
if (compilingFile.timeTaken > InkSettings.Instance.compileTimeout) {
// TODO - Cancel the thread if it's still going. Not critical, since its kinda fine if it compiles a bit later, but it's not clear.
RemoveCompilingFile(i);
Debug.LogError("Ink Compiler timed out for "+compilingFile.inkAbsoluteFilePath+".\nCompilation should never take more than a few seconds, but for large projects or slow computers you may want to increase the timeout time in the InkSettings file.\nIf this persists there may be another issue; or else check an ink file exists at this path and try Assets/Recompile Ink, else please report as a bug with the following error log at this address: https://github.com/inkle/ink/issues\nError log:\n"+string.Join("\n",compilingFile.unhandledErrorOutput.ToArray()));
TryCompileNextFileInStack();
}
}
}
// If we're not showing a progress bar in Linux this whole step is superfluous
#if !UNITY_EDITOR_LINUX
UpdateProgressBar();
#endif
}
static void RemoveCompilingFile (int index) {
InkLibrary.Instance.compilationStack.RemoveAt(index);
InkLibrary.Save();
// Progress bar prevents delayCall callback from firing in Linux Editor, locking the
// compilation until it times out. Let's just not show progress bars in Linux Editor
#if !UNITY_EDITOR_LINUX
if (InkLibrary.Instance.compilationStack.Count == 0) EditorUtility.ClearProgressBar();
#endif
}
static void UpdateProgressBar () {
if(InkLibrary.Instance.compilationStack.Count == 0) return;
int numCompiling = InkLibrary.NumFilesInCompilingStackInState(CompilationStackItem.State.Compiling);
string message = "Compiling .Ink File "+(InkLibrary.Instance.compilationStack.Count-numCompiling)+" of "+InkLibrary.Instance.compilationStack.Count+".";
if(playModeBlocked) message += " Will enter play mode when complete.";
if(buildBlocked || playModeBlocked || EditorApplication.isPlaying) EditorUtility.DisplayProgressBar("Compiling Ink...", message, GetEstimatedCompilationProgress());
else EditorUtility.ClearProgressBar();
}
public static float GetEstimatedCompilationProgress () {
if(!compiling) return 1;
float progress = 0;
foreach (var compilingFile in InkLibrary.Instance.compilationStack) {
if (compilingFile.state == CompilationStackItem.State.Compiling)
progress += compilingFile.timeTaken / InkSettings.Instance.compileTimeout;
if (compilingFile.state == CompilationStackItem.State.Complete)
progress += 1;
}
progress /= InkLibrary.Instance.compilationStack.Count;
return progress;
}
#if UNITY_2017_1_OR_NEWER
static void OnPlayModeChange (PlayModeStateChange mode) {
if(mode == PlayModeStateChange.EnteredEditMode && InkLibrary.Instance.pendingCompilationStack.Count > 0)
CompilePendingFiles();
if(mode == PlayModeStateChange.ExitingEditMode && compiling)
BlockPlayMode();
if(mode == PlayModeStateChange.EnteredPlayMode && compiling)
EnteredPlayModeWhenCompiling();
}
#else
static void LegacyOnPlayModeChange () {
if(!EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying && InkLibrary.Instance.pendingCompilationStack.Count > 0)
CompilePendingFiles();
if(EditorApplication.isPlayingOrWillChangePlaymode && !EditorApplication.isPlaying && compiling)
BlockPlayMode();
if(EditorApplication.isPlayingOrWillChangePlaymode && EditorApplication.isPlaying && compiling)
EnteredPlayModeWhenCompiling();
}
#endif
static void CompilePendingFiles () {
InkLibrary.CreateOrReadUpdatedInkFiles (InkLibrary.Instance.pendingCompilationStack);
foreach (var pendingMasterFile in GetUniqueMasterInkFilesToCompile(InkLibrary.Instance.pendingCompilationStack))
InkCompiler.CompileInk(pendingMasterFile);
}
static void BlockPlayMode () {
EditorApplication.isPlaying = false;
var percentage = String.Format("{0:P0}.", GetEstimatedCompilationProgress());
Debug.LogWarning("Delayed entering play mode because Ink is still compiling ("+percentage+"). Will enter play mode on completion.");
playModeBlocked = true;
}
static void EnteredPlayModeWhenCompiling () {
Debug.LogError("Entered Play Mode while Ink was still compiling! Your story will not be up to date. Recommend exiting and re-entering play mode.\nWe normally delay entering play mode when compiling, so you've found an edge case!");
}
public static void CompileInk (params InkFile[] inkFiles) {
CompileInk(inkFiles, false, null);
}
public static void CompileInk (InkFile[] inkFiles, bool immediate, Action onComplete) {
#if UNITY_2019_1_OR_NEWER
AssetDatabase.DisallowAutoRefresh();
#endif
InkLibrary.Validate();
if(onComplete != null) onCompleteActions.Add(onComplete);
StringBuilder filesCompiledLog = new StringBuilder("Files compiled:");
foreach (var inkFile in inkFiles) filesCompiledLog.AppendLine().Append(inkFile.filePath);
StringBuilder outputLog = new StringBuilder ();
outputLog.Append ("Ink compilation started at ");
outputLog.AppendLine (DateTime.Now.ToLongTimeString ());
outputLog.Append (filesCompiledLog.ToString());
Debug.Log(outputLog);
foreach(var inkFile in inkFiles) {
CompileInkInternal (inkFile, immediate);
}
}
/// <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.Save();
TryCompileNextFileInStack();
}
private static void TryCompileNextFileInStack () {
if(!compiling) return;
InkCompiler.CompilationStackItem fileToCompile = null;
foreach(var x in InkLibrary.Instance.compilationStack) {
if(x.state == CompilationStackItem.State.Compiling) return;
if(x.state == CompilationStackItem.State.Queued) {
fileToCompile = x;
break;
}
}
if(fileToCompile != null) {
BeginCompilingFile(fileToCompile);
if(fileToCompile.immediate) {
CompileInkThreaded(fileToCompile);
} 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, fileToCompile);
}
}
}
private static void BeginCompilingFile(CompilationStackItem item) {
if(item.state != CompilationStackItem.State.Queued) return;
item.state = CompilationStackItem.State.Compiling;
item.startTime = DateTime.Now;
}
private static void CompleteCompilingFile(CompilationStackItem item) {
if(item.state != CompilationStackItem.State.Compiling) return;
item.state = CompilationStackItem.State.Complete;
item.endTime = DateTime.Now;
if (item.timeTaken > InkSettings.Instance.compileTimeout * 0.6f)
Debug.LogWarning ("Compilation for "+Path.GetFileName(item.inkFile.filePath)+" took over 60% of the time required to timeout the compiler. Consider increasing the compile timeout on the InkSettings file.");
}
private static void CompileInkThreaded(object itemObj) {
CompilationStackItem item = (CompilationStackItem) itemObj;
// This should be called before this point, but just in case.
BeginCompilingFile(item);
var inputString = File.ReadAllText(item.inkAbsoluteFilePath);
var compiler = new Compiler(inputString, new Compiler.Options
{
countAllVisits = true,
fileHandler = new Compiler.UnityInkFileHandler(Path.GetDirectoryName(item.inkAbsoluteFilePath)),
errorHandler = (string message, ErrorType type) => {
InkCompilerLog log;
if(InkCompilerLog.TryParse(message, out log)) {
if(string.IsNullOrEmpty(log.fileName)) log.fileName = Path.GetFileName(item.inkAbsoluteFilePath);
item.logOutput.Add(log);
} else {
Debug.LogWarning("Couldn't parse log "+message);
}
}
});
try
{
var compiledStory = compiler.Compile();
if (compiledStory != null)
item.compiledJson = compiledStory.ToJson();
}
catch (SystemException e)
{
item.unhandledErrorOutput.Add(string.Format(
"Ink Compiler threw exception \nError: {0}\n---- Trace ----\n{1}\n--------\n", e.Message,
e.StackTrace));
}
CompleteCompilingFile(item);
TryCompileNextFileInStack();
}
// When all files in stack have been compiled. This is called via update because Process events run in another thread.
private static void DelayedComplete () {
if(InkLibrary.NumFilesInCompilingStackInState(CompilationStackItem.State.Compiling) > 0) {
Debug.LogWarning("Delayed, but a file is now compiling! You can ignore this warning.");
return;
}
bool errorsFound = false;
StringBuilder filesCompiledLog = new StringBuilder("Files compiled:");
// Create and import compiled files
AssetDatabase.StartAssetEditing();
foreach (var compilingFile in InkLibrary.Instance.compilationStack) {
// Complete status is also set when an error occured, in these cases 'compiledJson' will be null so there's no import to process
if (compilingFile.compiledJson == null) continue;
// Write new compiled data to the file system
File.WriteAllText(compilingFile.jsonAbsoluteFilePath, compilingFile.compiledJson, Encoding.UTF8);
AssetDatabase.ImportAsset(compilingFile.inkFile.jsonPath);
}
AssetDatabase.StopAssetEditing();
foreach (var compilingFile in InkLibrary.Instance.compilationStack) {
// Load and store a reference to the compiled file
compilingFile.inkFile.FindCompiledJSONAsset();
filesCompiledLog.AppendLine().Append(compilingFile.inkFile.filePath);
filesCompiledLog.Append(string.Format(" ({0}s)", compilingFile.timeTaken));
if(compilingFile.unhandledErrorOutput.Count > 0) {
filesCompiledLog.Append(" (With unhandled error)");
StringBuilder errorLog = new StringBuilder ();
errorLog.Append ("Unhandled error(s) occurred compiling Ink file ");
errorLog.Append ("'");
errorLog.Append (compilingFile.inkFile.filePath);
errorLog.Append ("'");
errorLog.AppendLine ("! Please report following error(s) as a bug:");
foreach (var error in compilingFile.unhandledErrorOutput)
errorLog.AppendLine (error);
Debug.LogError(errorLog);
compilingFile.inkFile.metaInfo.unhandledCompileErrors = compilingFile.unhandledErrorOutput;
errorsFound = true;
} else {
SetOutputLog(compilingFile);
bool errorsInEntireStory = false;
bool warningsInEntireStory = false;
foreach(var inkFile in compilingFile.inkFile.metaInfo.inkFilesInIncludeHierarchy) {
if(inkFile.metaInfo.hasErrors) {
errorsInEntireStory = true;
}
if(inkFile.metaInfo.hasWarnings) {
warningsInEntireStory = true;
}
}
if(errorsInEntireStory) {
filesCompiledLog.Append(" (With error)");
errorsFound = true;
}
if(warningsInEntireStory) {
filesCompiledLog.Append(" (With warning)");
}
}
}
foreach (var compilingFile in InkLibrary.Instance.compilationStack) {
if (OnCompileInk != null) {
OnCompileInk (compilingFile.inkFile);
}
}
StringBuilder outputLog = new StringBuilder ();
if(errorsFound) {
outputLog.Append ("Ink compilation completed with errors at ");
outputLog.AppendLine (DateTime.Now.ToLongTimeString ());
outputLog.Append (filesCompiledLog.ToString());
Debug.LogError(outputLog);
} else {
outputLog.Append ("Ink compilation completed at ");
outputLog.AppendLine (DateTime.Now.ToLongTimeString ());
outputLog.Append (filesCompiledLog.ToString());
Debug.Log(outputLog);
}
InkLibrary.Instance.compilationStack.Clear();
InkLibrary.Save();
InkMetaLibrary.Save();
#if !UNITY_EDITOR_LINUX
EditorUtility.ClearProgressBar();
#endif
#if UNITY_2019_1_OR_NEWER
AssetDatabase.AllowAutoRefresh();
#endif
// This is now allowed, if compiled manually. I've left this code commented out because at some point we might want to track what caused a file to compile.
// if(EditorApplication.isPlayingOrWillChangePlaymode && InkSettings.Instance.delayInPlayMode) {
// Debug.LogError("Ink just finished recompiling while in play mode. This should never happen when InkSettings.Instance.delayInPlayMode is true!");
// }
buildBlocked = false;
if(playModeBlocked) {
playModeBlocked = false;
if(!errorsFound) {
// Delaying gives the editor a frame to clear the progress bar.
EditorApplication.delayCall += () => {
Debug.Log("Compilation completed, entering play mode.");
EditorApplication.isPlaying = true;
};
} else {
Debug.LogWarning("Play mode not entered after ink compilation because ink had errors.");
}
}
foreach(var onCompleteAction in onCompleteActions) {
if(onCompleteAction != null) onCompleteAction();
}
onCompleteActions.Clear();
}
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.unhandledCompileErrors.Clear();
childInkFile.metaInfo.errors.Clear();
childInkFile.metaInfo.warnings.Clear();
childInkFile.metaInfo.todos.Clear();
}
foreach(var output in pendingFile.logOutput) {
if(output.type == ErrorType.Error) {
pendingFile.inkFile.metaInfo.errors.Add(output);
Debug.LogError("Ink "+output.type+": "+output.content + " (at "+output.fileName+":"+output.lineNumber+")", pendingFile.inkFile.inkAsset);
} else if (output.type == ErrorType.Warning) {
pendingFile.inkFile.metaInfo.warnings.Add(output);
Debug.LogWarning("Ink "+output.type+": "+output.content + " (at "+output.fileName+" "+output.lineNumber+")", pendingFile.inkFile.inkAsset);
} else if (output.type == ErrorType.Author) {
pendingFile.inkFile.metaInfo.todos.Add(output);
Debug.Log("Ink Log: "+output.content + " (at "+output.fileName+" "+output.lineNumber+")", pendingFile.inkFile.inkAsset);
}
}
}
static void RemoveFromPendingCompilationStack (InkFile inkFile) {
InkLibrary.Instance.pendingCompilationStack.Remove(inkFile.filePath);
foreach(var includeFile in inkFile.metaInfo.inkFilesInIncludeHierarchy) {
InkLibrary.Instance.pendingCompilationStack.Remove(includeFile.filePath);
}
}
public static List<InkFile> GetUniqueMasterInkFilesToCompile (List<string> importedInkAssets) {
List<InkFile> masterInkFiles = new List<InkFile>();
foreach (var importedAssetPath in importedInkAssets) {
var masterInkFile = GetMasterFileFromInkAssetPath(importedAssetPath);
// This was being used instead of masterInkFile for the following lines, which seems obviously stupid. Changed and added this assert.
// If this ever fires then I guess I should put it back!
Debug.Assert(masterInkFile == masterInkFile.metaInfo.masterInkFileIncludingSelf);
if (!masterInkFiles.Contains(masterInkFile.metaInfo.masterInkFileIncludingSelf) && (InkSettings.Instance.compileAutomatically || masterInkFile.compileAutomatically)) {
masterInkFiles.Add(masterInkFile);
}
}
return masterInkFiles;
}
// An ink file might actually have several owners! This should be reflected here.
public static InkFile GetMasterFileFromInkAssetPath (string importedAssetPath) {
InkFile inkFile = InkLibrary.GetInkFileWithPath(importedAssetPath);
// Trying to catch a rare (and not especially important) bug that seems to happen occasionally when opening a project
// It's probably this - I've noticed it before in another context.
Debug.Assert(InkSettings.Instance != null, "No ink settings file. This is a bug. For now you should be able to fix this via Assets > Rebuild Ink Library");
// I've caught it here before
Debug.Assert(inkFile != null, "No internal InkFile reference at path "+importedAssetPath+". This is a bug. For now you can fix this via Assets > Rebuild Ink Library");
Debug.Assert(inkFile.metaInfo != null);
Debug.Assert(inkFile.metaInfo.masterInkFileIncludingSelf != null);
return inkFile.metaInfo.masterInkFileIncludingSelf;
}
}
}

12
Assets/Plugins/Ink/Core/Editor/Compiler/InkCompiler.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 430cb8f71c23c438cb8b0ce85cc80fa6
timeCreated: 1459463931
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/Plugins/Ink/Core/Editor/Ink Library.meta

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: c547bc1dd015a497cb998538d42d2340
folderAsset: yes
timeCreated: 1459878666
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

58
Assets/Plugins/Ink/Core/Editor/Ink Library/InkCompilerLog.cs

@ -0,0 +1,58 @@
using System.Text.RegularExpressions;
using Debug = UnityEngine.Debug;
namespace Ink.UnityIntegration
{
[System.Serializable]
public class InkCompilerLog {
public Ink.ErrorType type;
public string content;
public string fileName;
public int lineNumber;
public InkCompilerLog (Ink.ErrorType type, string content, string fileName, int lineNumber = -1) {
this.type = type;
this.content = content;
this.fileName = fileName;
this.lineNumber = lineNumber;
}
public static bool TryParse (string rawLog, out InkCompilerLog log) {
var match = _errorRegex.Match(rawLog);
if (match.Success) {
Ink.ErrorType errorType = Ink.ErrorType.Author;
string filename = null;
int lineNo = -1;
string message = null;
var errorTypeCapture = match.Groups["errorType"];
if( errorTypeCapture != null ) {
var errorTypeStr = errorTypeCapture.Value;
if(errorTypeStr == "AUTHOR" || errorTypeStr == "TODO") errorType = Ink.ErrorType.Author;
else if(errorTypeStr == "WARNING") errorType = Ink.ErrorType.Warning;
else if(errorTypeStr == "ERROR") errorType = Ink.ErrorType.Error;
else Debug.LogWarning("Could not parse error type from "+errorTypeStr);
}
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();
log = new InkCompilerLog(errorType, message, filename, lineNo);
return true;
} else {
Debug.LogWarning("Could not parse InkFileLog from log: "+rawLog);
log = null;
return false;
}
}
private static Regex _errorRegex = new Regex(@"(?<errorType>ERROR|WARNING|TODO):(?:\s(?:'(?<filename>[^']*)'\s)?line (?<lineNo>\d+):)?(?<message>.*)");
}
}

11
Assets/Plugins/Ink/Core/Editor/Ink Library/InkCompilerLog.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2af758247ca160446b0727c6e91632cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

110
Assets/Plugins/Ink/Core/Editor/Ink Library/InkFile.cs

@ -0,0 +1,110 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using Debug = UnityEngine.Debug;
namespace Ink.UnityIntegration {
// Helper class for ink files that maintains INCLUDE connections between ink files
[System.Serializable]
public class InkFile {
public bool compileAutomatically = false;
// A reference to the ink file
public DefaultAsset inkAsset;
//specify json destination folder (if None, default to same folder as ink file)
public DefaultAsset jsonAssetDirectory;
// The compiled json file. Use this to start a story.
public TextAsset jsonAsset;
[System.NonSerialized]
private InkMetaFile _metaInfo;
public InkMetaFile metaInfo {
get {
if(_metaInfo == null || _metaInfo.inkAsset == null)
_metaInfo = InkMetaLibrary.GetInkMetaFile(this);
return _metaInfo;
} set {
_metaInfo = value;
}
}
// The file path relative to the Assets folder (Assets/Ink/Story.ink)
public string filePath {
get {
if(inkAsset == null)
return null;
return InkEditorUtils.SanitizePathString(AssetDatabase.GetAssetPath(inkAsset));
}
}
// The full file path (C:/Users/Inkle/HeavensVault/Assets/Ink/Story.ink)
public string absoluteFilePath {
get {
if(inkAsset == null)
return null;
return InkEditorUtils.UnityRelativeToAbsolutePath(filePath);
}
}
public string absoluteFolderPath {
get {
return InkEditorUtils.SanitizePathString(Path.GetDirectoryName(absoluteFilePath));
}
}
// The path of any compiled json file. Relative to assets folder.
public string jsonPath {
get {
var _filePath = filePath;
Debug.Assert(_filePath != null, "File path for ink file is null! The ink library requires rebuilding.");
DefaultAsset jsonFolder = jsonAssetDirectory;
if (jsonFolder == null) // no path specified for this specific file
{
if(InkSettings.Instance.defaultJsonAssetPath != null)
{
// use default path in InkSettings
jsonFolder = InkSettings.Instance.defaultJsonAssetPath;
}
if (jsonFolder == null)
{
//fallback to same folder as .ink file
jsonFolder = AssetDatabase.LoadAssetAtPath<DefaultAsset>(Path.GetDirectoryName(_filePath));
}
}
Debug.Assert(jsonFolder != null, "JSON folder not found for ink file at path "+_filePath);
string jsonPath = AssetDatabase.GetAssetPath(jsonFolder);
string strJsonAssetPath = InkEditorUtils.CombinePaths(jsonPath, Path.GetFileNameWithoutExtension(_filePath)) + ".json";
return strJsonAssetPath;
}
}
public string absoluteJSONPath {
get {
if(inkAsset == null)
return null;
return InkEditorUtils.UnityRelativeToAbsolutePath(jsonPath);
}
}
public InkFile (DefaultAsset inkAsset) {
Debug.Assert(inkAsset != null);
this.inkAsset = inkAsset;
}
public void FindCompiledJSONAsset () {
Debug.Assert(inkAsset != null);
jsonAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(jsonPath);
}
public override string ToString () {
return string.Format ("[InkFile: filePath={0}]", filePath);
}
}
}

12
Assets/Plugins/Ink/Core/Editor/Ink Library/InkFile.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b497ccd4b61cb4fee8b8f0ce86302e83
timeCreated: 1459464092
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

342
Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibrary.cs

@ -0,0 +1,342 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
/// <summary>
/// Holds a reference to an InkFile object for every .ink file detected in the Assets folder.
/// Provides helper functions to easily obtain these files.
/// </summary>
namespace Ink.UnityIntegration {
public class InkLibrary : ScriptableObject, IEnumerable<InkFile> {
public static System.Version versionCurrent = new System.Version(0,9,4);
public static bool created {
get {
// If it's null, there's no InkLibrary asset in the project
return _Instance != null;
}
}
private static InkLibrary _Instance;
public static InkLibrary Instance {
get {
if(_Instance == null) {
InkLibrary newInstance = null;
if(InkEditorUtils.FindOrCreateSingletonScriptableObjectOfType<InkLibrary>(defaultPath, out newInstance)) {
Instance = newInstance;
Rebuild();
} else {
Instance = newInstance;
}
}
return _Instance;
} private set {
_Instance = value;
CreateDictionary();
Validate();
}
}
public const string defaultPath = "Assets/InkLibrary.asset";
public List<InkFile> inkLibrary = new List<InkFile>();
Dictionary<DefaultAsset, InkFile> inkLibraryDictionary;
// If InkSettings' delayInPlayMode option is true, dirty files are added here when they're changed in play mode
// This ensures they're remembered when you exit play mode and can be compiled
public List<string> pendingCompilationStack = new List<string>();
// The state of files currently being compiled. You can ignore this!
public List<InkCompiler.CompilationStackItem> compilationStack = new List<InkCompiler.CompilationStackItem>();
public int Count {
get {
return inkLibrary.Count;
}
}
public InkFile this[int key] {
get {
return inkLibrary[key];
} set {
inkLibrary[key] = value;
}
}
IEnumerator<InkFile> IEnumerable<InkFile>.GetEnumerator() {
return inkLibrary.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return inkLibrary.GetEnumerator();
}
private void OnEnable() {
Instance = this;
}
private void OnDisable() {
Instance = null;
}
static void CreateDictionary () {
Instance.inkLibraryDictionary = new Dictionary<DefaultAsset, InkFile>();
foreach(var inkFile in Instance.inkLibrary) {
Instance.inkLibraryDictionary.Add(inkFile.inkAsset, inkFile);
}
}
/// <summary>
/// Checks if the library is corrupt and rebuilds if necessary.
/// </summary>
public static void Validate () {
if(RequiresRebuild()) {
Rebuild();
Debug.LogWarning("InkLibrary was invalid and has been rebuilt. You can ignore this warning.");
}
}
/// <summary>
/// Checks if the library is corrupt and requires a Rebuild.
/// This can happen when asset IDs change, causing the wrong file to be referenced.
/// This occassionally occurs from source control.
/// This is a fairly performant check.
/// </summary>
public static bool RequiresRebuild () {
foreach(var inkFile in Instance.inkLibrary) {
if(inkFile == null) {
return true;
}
if(inkFile.inkAsset == null) {
return true;
}
if(!Instance.inkLibraryDictionary.ContainsKey(inkFile.inkAsset)) {
return true;
}
if(inkFile.metaInfo == null) {
return true;
}
if(inkFile.metaInfo.inkAsset == null) {
return true;
}
if(inkFile.metaInfo.inkAsset != inkFile.inkAsset) {
return true;
}
foreach(var include in inkFile.metaInfo.includes) {
if(include == null) {
return true;
}
if(!Instance.inkLibraryDictionary.ContainsKey(include)) {
return true;
}
}
}
return false;
}
/// <summary>
/// Removes and null references in the library
/// </summary>
public static bool Clean () {
bool wasDirty = false;
for (int i = InkLibrary.Instance.Count - 1; i >= 0; i--) {
InkFile inkFile = InkLibrary.Instance[i];
if (inkFile.inkAsset == null) {
InkLibrary.RemoveAt(i);
wasDirty = true;
}
}
return wasDirty;
}
public static void Add (InkFile inkFile) {
Instance.inkLibrary.Add(inkFile);
Instance.inkLibraryDictionary.Add(inkFile.inkAsset, inkFile);
InkMetaLibrary.Instance.metaLibrary.Add(new InkMetaFile(inkFile));
}
public static void RemoveAt (int index) {
var inkFile = Instance.inkLibrary[index];
Instance.inkLibrary.RemoveAt(index);
Instance.inkLibraryDictionary.Remove(inkFile.inkAsset);
InkMetaLibrary.Instance.metaLibrary.Remove(inkFile.metaInfo);
}
/// <summary>
/// Updates the ink library. Executed whenever an ink file is changed by InkToJSONPostProcessor
/// Can be called manually, but incurs a performance cost.
/// </summary>
public static void Rebuild () {
// Remove any old file connections
Clean();
// Add any new file connections (if any are found it replaces the old library entirely)
string[] inkFilePaths = GetAllInkFilePaths();
bool inkLibraryChanged = false;
List<InkFile> newInkLibrary = new List<InkFile>(inkFilePaths.Length);
for (int i = 0; i < inkFilePaths.Length; i++) {
InkFile inkFile = GetInkFileWithAbsolutePath(inkFilePaths [i]);
// If the ink library doesn't have a representation for this file, then make one
if(inkFile == null) {
inkLibraryChanged = true;
string localAssetPath = InkEditorUtils.AbsoluteToUnityRelativePath(inkFilePaths [i]);
DefaultAsset inkFileAsset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(localAssetPath);
// If the ink file can't be found, it might not yet have been imported. We try to manually import it to fix this.
if(inkFileAsset == null) {
AssetDatabase.ImportAsset(localAssetPath);
inkFileAsset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(localAssetPath);
if(inkFileAsset == null) {
Debug.LogWarning("Ink File Asset not found at "+localAssetPath+". This can occur if the .meta file has not yet been created. This issue should resolve itself, but if unexpected errors occur, rebuild Ink Library using Assets > Recompile Ink");
continue;
}
}
inkFile = new InkFile(inkFileAsset);
}
newInkLibrary.Add(inkFile);
}
if(inkLibraryChanged)
Instance.inkLibrary = newInkLibrary;
CreateDictionary();
// Validate the meta files
var metaFiles = Instance.inkLibrary.Select(x => x.metaInfo);
bool metaFilesChanged = !InkMetaLibrary.Instance.metaLibrary.SequenceEqual(metaFiles);
if(metaFilesChanged)
InkMetaLibrary.Instance.metaLibrary = metaFiles.ToList();
InkMetaLibrary.RebuildInkFileConnections();
foreach (InkFile inkFile in Instance.inkLibrary) inkFile.FindCompiledJSONAsset();
Save();
Debug.Log("Ink Library was rebuilt.");
}
public static void CreateOrReadUpdatedInkFiles (List<string> importedInkAssets) {
foreach (var importedAssetPath in importedInkAssets) {
InkFile inkFile = InkLibrary.GetInkFileWithPath(importedAssetPath);
if(inkFile == null) {
DefaultAsset asset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(importedAssetPath);
inkFile = new InkFile(asset);
Add(inkFile);
} else {
inkFile.metaInfo.ParseContent();
}
}
// Now we've updated all the include paths for the ink library we can create master/child references between them.
InkMetaLibrary.RebuildInkFileConnections();
}
// Finds absolute file paths of all the ink files in Application.dataPath
private static string[] GetAllInkFilePaths () {
string[] inkFilePaths = Directory.GetFiles(Application.dataPath, "*.ink", SearchOption.AllDirectories);
for (int i = 0; i < inkFilePaths.Length; i++) {
inkFilePaths [i] = InkEditorUtils.SanitizePathString(inkFilePaths [i]);
}
return inkFilePaths;
}
public static void Save () {
EditorUtility.SetDirty(Instance);
// AssetDatabase.SaveAssets();
EditorApplication.RepaintProjectWindow();
}
// All the master files
public static IEnumerable<InkFile> GetMasterInkFiles () {
if(Instance.inkLibrary == null) yield break;
foreach (InkFile inkFile in Instance.inkLibrary) {
if(inkFile.metaInfo.isMaster)
yield return inkFile;
}
}
// All the master files which are dirty and are set to compile
public static IEnumerable<InkFile> GetFilesRequiringRecompile () {
foreach(InkFile inkFile in InkLibrary.GetMasterInkFiles ()) {
if(inkFile.metaInfo.requiresCompile && (InkSettings.Instance.compileAutomatically || inkFile.compileAutomatically))
yield return inkFile;
}
}
// All the master files which are set to compile
public static IEnumerable<InkFile> FilesCompiledByRecompileAll () {
foreach(InkFile inkFile in InkLibrary.GetMasterInkFiles ()) {
if(InkSettings.Instance.compileAutomatically || inkFile.compileAutomatically)
yield return inkFile;
}
}
/// <summary>
/// Gets the ink file from the .ink file reference.
/// </summary>
/// <returns>The ink file with path.</returns>
/// <param name="path">Path.</param>
public static InkFile GetInkFileWithFile (DefaultAsset file) {
if(InkLibrary.Instance.inkLibrary == null) return null;
if(Instance.inkLibraryDictionary == null) {
Debug.LogWarning("GetInkFileWithFile: inkLibraryDictionary was null! This should never occur, but is handled following a user reported bug. If this has never been seen long after 12/08/2020, it can be safely removed");
CreateDictionary();
}
foreach(InkFile inkFile in Instance.inkLibrary) {
if(inkFile.inkAsset == file) {
return inkFile;
}
}
Debug.LogWarning (file + " missing from ink library. Please rebuild.");
return null;
}
/// <summary>
/// Gets the ink file with path relative to Assets folder, for example: "Assets/Ink/myStory.ink".
/// </summary>
/// <returns>The ink file with path.</returns>
/// <param name="path">Path.</param>
public static InkFile GetInkFileWithPath (string path) {
if(Instance.inkLibrary == null) return null;
foreach(InkFile inkFile in Instance.inkLibrary) {
if(inkFile.filePath == path) {
return inkFile;
}
}
return null;
}
/// <summary>
/// Gets the ink file with absolute path.
/// </summary>
/// <returns>The ink file with path.</returns>
/// <param name="path">Path.</param>
public static InkFile GetInkFileWithAbsolutePath (string absolutePath) {
if(InkLibrary.Instance.inkLibrary == null) return null;
foreach(InkFile inkFile in Instance.inkLibrary) {
if(inkFile.absoluteFilePath == absolutePath) {
return inkFile;
}
}
return null;
}
public static int NumFilesInCompilingStackInState (InkCompiler.CompilationStackItem.State state) {
int count = 0;
foreach(var x in Instance.compilationStack) {
if(x.state == state)
count++;
}
return count;
}
public static List<InkCompiler.CompilationStackItem> FilesInCompilingStackInState (InkCompiler.CompilationStackItem.State state) {
List<InkCompiler.CompilationStackItem> items = new List<InkCompiler.CompilationStackItem>();
foreach(var x in Instance.compilationStack) {
if(x.state == state)
items.Add(x);
}
return items;
}
public static InkCompiler.CompilationStackItem GetCompilationStackItem (InkFile inkFile) {
foreach(var x in Instance.compilationStack) {
if(x.inkFile == inkFile)
return x;
}
return null;
}
}
}

12
Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibrary.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: dc234ab28a32840f5adfb84a075bc023
timeCreated: 1485516445
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

105
Assets/Plugins/Ink/Core/Editor/Ink Library/InkLibraryEditor.cs

@ -0,0 +1,105 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
namespace Ink.UnityIntegration {
[CustomEditor(typeof(InkLibrary))]
public class InkLibraryEditor : Editor {
#pragma warning disable
protected InkLibrary data;
public void OnEnable() {
data = (InkLibrary) target;
}
protected override void OnHeaderGUI () {
GUILayout.BeginHorizontal();
GUILayout.Space(38f);
GUILayout.BeginVertical();
GUILayout.Space(19f);
GUILayout.BeginHorizontal();
GUILayoutUtility.GetRect(10f, 10f, 16f, 16f, EditorStyles.layerMaskField);
GUILayout.FlexibleSpace();
EditorGUI.BeginDisabledGroup(InkCompiler.compiling);
if (GUILayout.Button(new GUIContent("Rebuild Library", "Rebuilds the ink library. Do this if you're getting unusual errors"), EditorStyles.miniButton)) {
InkLibrary.Rebuild();
}
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();