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

Cascade recompile files with dependencies #65

Merged
merged 2 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions addons/GodotInk/Src/InkDock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public partial class InkDock : VBoxContainer

private EditorFileDialog fileDialog = null!;

private string storyPath = "";
private InkStory? story;
private bool storyStarted;

Expand Down Expand Up @@ -74,7 +75,7 @@ private void UpdateTop()
{
bool hasStory = story != null;

storyNameLabel.Text = hasStory ? story!.ResourcePath : string.Empty;
storyNameLabel.Text = hasStory ? storyPath : string.Empty;

startButton.Visible = hasStory && !storyStarted;
stopButton.Visible = hasStory && storyStarted;
Expand All @@ -88,7 +89,8 @@ private void LoadStory(string path)
{
try
{
story = GD.Load<InkStory>(path);
storyPath = path;
story = ResourceLoader.Load<InkStory>(path, null, ResourceLoader.CacheMode.Ignore);

story.Continued += ContinueStory;

Expand All @@ -106,14 +108,20 @@ private void StartStory()
if (story == null) return;

storyStarted = true;
_ = story.ContinueMaximally();
story.ContinueMaximally();

UpdateTop();
}

private void StopStory()
{
StopStory(false);
}

private void StopStory(bool setStoryToNull)
{
storyStarted = false;

try
{
story?.ResetState();
Expand All @@ -123,6 +131,9 @@ private void StopStory()
story = null;
}

if (setStoryToNull)
story = null;

ClearStory(true);
}

Expand Down Expand Up @@ -193,14 +204,14 @@ private void ClickChoice(int idx)
AddToStory(new HSeparator());

if (story.CanContinue)
_ = story.ContinueMaximally();
story.ContinueMaximally();
}

private async void AddToStory(CanvasItem item)
{
storyText.AddChild(item);
_ = await ToSignal(GetTree(), "process_frame");
_ = await ToSignal(GetTree(), "process_frame");
await ToSignal(GetTree(), "process_frame");
await ToSignal(GetTree(), "process_frame");
scroll.ScrollVertical = (int)scroll.GetVScrollBar().MaxValue;
}

Expand All @@ -216,13 +227,9 @@ private void RemoveAllChoices()
storyChoices.RemoveChild(n);
}

public void WhenInkResourceReimported(string resourcePath)
public void WhenInkResourceReimported()
{
if (story?.ResourcePath == resourcePath)
{
story = null;
StopStory();
}
StopStory(true);
}
}

Expand Down
69 changes: 60 additions & 9 deletions addons/GodotInk/Src/InkStoryImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@
#nullable enable

using Godot;
using Godot.Collections;
using Ink;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;

using DependenciesCache = System.Collections.Generic.Dictionary<string, string[]>;
using GArrayGictionary = Godot.Collections.Array<Godot.Collections.Dictionary>;
using GArrayString = Godot.Collections.Array<string>;
using Gictionary = Godot.Collections.Dictionary;

namespace GodotInk;

Expand All @@ -15,6 +23,8 @@ public partial class InkStoryImporter : EditorImportPlugin
private const string OPT_MAIN_FILE = "is_main_file";
private const string OPT_COMPRESS = "compress";

private static readonly Regex includeRegex = new(@"^\s*INCLUDE\s*(?<Path>.*)\s*$", RegexOptions.Multiline | RegexOptions.Compiled);

#pragma warning disable IDE0022
public override string _GetImporterName() => "ink";

Expand All @@ -32,24 +42,29 @@ public partial class InkStoryImporter : EditorImportPlugin

public override int _GetImportOrder() => 0;

public override Array<Dictionary> _GetImportOptions(string path, int presetIndex) => new()
public override GArrayGictionary _GetImportOptions(string path, int presetIndex) => new()
{
new() { { "name", OPT_MAIN_FILE }, { "default_value", false } },
new() { { "name", OPT_COMPRESS }, { "default_value", true } }
};

public override bool _GetOptionVisibility(string path, StringName optionName, Dictionary options) => true;
public override bool _GetOptionVisibility(string path, StringName optionName, Gictionary options) => true;
#pragma warning restore IDE0022

public override Error _Import(string sourceFile, string savePath,
Dictionary options, Array<string> platformVariants, Array<string> genFiles)
public override Error _Import(string sourceFile, string savePath, Gictionary options, GArrayString _, GArrayString __)
{
UpdateCache(sourceFile, ExtractIncludes(sourceFile));

string destFile = $"{savePath}.{_GetSaveExtension()}";
Error returnValue = options[OPT_MAIN_FILE].AsBool()
? ImportFromInk(sourceFile, destFile, options[OPT_COMPRESS].AsBool())
: ResourceSaver.Save(new StubInkStory(), destFile);

if (!options[OPT_MAIN_FILE].AsBool())
return ResourceSaver.Save(new StubInkStory(), destFile);
string[] additionalFiles = GetCache().Where(kvp => kvp.Value.Contains(sourceFile)).Select(kvp => kvp.Key).ToArray();
foreach (var additionalFile in additionalFiles)
AppendImportExternalResource(additionalFile);

return ImportFromInk(sourceFile, destFile, options[OPT_COMPRESS].AsBool());
return returnValue;
}

private static Error ImportFromInk(string sourceFile, string destFile, bool shouldCompress)
Expand All @@ -64,7 +79,8 @@ private static Error ImportFromInk(string sourceFile, string destFile, bool shou
sourceFilename = sourceFile,
errorHandler = InkCompilerErrorHandler,
fileHandler = new FileHandler(
Path.GetDirectoryName(file.GetPathAbsolute()) ?? ProjectSettings.GlobalizePath("res://")),
Path.GetDirectoryName(file.GetPathAbsolute()) ?? ProjectSettings.GlobalizePath("res://")
),
});

try
Expand All @@ -81,6 +97,15 @@ private static Error ImportFromInk(string sourceFile, string destFile, bool shou
}
}

private static List<string> ExtractIncludes(string sourceFile)
{
using Godot.FileAccess file = Godot.FileAccess.Open(sourceFile, Godot.FileAccess.ModeFlags.Read);
return includeRegex.Matches(file.GetAsText())
.OfType<Match>()
.Select(match => sourceFile.GetBaseDir().PathJoin(match.Groups["Path"].Value))
.ToList();
}

private static void InkCompilerErrorHandler(string message, ErrorType errorType)
{
switch (errorType)
Expand All @@ -94,6 +119,32 @@ private static void InkCompilerErrorHandler(string message, ErrorType errorType)
}
}

private const string CACHE_FILE = "user://ink_cache.json";

public static void UpdateCache(string sourceFile, List<string> dependencies)
{
DependenciesCache cache = GetCache();
cache[sourceFile] = dependencies.ToArray();
cache = cache.Where(kvp => kvp.Value.Length > 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

using Godot.FileAccess file = Godot.FileAccess.Open(CACHE_FILE, Godot.FileAccess.ModeFlags.Write);
file?.StoreString(JsonSerializer.Serialize(cache));
}

public static DependenciesCache GetCache()
{
using Godot.FileAccess file = Godot.FileAccess.Open(CACHE_FILE, Godot.FileAccess.ModeFlags.Read);
try
{
return JsonSerializer.Deserialize<DependenciesCache>(file?.GetAsText() ?? "{}")
?? new DependenciesCache();
}
catch (JsonException)
{
return new DependenciesCache();
}
}

private class FileHandler : IFileHandler
{
private readonly string rootDir;
Expand Down
7 changes: 3 additions & 4 deletions addons/GodotInk/plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ func _when_resources_reimported(resources : PackedStringArray) -> void:
return

for resource in resources:
if resource.get_extension() != "ink":
continue

_dock.call("WhenInkResourceReimported", resource)
if resource.get_extension() == "ink":
_dock.call("WhenInkResourceReimported")
return