Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ink Scripted Importer #205

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open

Ink Scripted Importer #205

wants to merge 21 commits into from

Conversation

SHiLLySiT
Copy link

This aims to implement #53, which IMO, has some huge benefits:

  1. There is no longer separate source .INK files and compiled .JSON files that can get out of sync. Which means designers don't need to remember commit both .INK and JSON files, which can happen if they're testing/writing outside Unity with Inky.
  2. No need to deal with managing a ink file compilation queue, and fighting with the Editor. Ink files are compiled when imported, either when added or changed.
  3. You can expose InkFile references instead of generic TextAsset references in game code.
  4. This codebase becomes significantly less complex, and less prone to weird errors that have to deal with compiling assets outside of Unity's normal import process.

This PR is currently in a proof of concept stage: it hasn't been fully tested, but loading and running ink files at runtime and in the Editor is working.

The original implementation was written before Unity supported custom scripted importers, so many of the systems are now obsolete. Since this is a pretty big change, I wanted to open a PR to get an initial review to get some initial thoughts from the maintainers.

Interested in all feedback, but the question at the top of my mind: Do we need to expose includes and master files in the editor? While Ink at a language level still has these concepts, I'm not sure how important it is to expose these in Unity if its no longer important for compilation?

@SHiLLySiT SHiLLySiT marked this pull request as draft September 2, 2024 02:12
@tomkail
Copy link
Collaborator

tomkail commented Sep 2, 2024

Oh wow thanks for looking into this! I'll take a look this week if I find time. At a glance it looks lovely (so much less code!!)
I've pinged the Unity dev community on Discord (https://discord.gg/inkle) to take a look too, since this is a big change and I'd like as many devs as possible to confirm that it doesn't affect them negatively in any way.

@SHiLLySiT
Copy link
Author

Totally! I see your message in #ink-unity-integration-dev. I'll keep watch for questions/comments there too. Thanks!

@SHiLLySiT SHiLLySiT marked this pull request as ready for review October 6, 2024 23:45
@SHiLLySiT
Copy link
Author

@tomkail Okay I'm moving this out of draft as I've cleaned up the known things I needed to do, but I suspect there may be things I've missed since this was such a huge change. Feel free to tag me on any changes you want after doing a review. I'll loop back when I have the time 🤘

@tomkail
Copy link
Collaborator

tomkail commented Oct 7, 2024 via email

@SHiLLySiT
Copy link
Author

SHiLLySiT commented Oct 8, 2024

Sounds good to me! I'd rather give more people more time to test it out before its merged into main 😅

I don't appear to have the option to change the base branch to a new (non-existing) branch tho. If you make a beta branch I can update the PR!

@SHiLLySiT
Copy link
Author

I forgot to update the docs, so I snuck another commit in 👍

Comment on lines -114 to +115
DefaultAsset asset = AssetDatabase.LoadAssetAtPath<DefaultAsset>(path);
DrawInkFile(InkLibrary.GetInkFileWithFile(asset), rect);
InkFile asset = AssetDatabase.LoadAssetAtPath<InkFile>(path);
DrawInkFile(asset, rect);
Copy link

@ErnSur ErnSur Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InkFile is now a Scriptable Object.
No OnDrawProjectWindowItem would be needed if we assign a custom icon to InkFile.cs from the inspector




public class InkFile : ScriptableObject {
Copy link

@ErnSur ErnSur Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with the way the project is maintained but this is a breaking change so it would be nice to bump the major version in the package manifest.

{
  "name": "com.inkle.ink-unity-integration",
  "version": "2.0.0",
  ...
}

Copy link

@ErnSur ErnSur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some general comments, moving to scripted importers is a natural step forward for the library but it looks like it will require breaking changes.
This could be a chance for some cleanups and other breaking changes around the codebase.
Let me know if you want more feedback, I'm interested in closer collaboration.

/// Automatically compiles .ink assets each time they are imported, and creates an InkFile asset.
/// </summary>
[ScriptedImporter(1, "ink")]
public class InkImporter : ScriptedImporter
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing namespace: Ink.UnityIntegration

Comment on lines +19 to +50
var compiler = new Compiler(inputString, new Compiler.Options
{
countAllVisits = true,
fileHandler = new UnityInkFileHandler(Path.GetDirectoryName(absolutePath)),
errorHandler = (string message, ErrorType type) => {
InkCompilerLog log;
if(InkCompilerLog.TryParse(message, out log)) {
if(string.IsNullOrEmpty(log.relativeFilePath)) log.relativeFilePath = Path.GetFileName(absolutePath);
switch (log.type)
{
case ErrorType.Error:
inkFile.errors.Add(log);
Debug.LogError("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+":"+log.lineNumber+")", inkFile);
break;
case ErrorType.Warning:
inkFile.warnings.Add(log);
Debug.LogWarning("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
break;
case ErrorType.Author:
inkFile.todos.Add(log);
if (InkSettings.instance.printInkLogsInConsoleOnCompile)
{
Debug.Log("Ink Log for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
}
break;
}

} else {
Debug.LogWarning("Couldn't parse log "+message);
}
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be extracted to a new method for readability, same with errorHandler inside it

Suggested change
var compiler = new Compiler(inputString, new Compiler.Options
{
countAllVisits = true,
fileHandler = new UnityInkFileHandler(Path.GetDirectoryName(absolutePath)),
errorHandler = (string message, ErrorType type) => {
InkCompilerLog log;
if(InkCompilerLog.TryParse(message, out log)) {
if(string.IsNullOrEmpty(log.relativeFilePath)) log.relativeFilePath = Path.GetFileName(absolutePath);
switch (log.type)
{
case ErrorType.Error:
inkFile.errors.Add(log);
Debug.LogError("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+":"+log.lineNumber+")", inkFile);
break;
case ErrorType.Warning:
inkFile.warnings.Add(log);
Debug.LogWarning("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
break;
case ErrorType.Author:
inkFile.todos.Add(log);
if (InkSettings.instance.printInkLogsInConsoleOnCompile)
{
Debug.Log("Ink Log for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
}
break;
}
} else {
Debug.LogWarning("Couldn't parse log "+message);
}
}
});
var compiler = CreateCompiler(inputString, absolutePath, inkFile);

Comment on lines +31 to +47
Debug.LogError("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+":"+log.lineNumber+")", inkFile);
break;
case ErrorType.Warning:
inkFile.warnings.Add(log);
Debug.LogWarning("Ink "+log.type+" for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
break;
case ErrorType.Author:
inkFile.todos.Add(log);
if (InkSettings.instance.printInkLogsInConsoleOnCompile)
{
Debug.Log("Ink Log for "+Path.GetFileName(absolutePath)+": "+log.content + " (at "+log.relativeFilePath+" "+log.lineNumber+")", inkFile);
}
break;
}

} else {
Debug.LogWarning("Couldn't parse log "+message);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For The AssetImportContext.LogImportError() could be used for handling all of the importer errors.
Unity handles UI for displaying errors logged this way in the importer header. This in turn could eliminate the need for custom error UI in the Ink File Editor

@@ -68,17 +68,6 @@ public string templateFilePath {
else return AssetDatabase.GetAssetPath(templateFile);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the templateFile should probably change type to the ScriptableObject imported by the InkImporter

Comment on lines +16 to +17
public static System.Version inkVersionCurrent = new System.Version(1,2,0);
public static System.Version unityIntegrationVersionCurrent = new System.Version(1,2,1);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be best to put it somewhere else

// Helper class for ink files that maintains INCLUDE connections between ink files
/// <summary>
/// ScriptableObject that serves as the imported version of .ink files.
/// </summary>
[Serializable]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Serializable is redundant on a scriptable object

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the static nested class InkIncludeParser is still inside the type but its not used (could be removed).

[ScriptedImporter(1, "ink")]
public class InkImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If compiling output of one ink file depends on another ink file then the AssetImportContext.DependsOnSourceAsset should be used for proper importer behavior.

/// Automatically compiles .ink assets each time they are imported, and creates an InkFile asset.
/// </summary>
[ScriptedImporter(1, "ink")]
public class InkImporter : ScriptedImporter
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A complimentary InkImporterEditor : ScriptedImporterEditor could be created for better UX.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest writing new UI code with UI Toolkit.
it's impossible given that the package manifest says unity 2018 is still supported.
That's a separate topic, but maybe a poll on discord could be useful to see if users really need a support for very old editor versions.
IMO bumping minimal version to 2021.3+ would be a sensible decision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants