diff --git a/.gitignore b/.gitignore
index f6c2350..26370b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,10 @@
!.vscode/extensions.json
*.code-workspace
+## VisualStudio
+
+.vs/
+
# Local History for Visual Studio Code
.history/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 866cfa4..461dea6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [0.2.12] 2024-09-15
+* Use file-scoped namespaces in all plugin scripts to reduce indentation, by @valkyrienyanko
+
## [0.2.11] 2024-09-13
* Fix an issue where the OptionsListView did not fade in properly and instead suddenly appeared at the end of the fade time. (Fix #62)
* `Effects.Fade` now uses a Godot Tween.
diff --git a/addons/YarnSpinner-Godot/Editor/YarnCompileErrorsPropertyEditor.cs b/addons/YarnSpinner-Godot/Editor/YarnCompileErrorsPropertyEditor.cs
index 4b41f52..7185fba 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnCompileErrorsPropertyEditor.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnCompileErrorsPropertyEditor.cs
@@ -3,69 +3,68 @@
using Godot;
using Array = Godot.Collections.Array;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+[Tool]
+public partial class YarnCompileErrorsPropertyEditor : EditorProperty
{
- [Tool]
- public partial class YarnCompileErrorsPropertyEditor : EditorProperty
- {
- // The main control for editing the property.
- private Label _propertyControl;
+ // The main control for editing the property.
+ private Label _propertyControl;
- // An internal value of the property.
- private Array _currentValue;
+ // An internal value of the property.
+ private Array _currentValue;
- [Signal]
- public delegate void OnErrorsUpdateEventHandler(GodotObject yarnProject);
+ [Signal]
+ public delegate void OnErrorsUpdateEventHandler(GodotObject yarnProject);
+
+ public YarnCompileErrorsPropertyEditor()
+ {
+ _propertyControl = new Label();
+ Label = "Project Errors";
+ // Add the control as a direct child of EditorProperty node.
+ AddChild(_propertyControl);
+ // Make sure the control is able to retain the focus.
+ AddFocusable(_propertyControl);
+ // Setup the initial state and connect to the signal to track changes.
+ RefreshControlText();
+ }
- public YarnCompileErrorsPropertyEditor()
+ public override void _UpdateProperty()
+ {
+ // Read the current value from the property.
+ var newVariantValue = GetEditedObject().Get(GetEditedProperty());
+ var newValue = (Array) newVariantValue;
+ if (newValue == _currentValue)
{
- _propertyControl = new Label();
- Label = "Project Errors";
- // Add the control as a direct child of EditorProperty node.
- AddChild(_propertyControl);
- // Make sure the control is able to retain the focus.
- AddFocusable(_propertyControl);
- // Setup the initial state and connect to the signal to track changes.
- RefreshControlText();
+ return;
}
- public override void _UpdateProperty()
- {
- // Read the current value from the property.
- var newVariantValue = GetEditedObject().Get(GetEditedProperty());
- var newValue = (Array) newVariantValue;
- if (newValue == _currentValue)
- {
- return;
- }
+ _currentValue = newValue;
+ RefreshControlText();
+ EmitSignal(SignalName.OnErrorsUpdate);
+ }
- _currentValue = newValue;
- RefreshControlText();
- EmitSignal(SignalName.OnErrorsUpdate);
+ private void RefreshControlText()
+ {
+ if (_currentValue == null)
+ {
+ _propertyControl.Text = "";
}
-
- private void RefreshControlText()
+ else if (_currentValue.Count == 0)
{
- if (_currentValue == null)
- {
- _propertyControl.Text = "";
- }
- else if (_currentValue.Count == 0)
- {
- _propertyControl.Text = "None";
- }
- else
- {
- _propertyControl.Text =
- $"❌{_currentValue.Count} error{(_currentValue.Count > 1 ? "s" : "")}";
- }
+ _propertyControl.Text = "None";
}
-
- public void Refresh()
+ else
{
- EmitChanged(GetEditedProperty(),
- GetEditedObject().Get(GetEditedProperty()));
+ _propertyControl.Text =
+ $"❌{_currentValue.Count} error{(_currentValue.Count > 1 ? "s" : "")}";
}
}
+
+ public void Refresh()
+ {
+ EmitChanged(GetEditedProperty(),
+ GetEditedObject().Get(GetEditedProperty()));
+ }
}
#endif
\ No newline at end of file
diff --git a/addons/YarnSpinner-Godot/Editor/YarnEditorUtility.cs b/addons/YarnSpinner-Godot/Editor/YarnEditorUtility.cs
index d17d0ee..272d83e 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnEditorUtility.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnEditorUtility.cs
@@ -4,110 +4,109 @@
using File = System.IO.File;
using Path = System.IO.Path;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+///
+/// Contains utility methods for working with Yarn Spinner content in
+/// the Godot editor.
+///
+public static class YarnEditorUtility
{
+
+
+ const string TemplateFilePath = "res://addons/YarnSpinner-Godot/Editor/YarnScriptTemplate.txt";
+
///
- /// Contains utility methods for working with Yarn Spinner content in
- /// the Godot editor.
- ///
- public static class YarnEditorUtility
+ /// Menu Item "Tools > YarnSpinner > Create Yarn Script"
+ ///
+ ///
+ public static void CreateYarnScript(string scriptPath)
{
+ GD.Print($"Creating new yarn script at {scriptPath}");
+ CreateYarnScriptAssetFromTemplate(scriptPath);
+ }
-
- const string TemplateFilePath = "res://addons/YarnSpinner-Godot/Editor/YarnScriptTemplate.txt";
-
- ///
- /// Menu Item "Tools > YarnSpinner > Create Yarn Script"
- ///
- ///
- public static void CreateYarnScript(string scriptPath)
+ ///
+ /// Menu Item "Tools > YarnSpinner > Create Yarn Script"
+ ///
+ /// res:// path of the YarnProject resource to create
+ public static void CreateYarnProject(string projectPath)
+ {
+ var jsonProject = new Yarn.Compiler.Project();
+ var absPath = ProjectSettings.GlobalizePath(projectPath);
+ jsonProject.SaveToFile(absPath);
+ }
+ ///
+ /// Menu Item "Tools > YarnSpinner > Create Markup Palette"
+ ///
+ /// res:// path to the markup palette to create
+ public static void CreateMarkupPalette(string palettePath)
+ {
+ var newPalette = new MarkupPalette();
+ var absPath = ProjectSettings.GlobalizePath(palettePath);
+ newPalette.ResourceName = Path.GetFileNameWithoutExtension(absPath);
+ newPalette.ResourcePath = palettePath;
+ var saveErr = ResourceSaver.Save(newPalette, palettePath);
+ if (saveErr != Error.Ok)
{
- GD.Print($"Creating new yarn script at {scriptPath}");
- CreateYarnScriptAssetFromTemplate(scriptPath);
+ GD.Print($"Failed to save markup palette to {palettePath}");
}
+ }
+
+ ///
+ /// Menu Item "Yarn Spinner/Create Yarn Script"
+ ///
+ ///
+ ///
+ public static void CreateYarnLocalization(string localizationPath)
+ {
+ var newLocalization = new Localization();
+ var absPath = ProjectSettings.GlobalizePath(localizationPath);
+ newLocalization.ResourceName = Path.GetFileNameWithoutExtension(absPath);
+ newLocalization.ResourcePath = localizationPath;
+ ResourceSaver.Save( newLocalization , localizationPath);
+ GD.Print($"Saved new yarn localization to {localizationPath}");
+ }
- ///
- /// Menu Item "Tools > YarnSpinner > Create Yarn Script"
- ///
- /// res:// path of the YarnProject resource to create
- public static void CreateYarnProject(string projectPath)
- {
- var jsonProject = new Yarn.Compiler.Project();
- var absPath = ProjectSettings.GlobalizePath(projectPath);
- jsonProject.SaveToFile(absPath);
- }
- ///
- /// Menu Item "Tools > YarnSpinner > Create Markup Palette"
- ///
- /// res:// path to the markup palette to create
- public static void CreateMarkupPalette(string palettePath)
+ private static void CreateYarnScriptAssetFromTemplate(string pathName)
+ {
+ // Read the contents of the template file
+ string templateContent;
+ try
{
- var newPalette = new MarkupPalette();
- var absPath = ProjectSettings.GlobalizePath(palettePath);
- newPalette.ResourceName = Path.GetFileNameWithoutExtension(absPath);
- newPalette.ResourcePath = palettePath;
- var saveErr = ResourceSaver.Save(newPalette, palettePath);
- if (saveErr != Error.Ok)
- {
- GD.Print($"Failed to save markup palette to {palettePath}");
- }
+ templateContent = File.ReadAllText(ProjectSettings.GlobalizePath(TemplateFilePath));
}
-
- ///
- /// Menu Item "Yarn Spinner/Create Yarn Script"
- ///
- ///
- ///
- public static void CreateYarnLocalization(string localizationPath)
+ catch
{
- var newLocalization = new Localization();
- var absPath = ProjectSettings.GlobalizePath(localizationPath);
- newLocalization.ResourceName = Path.GetFileNameWithoutExtension(absPath);
- newLocalization.ResourcePath = localizationPath;
- ResourceSaver.Save( newLocalization , localizationPath);
- GD.Print($"Saved new yarn localization to {localizationPath}");
+ GD.PrintErr("Failed to find the Yarn script template file. Creating an empty file instead.");
+ // the minimal valid Yarn script - no headers, no body
+ templateContent = "---\n===\n";
}
- private static void CreateYarnScriptAssetFromTemplate(string pathName)
- {
- // Read the contents of the template file
- string templateContent;
- try
- {
- templateContent = File.ReadAllText(ProjectSettings.GlobalizePath(TemplateFilePath));
- }
- catch
- {
- GD.PrintErr("Failed to find the Yarn script template file. Creating an empty file instead.");
- // the minimal valid Yarn script - no headers, no body
- templateContent = "---\n===\n";
- }
-
- // Figure out the 'file name' that the user entered
- // The script name is the name of the file, sans extension.
- string scriptName = Path.GetFileNameWithoutExtension(pathName);
+ // Figure out the 'file name' that the user entered
+ // The script name is the name of the file, sans extension.
+ string scriptName = Path.GetFileNameWithoutExtension(pathName);
- // Replace any spaces with underscores - these aren't allowed
- // in node names
- scriptName = scriptName.Replace(" ", "_");
+ // Replace any spaces with underscores - these aren't allowed
+ // in node names
+ scriptName = scriptName.Replace(" ", "_");
- // Replace the placeholder with the script name
- templateContent = templateContent.Replace("#SCRIPTNAME#", scriptName);
+ // Replace the placeholder with the script name
+ templateContent = templateContent.Replace("#SCRIPTNAME#", scriptName);
- string lineEndings = "\n";
+ string lineEndings = "\n";
- // Replace every line ending in the template (this way we don't
- // need to keep track of which line ending the asset was last
- // saved in)
- templateContent = System.Text.RegularExpressions.Regex.Replace(templateContent, @"\r\n?|\n", lineEndings);
+ // Replace every line ending in the template (this way we don't
+ // need to keep track of which line ending the asset was last
+ // saved in)
+ templateContent = System.Text.RegularExpressions.Regex.Replace(templateContent, @"\r\n?|\n", lineEndings);
- // Write it all out to disk as UTF-8
- var fullPath = Path.GetFullPath(ProjectSettings.GlobalizePath(pathName));
- File.WriteAllText(fullPath, templateContent, System.Text.Encoding.UTF8);
- GD.Print($"Wrote new file {pathName}");
- YarnSpinnerPlugin.editorInterface.GetResourceFilesystem().ScanSources();
- }
-
+ // Write it all out to disk as UTF-8
+ var fullPath = Path.GetFullPath(ProjectSettings.GlobalizePath(pathName));
+ File.WriteAllText(fullPath, templateContent, System.Text.Encoding.UTF8);
+ GD.Print($"Wrote new file {pathName}");
+ YarnSpinnerPlugin.editorInterface.GetResourceFilesystem().ScanSources();
}
+
}
#endif
\ No newline at end of file
diff --git a/addons/YarnSpinner-Godot/Editor/YarnImporter.cs b/addons/YarnSpinner-Godot/Editor/YarnImporter.cs
index a95a5e5..2d5bffe 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnImporter.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnImporter.cs
@@ -5,126 +5,125 @@
using Godot;
using Godot.Collections;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+///
+/// A for Yarn scripts (.yarn files)
+///
+public partial class YarnImporter : EditorImportPlugin
{
- ///
- /// A for Yarn scripts (.yarn files)
- ///
- public partial class YarnImporter : EditorImportPlugin
- {
- public override string[] _GetRecognizedExtensions() =>
- new[]
- {
- "yarn"
- };
+ public override string[] _GetRecognizedExtensions() =>
+ new[]
+ {
+ "yarn"
+ };
+
+ public override string _GetImporterName() => "yarnscript";
- public override string _GetImporterName() => "yarnscript";
+ public override string _GetVisibleName() => "Yarn Script";
- public override string _GetVisibleName() => "Yarn Script";
+ public override string _GetSaveExtension() => "tres";
- public override string _GetSaveExtension() => "tres";
+ public override string _GetResourceType() => "Resource";
- public override string _GetResourceType() => "Resource";
+ public override int _GetPresetCount() => 0;
- public override int _GetPresetCount() => 0;
+ public override float _GetPriority() => 1.0f;
- public override float _GetPriority() => 1.0f;
+ public override int _GetImportOrder() => 0;
- public override int _GetImportOrder() => 0;
+ public override Array _GetImportOptions(string path, int presetIndex) => new();
- public override Array _GetImportOptions(string path, int presetIndex) => new();
+ public override Error _Import(
+ string assetPath,
+ string savePath,
+ Dictionary options,
+ Array platformVariants,
+ Array genFiles)
+ {
+ var extension = System.IO.Path.GetExtension(assetPath);
- public override Error _Import(
- string assetPath,
- string savePath,
- Dictionary options,
- Array platformVariants,
- Array genFiles)
+ if (extension == ".yarn")
{
- var extension = System.IO.Path.GetExtension(assetPath);
+ ImportYarn(assetPath);
+ }
- if (extension == ".yarn")
- {
- ImportYarn(assetPath);
- }
+ var importedMarkerResource = new Resource();
+ importedMarkerResource.ResourceName =
+ System.IO.Path.GetFileNameWithoutExtension(ProjectSettings.GlobalizePath(assetPath));
- var importedMarkerResource = new Resource();
- importedMarkerResource.ResourceName =
- System.IO.Path.GetFileNameWithoutExtension(ProjectSettings.GlobalizePath(assetPath));
+ var saveErr = ResourceSaver.Save(importedMarkerResource, $"{savePath}.{_GetSaveExtension()}");
+ if (saveErr != Error.Ok)
+ {
+ GD.PrintErr($"Error saving yarn file import: {saveErr.ToString()}");
+ }
- var saveErr = ResourceSaver.Save(importedMarkerResource, $"{savePath}.{_GetSaveExtension()}");
- if (saveErr != Error.Ok)
- {
- GD.PrintErr($"Error saving yarn file import: {saveErr.ToString()}");
- }
+ return (int) Error.Ok;
+ }
- return (int) Error.Ok;
+ ///
+ /// Returns a byte array containing a SHA-256 hash of .
+ ///
+ /// The string to produce a hash value
+ /// for.
+ /// The hash of .
+ private static byte[] GetHash(string inputString)
+ {
+ using (HashAlgorithm algorithm = SHA256.Create())
+ {
+ return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
+ }
- ///
- /// Returns a byte array containing a SHA-256 hash of .
- ///
- /// The string to produce a hash value
- /// for.
- /// The hash of .
- private static byte[] GetHash(string inputString)
+ ///
+ /// Returns a string containing the hexadecimal representation of a
+ /// SHA-256 hash of .
+ ///
+ /// The string to produce a hash
+ /// for.
+ /// The length of the string to
+ /// return. The returned string will be at most characters long. If this is set to -1,
+ /// the entire string will be returned.
+ /// A string version of the hash.
+ public static string GetHashString(string inputString, int limitCharacters = -1)
+ {
+ var sb = new StringBuilder();
+ foreach (byte b in GetHash(inputString))
{
- using (HashAlgorithm algorithm = SHA256.Create())
- {
- return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
- }
+ sb.Append(b.ToString("x2"));
}
- ///
- /// Returns a string containing the hexadecimal representation of a
- /// SHA-256 hash of .
- ///
- /// The string to produce a hash
- /// for.
- /// The length of the string to
- /// return. The returned string will be at most characters long. If this is set to -1,
- /// the entire string will be returned.
- /// A string version of the hash.
- public static string GetHashString(string inputString, int limitCharacters = -1)
+ if (limitCharacters == -1)
{
- var sb = new StringBuilder();
- foreach (byte b in GetHash(inputString))
- {
- sb.Append(b.ToString("x2"));
- }
-
- if (limitCharacters == -1)
- {
- // Return the entire string
- return sb.ToString();
- }
- else
- {
- // Return a substring (or the entire string, if
- // limitCharacters is longer than the string)
- return sb.ToString(0, Mathf.Min(sb.Length, limitCharacters));
- }
+ // Return the entire string
+ return sb.ToString();
}
+ else
+ {
+ // Return a substring (or the entire string, if
+ // limitCharacters is longer than the string)
+ return sb.ToString(0, Mathf.Min(sb.Length, limitCharacters));
+ }
+ }
- private void ImportYarn(string assetPath)
+ private void ImportYarn(string assetPath)
+ {
+ GD.Print($"Importing Yarn script {assetPath}");
+ var projectPath = YarnProjectEditorUtility.GetDestinationProjectPath(assetPath);
+ if (projectPath == null)
+ {
+ GD.Print($"The yarn file {assetPath} is not currently associated with a Yarn Project." +
+ " Create a Yarn Project by selecting YarnProject from the create new resource menu and make sure this" +
+ " script matches one of the patterns defined for yarn source files.");
+ }
+ else
{
- GD.Print($"Importing Yarn script {assetPath}");
- var projectPath = YarnProjectEditorUtility.GetDestinationProjectPath(assetPath);
- if (projectPath == null)
- {
- GD.Print($"The yarn file {assetPath} is not currently associated with a Yarn Project." +
- " Create a Yarn Project by selecting YarnProject from the create new resource menu and make sure this" +
- " script matches one of the patterns defined for yarn source files.");
- }
- else
- {
- // trigger update of the yarn project
- var godotProject = ResourceLoader.Load(projectPath);
- YarnProjectEditorUtility.UpdateYarnProject(godotProject);
- }
+ // trigger update of the yarn project
+ var godotProject = ResourceLoader.Load(projectPath);
+ YarnProjectEditorUtility.UpdateYarnProject(godotProject);
}
}
}
diff --git a/addons/YarnSpinner-Godot/Editor/YarnMarkupPaletteInspectorPlugin.cs b/addons/YarnSpinner-Godot/Editor/YarnMarkupPaletteInspectorPlugin.cs
index 7d04946..d30a20b 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnMarkupPaletteInspectorPlugin.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnMarkupPaletteInspectorPlugin.cs
@@ -5,124 +5,123 @@
using YarnSpinnerGodot.Editor.UI;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+///
+/// Custom inspector for that allows the user
+/// to add / remove markup tags and set their associated colors.
+///
+[Tool]
+public partial class YarnMarkupPaletteInspectorPlugin : EditorInspectorPlugin
{
- ///
- /// Custom inspector for that allows the user
- /// to add / remove markup tags and set their associated colors.
- ///
- [Tool]
- public partial class YarnMarkupPaletteInspectorPlugin : EditorInspectorPlugin
- {
- public override bool _CanHandle(GodotObject obj) => obj is MarkupPalette;
+ public override bool _CanHandle(GodotObject obj) => obj is MarkupPalette;
- public override bool _ParseProperty(GodotObject @object, Variant.Type type,
- string path,
- PropertyHint hint, string hintText, PropertyUsageFlags usage, bool wide)
+ public override bool _ParseProperty(GodotObject @object, Variant.Type type,
+ string path,
+ PropertyHint hint, string hintText, PropertyUsageFlags usage, bool wide)
+ {
+ if (@object is not MarkupPalette palette)
{
- if (@object is not MarkupPalette palette)
- {
- return false;
- }
+ return false;
+ }
- try
+ try
+ {
+ if (path == nameof(MarkupPalette.ColourMarkers))
{
- if (path == nameof(MarkupPalette.ColourMarkers))
+ AddCustomControl(new Label
+ {Text = "Map [markup] tag names to colors"});
+ if (palette.ColourMarkers.Count == 0)
{
- AddCustomControl(new Label
- {Text = "Map [markup] tag names to colors"});
- if (palette.ColourMarkers.Count == 0)
- {
- var noColorsLabel = new Label();
- noColorsLabel.Text = "No colors remapped";
- AddCustomControl(noColorsLabel);
- }
- else
+ var noColorsLabel = new Label();
+ noColorsLabel.Text = "No colors remapped";
+ AddCustomControl(noColorsLabel);
+ }
+ else
+ {
+ var colorRemapGrid = new GridContainer();
+ colorRemapGrid.Columns = 3;
+ colorRemapGrid.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
+ colorRemapGrid.SizeFlagsHorizontal =
+ Control.SizeFlags.ExpandFill;
+
+ var originalHeader = new Label();
+ originalHeader.Text = "Markup Tag";
+ colorRemapGrid.AddChild(originalHeader);
+
+ var replacementHeader = new Label();
+ replacementHeader.Text = "Text Color";
+ colorRemapGrid.AddChild(replacementHeader);
+
+ var deleteHeader = new Label();
+ deleteHeader.Text = "Delete";
+ colorRemapGrid.AddChild(deleteHeader);
+ const int remapHeight = 4;
+ foreach (var tagName in palette.ColourMarkers.Keys)
{
- var colorRemapGrid = new GridContainer();
- colorRemapGrid.Columns = 3;
- colorRemapGrid.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
- colorRemapGrid.SizeFlagsHorizontal =
+ colorRemapGrid.AddChild(new Label {Text = tagName});
+
+ var replacementColorButton = new MarkupPaletteColorButton
+ {palette = palette, tagName = tagName};
+ replacementColorButton.Color =
+ palette.ColourMarkers[tagName];
+ replacementColorButton.Size = new Vector2(0, remapHeight);
+ replacementColorButton.SizeFlagsHorizontal =
Control.SizeFlags.ExpandFill;
+ colorRemapGrid.AddChild(replacementColorButton);
- var originalHeader = new Label();
- originalHeader.Text = "Markup Tag";
- colorRemapGrid.AddChild(originalHeader);
+ var deleteArea = new HBoxContainer();
+ var deleteSpacer = new Label {Text = " "};
- var replacementHeader = new Label();
- replacementHeader.Text = "Text Color";
- colorRemapGrid.AddChild(replacementHeader);
-
- var deleteHeader = new Label();
- deleteHeader.Text = "Delete";
- colorRemapGrid.AddChild(deleteHeader);
- const int remapHeight = 4;
- foreach (var tagName in palette.ColourMarkers.Keys)
+ var deleteButton = new MarkupPaletteDeleteTagButton
{
- colorRemapGrid.AddChild(new Label {Text = tagName});
-
- var replacementColorButton = new MarkupPaletteColorButton
- {palette = palette, tagName = tagName};
- replacementColorButton.Color =
- palette.ColourMarkers[tagName];
- replacementColorButton.Size = new Vector2(0, remapHeight);
- replacementColorButton.SizeFlagsHorizontal =
- Control.SizeFlags.ExpandFill;
- colorRemapGrid.AddChild(replacementColorButton);
-
- var deleteArea = new HBoxContainer();
- var deleteSpacer = new Label {Text = " "};
-
- var deleteButton = new MarkupPaletteDeleteTagButton
- {
- Text = "X",
- tagName = tagName,
- palette = palette
- };
- deleteButton.Text = "x";
- deleteButton.AddThemeColorOverride("normal", Colors.Red);
- deleteButton.Size = new Vector2(4, remapHeight);
- deleteButton.SizeFlagsHorizontal = 0;
-
- deleteArea.AddChild(deleteSpacer);
- deleteArea.AddChild(deleteButton);
- colorRemapGrid.AddChild(deleteArea);
- }
-
- AddCustomControl(colorRemapGrid);
+ Text = "X",
+ tagName = tagName,
+ palette = palette
+ };
+ deleteButton.Text = "x";
+ deleteButton.AddThemeColorOverride("normal", Colors.Red);
+ deleteButton.Size = new Vector2(4, remapHeight);
+ deleteButton.SizeFlagsHorizontal = 0;
+
+ deleteArea.AddChild(deleteSpacer);
+ deleteArea.AddChild(deleteButton);
+ colorRemapGrid.AddChild(deleteArea);
}
- var newTagRow = new HBoxContainer();
- var addNewTagButton = new MarkupPaletteAddTagButton
- {Text = "Add", palette = palette};
-
- var newTagNameInput = new LineEditWithSubmit()
- {
- PlaceholderText = "tag name, without []",
- CustomMinimumSize = new Vector2(80, 10),
- SubmitButton = addNewTagButton
- };
- addNewTagButton.newTagNameInput = newTagNameInput;
- newTagNameInput.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
- addNewTagButton.Disabled = true;
-
- newTagRow.AddChild(newTagNameInput);
- newTagRow.AddChild(addNewTagButton);
- newTagRow.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
- newTagRow.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
- AddCustomControl(newTagRow);
-
- return true;
+ AddCustomControl(colorRemapGrid);
}
- return false;
- }
- catch (Exception e)
- {
- GD.PushError(
- $"Error in {nameof(YarnMarkupPaletteInspectorPlugin)}: {e.Message}\n{e.StackTrace}");
- return false;
+ var newTagRow = new HBoxContainer();
+ var addNewTagButton = new MarkupPaletteAddTagButton
+ {Text = "Add", palette = palette};
+
+ var newTagNameInput = new LineEditWithSubmit()
+ {
+ PlaceholderText = "tag name, without []",
+ CustomMinimumSize = new Vector2(80, 10),
+ SubmitButton = addNewTagButton
+ };
+ addNewTagButton.newTagNameInput = newTagNameInput;
+ newTagNameInput.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
+ addNewTagButton.Disabled = true;
+
+ newTagRow.AddChild(newTagNameInput);
+ newTagRow.AddChild(addNewTagButton);
+ newTagRow.SizeFlagsVertical = Control.SizeFlags.ExpandFill;
+ newTagRow.SizeFlagsHorizontal = Control.SizeFlags.ExpandFill;
+ AddCustomControl(newTagRow);
+
+ return true;
}
+
+ return false;
+ }
+ catch (Exception e)
+ {
+ GD.PushError(
+ $"Error in {nameof(YarnMarkupPaletteInspectorPlugin)}: {e.Message}\n{e.StackTrace}");
+ return false;
}
}
}
diff --git a/addons/YarnSpinner-Godot/Editor/YarnProjectEditorUtility.cs b/addons/YarnSpinner-Godot/Editor/YarnProjectEditorUtility.cs
index 0174615..448d871 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnProjectEditorUtility.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnProjectEditorUtility.cs
@@ -21,886 +21,885 @@
using FileAccess = System.IO.FileAccess;
using Path = System.IO.Path;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+[Tool]
+public static class YarnProjectEditorUtility
{
- [Tool]
- public static class YarnProjectEditorUtility
+ ///
+ /// The contents of a .csv.import file to avoid importing it as a Godot localization csv file
+ ///
+ public const string KEEP_IMPORT_TEXT = "[remap]\n\nimporter=\"keep\"";
+
+ ///
+ /// Find an associated yarn project in the same or ancestor directory
+ ///
+ ///
+ ///
+ public static string GetDestinationProjectPath(string scriptPath)
{
- ///
- /// The contents of a .csv.import file to avoid importing it as a Godot localization csv file
- ///
- public const string KEEP_IMPORT_TEXT = "[remap]\n\nimporter=\"keep\"";
-
- ///
- /// Find an associated yarn project in the same or ancestor directory
- ///
- ///
- ///
- public static string GetDestinationProjectPath(string scriptPath)
- {
- string destinationProjectPath = null;
- var globalScriptPath = Path.GetFullPath(ProjectSettings.GlobalizePath(scriptPath));
- var allProjects = FindAllYarnProjects();
- foreach (var project in allProjects)
+ string destinationProjectPath = null;
+ var globalScriptPath = Path.GetFullPath(ProjectSettings.GlobalizePath(scriptPath));
+ var allProjects = FindAllYarnProjects();
+ foreach (var project in allProjects)
+ {
+ var projectPath = ProjectSettings.GlobalizePath(project.ToString())
+ .Replace("\\", "/");
+ try
{
- var projectPath = ProjectSettings.GlobalizePath(project.ToString())
- .Replace("\\", "/");
- try
- {
- var loadedProject = Yarn.Compiler.Project.LoadFromFile(projectPath);
- if (!loadedProject.SourceFiles.Contains(globalScriptPath))
- {
- continue;
- }
-
- destinationProjectPath = ProjectSettings.LocalizePath(projectPath);
- break;
- }
- catch (Exception e)
+ var loadedProject = Yarn.Compiler.Project.LoadFromFile(projectPath);
+ if (!loadedProject.SourceFiles.Contains(globalScriptPath))
{
- GD.PushError(
- $"Error while searching for the project associated with {scriptPath}: {e.Message}\n{e.StackTrace}");
+ continue;
}
- }
- return destinationProjectPath;
+ destinationProjectPath = ProjectSettings.LocalizePath(projectPath);
+ break;
+ }
+ catch (Exception e)
+ {
+ GD.PushError(
+ $"Error while searching for the project associated with {scriptPath}: {e.Message}\n{e.StackTrace}");
+ }
}
- private static IEnumerable FindAllYarnProjects()
- {
- var projectMatcher = new Matcher();
- projectMatcher.AddInclude($"**/*{YarnProject.YARN_PROJECT_EXTENSION}");
- return projectMatcher.GetResultsInFullPath(ProjectSettings.GlobalizePath("res://"))
- .Select(ProjectSettings.LocalizePath);
- }
+ return destinationProjectPath;
+ }
+
+ private static IEnumerable FindAllYarnProjects()
+ {
+ var projectMatcher = new Matcher();
+ projectMatcher.AddInclude($"**/*{YarnProject.YARN_PROJECT_EXTENSION}");
+ return projectMatcher.GetResultsInFullPath(ProjectSettings.GlobalizePath("res://"))
+ .Select(ProjectSettings.LocalizePath);
+ }
- private const int PROJECT_UPDATE_TIMEOUT = 80; // ms
+ private const int PROJECT_UPDATE_TIMEOUT = 80; // ms
- private static ConcurrentDictionary _projectPathToLastUpdateTime =
- new ConcurrentDictionary();
+ private static ConcurrentDictionary _projectPathToLastUpdateTime =
+ new ConcurrentDictionary();
- private static Dictionary _projectPathToUpdateTask = new Dictionary();
- private static object _lastUpdateLock = new object();
+ private static Dictionary _projectPathToUpdateTask = new Dictionary();
+ private static object _lastUpdateLock = new object();
- ///
- /// Queue up a re-compile of scripts in a yarn project, add all associated data to the project,
- /// and save it back to disk in the same .tres file. This will wait for
- /// before updating the project, resetting the timeout each time it is called for a given YarnProject.
- /// Call this method when you want to avoid repeated updates of the same project.
- ///
- /// The yarn project to re-compile scripts for
- public static void UpdateYarnProject(YarnProject project)
+ ///
+ /// Queue up a re-compile of scripts in a yarn project, add all associated data to the project,
+ /// and save it back to disk in the same .tres file. This will wait for
+ /// before updating the project, resetting the timeout each time it is called for a given YarnProject.
+ /// Call this method when you want to avoid repeated updates of the same project.
+ ///
+ /// The yarn project to re-compile scripts for
+ public static void UpdateYarnProject(YarnProject project)
+ {
+ if (project == null)
{
- if (project == null)
- {
- return;
- }
+ return;
+ }
- ;
- if (string.IsNullOrEmpty(project.ResourcePath))
+ ;
+ if (string.IsNullOrEmpty(project.ResourcePath))
+ {
+ return;
+ }
+
+ lock (_lastUpdateLock)
+ {
+ _projectPathToLastUpdateTime[project.ResourcePath] = DateTime.Now;
+ if (!_projectPathToUpdateTask.ContainsKey(project.ResourcePath))
{
- return;
+ _projectPathToUpdateTask[project.ResourcePath] = UpdateYarnProjectTask(project);
}
+ }
+ }
+ private static async Task UpdateYarnProjectTask(YarnProject project)
+ {
+ TimeSpan getTimeDiff()
+ {
lock (_lastUpdateLock)
{
- _projectPathToLastUpdateTime[project.ResourcePath] = DateTime.Now;
- if (!_projectPathToUpdateTask.ContainsKey(project.ResourcePath))
- {
- _projectPathToUpdateTask[project.ResourcePath] = UpdateYarnProjectTask(project);
- }
+ return DateTime.Now - _projectPathToLastUpdateTime[project.ResourcePath];
}
}
- private static async Task UpdateYarnProjectTask(YarnProject project)
+ while (getTimeDiff() < TimeSpan.FromMilliseconds(PROJECT_UPDATE_TIMEOUT))
{
- TimeSpan getTimeDiff()
- {
- lock (_lastUpdateLock)
- {
- return DateTime.Now - _projectPathToLastUpdateTime[project.ResourcePath];
- }
- }
+ // wait to update the yarn project until we haven't received another request in PROJECT_UPDATE_TIMEOUT ms
+ await Task.Delay(PROJECT_UPDATE_TIMEOUT);
+ }
- while (getTimeDiff() < TimeSpan.FromMilliseconds(PROJECT_UPDATE_TIMEOUT))
+ try
+ {
+ CompileAllScripts(project);
+ SaveYarnProject(project);
+ }
+ catch (Exception e)
+ {
+ GD.PushError(
+ $"Error updating {nameof(YarnProject)} '{project.ResourcePath}': {e.Message}{e.StackTrace}");
+ }
+ finally
+ {
+ lock (_lastUpdateLock)
{
- // wait to update the yarn project until we haven't received another request in PROJECT_UPDATE_TIMEOUT ms
- await Task.Delay(PROJECT_UPDATE_TIMEOUT);
+ _projectPathToUpdateTask.Remove(project.ResourcePath);
}
+ }
+ }
- try
+ public static void WriteBaseLanguageStringsCSV(YarnProject project, string path)
+ {
+ UpdateLocalizationFile(project.baseLocalization.GetStringTableEntries(),
+ project.JSONProject.BaseLanguage, path, false);
+ }
+
+ public static void UpdateLocalizationCSVs(YarnProject project)
+ {
+ if (project.JSONProject.Localisation.Count > 0)
+ {
+ var modifiedFiles = new List();
+ if (project.baseLocalization == null)
{
CompileAllScripts(project);
- SaveYarnProject(project);
}
- catch (Exception e)
- {
- GD.PushError(
- $"Error updating {nameof(YarnProject)} '{project.ResourcePath}': {e.Message}{e.StackTrace}");
- }
- finally
- {
- lock (_lastUpdateLock)
- {
- _projectPathToUpdateTask.Remove(project.ResourcePath);
- }
- }
- }
- public static void WriteBaseLanguageStringsCSV(YarnProject project, string path)
- {
- UpdateLocalizationFile(project.baseLocalization.GetStringTableEntries(),
- project.JSONProject.BaseLanguage, path, false);
- }
-
- public static void UpdateLocalizationCSVs(YarnProject project)
- {
- if (project.JSONProject.Localisation.Count > 0)
+ foreach (var loc in project.JSONProject.Localisation)
{
- var modifiedFiles = new List();
- if (project.baseLocalization == null)
+ if (string.IsNullOrEmpty(loc.Value.Strings))
{
- CompileAllScripts(project);
+ GD.PrintErr(
+ $"Can't update localization for {loc.Key} because it doesn't have a Strings file.");
+ continue;
}
- foreach (var loc in project.JSONProject.Localisation)
- {
- if (string.IsNullOrEmpty(loc.Value.Strings))
- {
- GD.PrintErr(
- $"Can't update localization for {loc.Key} because it doesn't have a Strings file.");
- continue;
- }
+ var fileWasChanged = UpdateLocalizationFile(project.baseLocalization.GetStringTableEntries(),
+ loc.Key, loc.Value.Strings);
- var fileWasChanged = UpdateLocalizationFile(project.baseLocalization.GetStringTableEntries(),
- loc.Key, loc.Value.Strings);
-
- if (fileWasChanged)
- {
- modifiedFiles.Add(loc.Value.Strings);
- }
- }
-
- if (modifiedFiles.Count > 0)
+ if (fileWasChanged)
{
- GD.Print($"Updated the following files: {string.Join(", ", modifiedFiles)}");
- }
- else
- {
- GD.Print($"No Localization CSV files needed updating.");
+ modifiedFiles.Add(loc.Value.Strings);
}
}
- }
-
- ///
- /// Verifies the CSV file referred to by csvResourcePath and updates it if
- /// necessary.
- ///
- /// A collection of
- /// The language that provides strings for.
- /// res:// path to the destination CSV to update
- /// Whether the contents of was modified.
- private static bool UpdateLocalizationFile(IEnumerable baseLocalizationStrings,
- string language, string csvResourcePath, bool generateTranslation = true)
- {
- var absoluteCSVPath = ProjectSettings.GlobalizePath(csvResourcePath);
-
- // Tracks if the translated localisation needed modifications
- // (either new lines added, old lines removed, or changed lines
- // flagged)
- var modificationsNeeded = false;
- IEnumerable translatedStrings = new List();
- if (File.Exists(absoluteCSVPath))
+ if (modifiedFiles.Count > 0)
{
- var existingCSVText = File.ReadAllText(absoluteCSVPath);
- translatedStrings = StringTableEntry.ParseFromCSV(existingCSVText);
+ GD.Print($"Updated the following files: {string.Join(", ", modifiedFiles)}");
}
else
{
- GD.Print(
- $"CSV file {csvResourcePath} did not exist for locale {language}. A new file will be created at that location.");
- modificationsNeeded = true;
+ GD.Print($"No Localization CSV files needed updating.");
}
+ }
+ }
- // Convert both enumerables to dictionaries, for easier lookup
- var baseDictionary = baseLocalizationStrings.ToDictionary(entry => entry.ID);
- var translatedDictionary = translatedStrings.ToDictionary(entry => entry.ID);
+ ///
+ /// Verifies the CSV file referred to by csvResourcePath and updates it if
+ /// necessary.
+ ///
+ /// A collection of
+ /// The language that provides strings for.
+ /// res:// path to the destination CSV to update
+ /// Whether the contents of was modified.
+ private static bool UpdateLocalizationFile(IEnumerable baseLocalizationStrings,
+ string language, string csvResourcePath, bool generateTranslation = true)
+ {
+ var absoluteCSVPath = ProjectSettings.GlobalizePath(csvResourcePath);
- // The list of line IDs present in each localisation
- var baseIDs = baseLocalizationStrings.Select(entry => entry.ID);
- foreach (var str in translatedStrings)
- {
- if (baseDictionary.ContainsKey(str.ID))
- {
- str.Original = baseDictionary[str.ID].Text;
- }
- }
+ // Tracks if the translated localisation needed modifications
+ // (either new lines added, old lines removed, or changed lines
+ // flagged)
+ var modificationsNeeded = false;
- var translatedIDs = translatedStrings.Select(entry => entry.ID);
+ IEnumerable translatedStrings = new List();
+ if (File.Exists(absoluteCSVPath))
+ {
+ var existingCSVText = File.ReadAllText(absoluteCSVPath);
+ translatedStrings = StringTableEntry.ParseFromCSV(existingCSVText);
+ }
+ else
+ {
+ GD.Print(
+ $"CSV file {csvResourcePath} did not exist for locale {language}. A new file will be created at that location.");
+ modificationsNeeded = true;
+ }
- // The list of line IDs that are ONLY present in each
- // localisation
- var onlyInBaseIDs = baseIDs.Except(translatedIDs);
- var onlyInTranslatedIDs = translatedIDs.Except(baseIDs);
+ // Convert both enumerables to dictionaries, for easier lookup
+ var baseDictionary = baseLocalizationStrings.ToDictionary(entry => entry.ID);
+ var translatedDictionary = translatedStrings.ToDictionary(entry => entry.ID);
- // Remove every entry whose ID is only present in the
- // translated set. This entry has been removed from the base
- // localization.
- foreach (var id in onlyInTranslatedIDs.ToList())
- {
- translatedDictionary.Remove(id);
- modificationsNeeded = true;
- }
-
- // Conversely, for every entry that is only present in the base
- // localisation, we need to create a new entry for it.
- foreach (var id in onlyInBaseIDs)
+ // The list of line IDs present in each localisation
+ var baseIDs = baseLocalizationStrings.Select(entry => entry.ID);
+ foreach (var str in translatedStrings)
+ {
+ if (baseDictionary.ContainsKey(str.ID))
{
- StringTableEntry baseEntry = baseDictionary[id];
- baseEntry.File = ProjectSettings.LocalizePath(baseEntry.File);
- var newEntry = new StringTableEntry(baseEntry)
- {
- // Empty this text, so that it's apparent that a
- // translated version needs to be provided.
- Text = string.Empty,
- Original = baseEntry.Text,
- Language = language,
- };
- translatedDictionary.Add(id, newEntry);
- modificationsNeeded = true;
+ str.Original = baseDictionary[str.ID].Text;
}
+ }
- // Finally, we need to check for any entries in the translated
- // localisation that:
- // 1. have the same line ID as one in the base, but
- // 2. have a different Lock (the hash of the text), which
- // indicates that the base text has changed.
-
- // First, get the list of IDs that are in both base and
- // translated, and then filter this list to any where the lock
- // values differ
- var outOfDateLockIDs = baseDictionary.Keys
- .Intersect(translatedDictionary.Keys)
- .Where(id => baseDictionary[id].Lock != translatedDictionary[id].Lock);
-
- // Now loop over all of these, and update our translated
- // dictionary to include a note that it needs attention
- foreach (var id in outOfDateLockIDs)
- {
- // Get the translated entry as it currently exists
- var entry = translatedDictionary[id];
-
- // Include a note that this entry is out of date
- entry.Text = $"(NEEDS UPDATE) {entry.Text}";
-
- // update the base language text
- entry.Original = baseDictionary[id].Text;
- // Update the lock to match the new one
- entry.Lock = baseDictionary[id].Lock;
+ var translatedIDs = translatedStrings.Select(entry => entry.ID);
- // Put this modified entry back in the table
- translatedDictionary[id] = entry;
+ // The list of line IDs that are ONLY present in each
+ // localisation
+ var onlyInBaseIDs = baseIDs.Except(translatedIDs);
+ var onlyInTranslatedIDs = translatedIDs.Except(baseIDs);
- modificationsNeeded = true;
- }
+ // Remove every entry whose ID is only present in the
+ // translated set. This entry has been removed from the base
+ // localization.
+ foreach (var id in onlyInTranslatedIDs.ToList())
+ {
+ translatedDictionary.Remove(id);
+ modificationsNeeded = true;
+ }
- // We're all done!
+ // Conversely, for every entry that is only present in the base
+ // localisation, we need to create a new entry for it.
+ foreach (var id in onlyInBaseIDs)
+ {
+ StringTableEntry baseEntry = baseDictionary[id];
+ baseEntry.File = ProjectSettings.LocalizePath(baseEntry.File);
+ var newEntry = new StringTableEntry(baseEntry)
+ {
+ // Empty this text, so that it's apparent that a
+ // translated version needs to be provided.
+ Text = string.Empty,
+ Original = baseEntry.Text,
+ Language = language,
+ };
+ translatedDictionary.Add(id, newEntry);
+ modificationsNeeded = true;
+ }
- if (modificationsNeeded == false)
- {
- if (generateTranslation)
- {
- GenerateGodotTranslation(language, csvResourcePath);
- }
+ // Finally, we need to check for any entries in the translated
+ // localisation that:
+ // 1. have the same line ID as one in the base, but
+ // 2. have a different Lock (the hash of the text), which
+ // indicates that the base text has changed.
+
+ // First, get the list of IDs that are in both base and
+ // translated, and then filter this list to any where the lock
+ // values differ
+ var outOfDateLockIDs = baseDictionary.Keys
+ .Intersect(translatedDictionary.Keys)
+ .Where(id => baseDictionary[id].Lock != translatedDictionary[id].Lock);
+
+ // Now loop over all of these, and update our translated
+ // dictionary to include a note that it needs attention
+ foreach (var id in outOfDateLockIDs)
+ {
+ // Get the translated entry as it currently exists
+ var entry = translatedDictionary[id];
- // No changes needed to be done to the translated string
- // table entries. Stop here.
- return false;
- }
+ // Include a note that this entry is out of date
+ entry.Text = $"(NEEDS UPDATE) {entry.Text}";
- // We need to produce a replacement CSV file for the translated
- // entries.
+ // update the base language text
+ entry.Original = baseDictionary[id].Text;
+ // Update the lock to match the new one
+ entry.Lock = baseDictionary[id].Lock;
- var outputStringEntries = translatedDictionary.Values
- .OrderBy(entry => entry.File)
- .ThenBy(entry => int.Parse(entry.LineNumber));
+ // Put this modified entry back in the table
+ translatedDictionary[id] = entry;
- var outputCSV = StringTableEntry.CreateCSV(outputStringEntries);
+ modificationsNeeded = true;
+ }
- // Write out the replacement text to this existing file,
- // replacing its existing contents
- File.WriteAllText(absoluteCSVPath, outputCSV, System.Text.Encoding.UTF8);
- var csvImport = $"{absoluteCSVPath}.import";
- if (!File.Exists(csvImport))
- {
- File.WriteAllText(csvImport, KEEP_IMPORT_TEXT);
- }
+ // We're all done!
+ if (modificationsNeeded == false)
+ {
if (generateTranslation)
{
GenerateGodotTranslation(language, csvResourcePath);
}
- // Signal that the file was changed
- return true;
+ // No changes needed to be done to the translated string
+ // table entries. Stop here.
+ return false;
}
- private static void GenerateGodotTranslation(string language, string csvFilePath)
- {
- var absoluteCSVPath = ProjectSettings.GlobalizePath(csvFilePath);
- var translation = new Translation();
- translation.Locale = language;
+ // We need to produce a replacement CSV file for the translated
+ // entries.
- var csvText = File.ReadAllText(absoluteCSVPath);
- var stringEntries = StringTableEntry.ParseFromCSV(csvText);
- foreach (var entry in stringEntries)
- {
- translation.AddMessage(entry.ID, entry.Text);
- }
+ var outputStringEntries = translatedDictionary.Values
+ .OrderBy(entry => entry.File)
+ .ThenBy(entry => int.Parse(entry.LineNumber));
+
+ var outputCSV = StringTableEntry.CreateCSV(outputStringEntries);
- var extensionRegex = new Regex(@".csv$");
- var translationPath = extensionRegex.Replace(absoluteCSVPath, ".translation");
- var translationResPath = ProjectSettings.LocalizePath(translationPath);
- ResourceSaver.Save(translation, translationResPath);
- GD.Print($"Wrote translation file for {language} to {translationResPath}.");
+ // Write out the replacement text to this existing file,
+ // replacing its existing contents
+ File.WriteAllText(absoluteCSVPath, outputCSV, System.Text.Encoding.UTF8);
+ var csvImport = $"{absoluteCSVPath}.import";
+ if (!File.Exists(csvImport))
+ {
+ File.WriteAllText(csvImport, KEEP_IMPORT_TEXT);
}
- ///
- /// Workaround for https://github.com/godotengine/godot/issues/78513
- ///
- public static void ClearJSONCache()
+ if (generateTranslation)
{
- var assembly = typeof(JsonSerializerOptions).Assembly;
- var updateHandlerType = assembly.GetType("System.Text.Json.JsonSerializerOptionsUpdateHandler");
- var clearCacheMethod =
- updateHandlerType?.GetMethod("ClearCache", BindingFlags.Static | BindingFlags.Public);
- clearCacheMethod?.Invoke(null, new object[] {null});
+ GenerateGodotTranslation(language, csvResourcePath);
}
- public static void SaveYarnProject(YarnProject project)
+ // Signal that the file was changed
+ return true;
+ }
+
+ private static void GenerateGodotTranslation(string language, string csvFilePath)
+ {
+ var absoluteCSVPath = ProjectSettings.GlobalizePath(csvFilePath);
+ var translation = new Translation();
+ translation.Locale = language;
+
+ var csvText = File.ReadAllText(absoluteCSVPath);
+ var stringEntries = StringTableEntry.ParseFromCSV(csvText);
+ foreach (var entry in stringEntries)
{
- // force the JSON serialization to update before saving
- if (GodotObject.IsInstanceValid(project.baseLocalization))
- {
- project.baseLocalization.stringTable = project.baseLocalization.stringTable;
- }
+ translation.AddMessage(entry.ID, entry.Text);
+ }
- project.LineMetadata = project.LineMetadata;
- project.ListOfFunctions = project.ListOfFunctions;
- project.SerializedDeclarations = project.SerializedDeclarations;
- if (string.IsNullOrEmpty(project.JSONProjectPath))
- {
- project.JSONProjectPath = project.DefaultJSONProjectPath;
- }
+ var extensionRegex = new Regex(@".csv$");
+ var translationPath = extensionRegex.Replace(absoluteCSVPath, ".translation");
+ var translationResPath = ProjectSettings.LocalizePath(translationPath);
+ ResourceSaver.Save(translation, translationResPath);
+ GD.Print($"Wrote translation file for {language} to {translationResPath}.");
+ }
- // Prevent plugin failing to load when code is rebuilt
- ClearJSONCache();
- var saveErr = ResourceSaver.Save(project, project.ImportPath);
- if (saveErr != Error.Ok)
- {
- GD.PushError($"Error updating YarnProject {project.ResourceName} to {project.ResourcePath}: {saveErr}");
- }
- else
- {
- GD.Print($"Wrote updated YarnProject {project.ResourceName} to {project.ResourcePath}");
- }
+ ///
+ /// Workaround for https://github.com/godotengine/godot/issues/78513
+ ///
+ public static void ClearJSONCache()
+ {
+ var assembly = typeof(JsonSerializerOptions).Assembly;
+ var updateHandlerType = assembly.GetType("System.Text.Json.JsonSerializerOptionsUpdateHandler");
+ var clearCacheMethod =
+ updateHandlerType?.GetMethod("ClearCache", BindingFlags.Static | BindingFlags.Public);
+ clearCacheMethod?.Invoke(null, new object[] {null});
+ }
+
+ public static void SaveYarnProject(YarnProject project)
+ {
+ // force the JSON serialization to update before saving
+ if (GodotObject.IsInstanceValid(project.baseLocalization))
+ {
+ project.baseLocalization.stringTable = project.baseLocalization.stringTable;
}
- public static void CompileAllScripts(YarnProject project)
+ project.LineMetadata = project.LineMetadata;
+ project.ListOfFunctions = project.ListOfFunctions;
+ project.SerializedDeclarations = project.SerializedDeclarations;
+ if (string.IsNullOrEmpty(project.JSONProjectPath))
{
- lock (project)
- {
- List newFunctionList = new List();
- var assetPath = project.ResourcePath;
- GD.Print($"Compiling all scripts in {assetPath}");
+ project.JSONProjectPath = project.DefaultJSONProjectPath;
+ }
- project.ResourceName = Path.GetFileNameWithoutExtension(assetPath);
- var sourceScripts = project.JSONProject.SourceFiles.ToList();
- if (!sourceScripts.Any())
- {
- GD.Print(
- $"No .yarn files found matching the {nameof(project.JSONProject.SourceFilePatterns)} in {project.JSONProjectPath}");
- return;
- }
+ // Prevent plugin failing to load when code is rebuilt
+ ClearJSONCache();
+ var saveErr = ResourceSaver.Save(project, project.ImportPath);
+ if (saveErr != Error.Ok)
+ {
+ GD.PushError($"Error updating YarnProject {project.ResourceName} to {project.ResourcePath}: {saveErr}");
+ }
+ else
+ {
+ GD.Print($"Wrote updated YarnProject {project.ResourceName} to {project.ResourcePath}");
+ }
+ }
- var library = new Library();
+ public static void CompileAllScripts(YarnProject project)
+ {
+ lock (project)
+ {
+ List newFunctionList = new List();
+ var assetPath = project.ResourcePath;
+ GD.Print($"Compiling all scripts in {assetPath}");
- IEnumerable errors;
- project.ProjectErrors = Array.Empty();
+ project.ResourceName = Path.GetFileNameWithoutExtension(assetPath);
+ var sourceScripts = project.JSONProject.SourceFiles.ToList();
+ if (!sourceScripts.Any())
+ {
+ GD.Print(
+ $"No .yarn files found matching the {nameof(project.JSONProject.SourceFilePatterns)} in {project.JSONProjectPath}");
+ return;
+ }
- // We now now compile!
- var scriptAbsolutePaths = sourceScripts.ToList().Where(s => s != null)
- .Select(ProjectSettings.GlobalizePath).ToList();
- // Store the compiled program
- byte[] compiledBytes = null;
- CompilationResult? compilationResult = new CompilationResult?();
- if (scriptAbsolutePaths.Count > 0)
- {
- var job = CompilationJob.CreateFromFiles(scriptAbsolutePaths);
- // job.VariableDeclarations = localDeclarations;
- job.CompilationType = CompilationJob.Type.FullCompilation;
- job.Library = library;
- compilationResult = Yarn.Compiler.Compiler.Compile(job);
+ var library = new Library();
- errors = compilationResult.Value.Diagnostics.Where(d =>
- d.Severity == Diagnostic.DiagnosticSeverity.Error);
+ IEnumerable errors;
+ project.ProjectErrors = Array.Empty();
- if (errors.Count() > 0)
+ // We now now compile!
+ var scriptAbsolutePaths = sourceScripts.ToList().Where(s => s != null)
+ .Select(ProjectSettings.GlobalizePath).ToList();
+ // Store the compiled program
+ byte[] compiledBytes = null;
+ CompilationResult? compilationResult = new CompilationResult?();
+ if (scriptAbsolutePaths.Count > 0)
+ {
+ var job = CompilationJob.CreateFromFiles(scriptAbsolutePaths);
+ // job.VariableDeclarations = localDeclarations;
+ job.CompilationType = CompilationJob.Type.FullCompilation;
+ job.Library = library;
+ compilationResult = Yarn.Compiler.Compiler.Compile(job);
+
+ errors = compilationResult.Value.Diagnostics.Where(d =>
+ d.Severity == Diagnostic.DiagnosticSeverity.Error);
+
+ if (errors.Count() > 0)
+ {
+ var errorGroups = errors.GroupBy(e => e.FileName);
+ foreach (var errorGroup in errorGroups)
{
- var errorGroups = errors.GroupBy(e => e.FileName);
- foreach (var errorGroup in errorGroups)
- {
- var errorMessages = errorGroup.Select(e => e.ToString());
+ var errorMessages = errorGroup.Select(e => e.ToString());
- foreach (var message in errorMessages)
- {
- GD.PushError($"Error compiling: {message}");
- }
+ foreach (var message in errorMessages)
+ {
+ GD.PushError($"Error compiling: {message}");
}
-
- var projectErrors = errors.ToList().ConvertAll(e =>
- new YarnProjectError
- {
- Context = e.Context,
- Message = e.Message,
- FileName = ProjectSettings.LocalizePath(e.FileName)
- });
- project.ProjectErrors = projectErrors.ToArray();
- return;
}
- if (compilationResult.Value.Program == null)
- {
- GD.PushError(
- "public error: Failed to compile: resulting program was null, but compiler did not report errors.");
- return;
- }
+ var projectErrors = errors.ToList().ConvertAll(e =>
+ new YarnProjectError
+ {
+ Context = e.Context,
+ Message = e.Message,
+ FileName = ProjectSettings.LocalizePath(e.FileName)
+ });
+ project.ProjectErrors = projectErrors.ToArray();
+ return;
+ }
+
+ if (compilationResult.Value.Program == null)
+ {
+ GD.PushError(
+ "public error: Failed to compile: resulting program was null, but compiler did not report errors.");
+ return;
+ }
- // Store _all_ declarations - both the ones in this
- // .yarnproject file, and the ones inside the .yarn files.
+ // Store _all_ declarations - both the ones in this
+ // .yarnproject file, and the ones inside the .yarn files.
- // While we're here, filter out any declarations that begin with our
- // Yarn public prefix. These are synthesized variables that are
- // generated as a result of the compilation, and are not declared by
- // the user.
+ // While we're here, filter out any declarations that begin with our
+ // Yarn public prefix. These are synthesized variables that are
+ // generated as a result of the compilation, and are not declared by
+ // the user.
- var newDeclarations = new List() //localDeclarations
- .Concat(compilationResult.Value.Declarations)
- .Where(decl => !decl.Name.StartsWith("$Yarn.Internal."))
- .Where(decl => !(decl.Type is FunctionType))
- .Select(decl =>
+ var newDeclarations = new List() //localDeclarations
+ .Concat(compilationResult.Value.Declarations)
+ .Where(decl => !decl.Name.StartsWith("$Yarn.Internal."))
+ .Where(decl => !(decl.Type is FunctionType))
+ .Select(decl =>
+ {
+ SerializedDeclaration existingDeclaration = null;
+ // try to re-use a declaration if one exists to avoid changing the .tres file so much
+ foreach (var existing in project.SerializedDeclarations)
{
- SerializedDeclaration existingDeclaration = null;
- // try to re-use a declaration if one exists to avoid changing the .tres file so much
- foreach (var existing in project.SerializedDeclarations)
+ if (existing.name == decl.Name)
{
- if (existing.name == decl.Name)
- {
- existingDeclaration = existing;
- break;
- }
+ existingDeclaration = existing;
+ break;
}
+ }
- var serialized = existingDeclaration ?? new SerializedDeclaration();
- serialized.SetDeclaration(decl);
- return serialized;
- }).ToArray();
- project.SerializedDeclarations = newDeclarations;
- // Clear error messages from all scripts - they've all passed
- // compilation
- project.ProjectErrors = Array.Empty();
-
- CreateYarnInternalLocalizationAssets(project, compilationResult.Value);
+ var serialized = existingDeclaration ?? new SerializedDeclaration();
+ serialized.SetDeclaration(decl);
+ return serialized;
+ }).ToArray();
+ project.SerializedDeclarations = newDeclarations;
+ // Clear error messages from all scripts - they've all passed
+ // compilation
+ project.ProjectErrors = Array.Empty();
- using (var memoryStream = new MemoryStream())
- using (var outputStream = new CodedOutputStream(memoryStream))
- {
- // Serialize the compiled program to memory
- compilationResult.Value.Program.WriteTo(outputStream);
- outputStream.Flush();
+ CreateYarnInternalLocalizationAssets(project, compilationResult.Value);
- compiledBytes = memoryStream.ToArray();
- }
- }
-
- project.ListOfFunctions = newFunctionList.ToArray();
- project.CompiledYarnProgramBase64 = compiledBytes == null ? "" : Convert.ToBase64String(compiledBytes);
- var saveErr = ResourceSaver.Save(project, project.ImportPath,
- ResourceSaver.SaverFlags.ReplaceSubresourcePaths);
- if (saveErr != Error.Ok)
+ using (var memoryStream = new MemoryStream())
+ using (var outputStream = new CodedOutputStream(memoryStream))
{
- GD.PushError($"Failed to save updated {nameof(YarnProject)}: {saveErr}");
+ // Serialize the compiled program to memory
+ compilationResult.Value.Program.WriteTo(outputStream);
+ outputStream.Flush();
+
+ compiledBytes = memoryStream.ToArray();
}
}
- }
-
- private static void LogDiagnostic(Diagnostic diagnostic)
- {
- var messagePrefix = string.IsNullOrEmpty(diagnostic.FileName)
- ? string.Empty
- : $"{diagnostic.FileName}: {diagnostic.Range.Start}:{diagnostic.Range.Start.Character} ";
-
- var message = messagePrefix + diagnostic.Message;
- switch (diagnostic.Severity)
+ project.ListOfFunctions = newFunctionList.ToArray();
+ project.CompiledYarnProgramBase64 = compiledBytes == null ? "" : Convert.ToBase64String(compiledBytes);
+ var saveErr = ResourceSaver.Save(project, project.ImportPath,
+ ResourceSaver.SaverFlags.ReplaceSubresourcePaths);
+ if (saveErr != Error.Ok)
{
- case Diagnostic.DiagnosticSeverity.Error:
- GD.PrintErr(message);
- break;
- case Diagnostic.DiagnosticSeverity.Warning:
- GD.Print(message);
- break;
- case Diagnostic.DiagnosticSeverity.Info:
- GD.Print(message);
- break;
+ GD.PushError($"Failed to save updated {nameof(YarnProject)}: {saveErr}");
}
}
+ }
- public static CompilationResult CompileProgram(FileInfo[] inputs)
- {
- // The list of all files and their associated compiled results
- var results = new List<(FileInfo file, Program program, IDictionary stringTable)>();
+ private static void LogDiagnostic(Diagnostic diagnostic)
+ {
+ var messagePrefix = string.IsNullOrEmpty(diagnostic.FileName)
+ ? string.Empty
+ : $"{diagnostic.FileName}: {diagnostic.Range.Start}:{diagnostic.Range.Start.Character} ";
- var compilationJob = CompilationJob.CreateFromFiles(inputs.Select(fileInfo => fileInfo.FullName));
+ var message = messagePrefix + diagnostic.Message;
- CompilationResult compilationResult;
+ switch (diagnostic.Severity)
+ {
+ case Diagnostic.DiagnosticSeverity.Error:
+ GD.PrintErr(message);
+ break;
+ case Diagnostic.DiagnosticSeverity.Warning:
+ GD.Print(message);
+ break;
+ case Diagnostic.DiagnosticSeverity.Info:
+ GD.Print(message);
+ break;
+ }
+ }
- try
- {
- compilationResult = Yarn.Compiler.Compiler.Compile(compilationJob);
- }
- catch (Exception e)
- {
- var errorBuilder = new StringBuilder();
+ public static CompilationResult CompileProgram(FileInfo[] inputs)
+ {
+ // The list of all files and their associated compiled results
+ var results = new List<(FileInfo file, Program program, IDictionary stringTable)>();
- errorBuilder.AppendLine("Failed to compile because of the following error:");
- errorBuilder.AppendLine(e.ToString());
+ var compilationJob = CompilationJob.CreateFromFiles(inputs.Select(fileInfo => fileInfo.FullName));
- GD.PrintErr(errorBuilder.ToString());
- throw new Exception();
- }
+ CompilationResult compilationResult;
- return compilationResult;
+ try
+ {
+ compilationResult = Yarn.Compiler.Compiler.Compile(compilationJob);
}
-
- public static FunctionInfo CreateFunctionInfoFromMethodGroup(MethodInfo method)
+ catch (Exception e)
{
- var returnType = $"-> {method.ReturnType.Name}";
+ var errorBuilder = new StringBuilder();
- var parameters = method.GetParameters();
- var p = new string[parameters.Length];
- for (int i = 0; i < parameters.Length; i++)
- {
- var q = parameters[i].ParameterType;
- p[i] = parameters[i].Name;
- }
+ errorBuilder.AppendLine("Failed to compile because of the following error:");
+ errorBuilder.AppendLine(e.ToString());
- var info = new FunctionInfo();
- info.Name = method.Name;
- info.ReturnType = returnType;
- info.Parameters = p;
- return info;
- }
-
- ///
- /// If , will search
- /// all assemblies that have been defined using an for commands and actions, when this
- /// project is loaded into a . Otherwise,
- /// will be used.
- ///
- ///
- public static bool searchAllAssembliesForActions = true;
-
-
- private static void CreateYarnInternalLocalizationAssets(YarnProject project,
- CompilationResult compilationResult)
- {
- // Will we need to create a default localization? This variable
- // will be set to false if any of the languages we've
- // configured in languagesToSourceAssets is the default
- // language.
- var shouldAddDefaultLocalization = true;
- if (project.JSONProject.Localisation == null)
- {
- project.JSONProject.Localisation =
- new System.Collections.Generic.Dictionary();
- }
-
- if (shouldAddDefaultLocalization)
- {
- // We didn't add a localization for the default language.
- // Create one for it now.
- var stringTableEntries = GetStringTableEntries(project, compilationResult);
-
- var developmentLocalization = project.baseLocalization ?? new Localization();
- developmentLocalization.Clear();
- developmentLocalization.ResourceName = $"Default ({project.defaultLanguage})";
- developmentLocalization.LocaleCode = project.defaultLanguage;
-
- // Add these new lines to the development localisation's asset
- foreach (var entry in stringTableEntries)
- {
- developmentLocalization.AddLocalisedStringToAsset(entry.ID, entry);
- }
+ GD.PrintErr(errorBuilder.ToString());
+ throw new Exception();
+ }
- project.baseLocalization = developmentLocalization;
+ return compilationResult;
+ }
- // Since this is the default language, also populate the line metadata.
- project.LineMetadata ??= new LineMetadata();
- project.LineMetadata.Clear();
- project.LineMetadata.AddMetadata(LineMetadataTableEntriesFromCompilationResult(compilationResult));
- }
- }
+ public static FunctionInfo CreateFunctionInfoFromMethodGroup(MethodInfo method)
+ {
+ var returnType = $"-> {method.ReturnType.Name}";
- ///
- /// Generates a collection of
- /// objects, one for each line in this Yarn Project's scripts.
- ///
- /// An IEnumerable containing a for each of the lines in the Yarn
- /// Project, or if the Yarn Project contains
- /// errors.
- public static IEnumerable GenerateStringsTable(YarnProject project)
+ var parameters = method.GetParameters();
+ var p = new string[parameters.Length];
+ for (int i = 0; i < parameters.Length; i++)
{
- CompilationResult? compilationResult = CompileStringsOnly(project);
+ var q = parameters[i].ParameterType;
+ p[i] = parameters[i].Name;
+ }
- if (!compilationResult.HasValue)
- {
- // We only get no value if we have no scripts to work with.
- // In this case, return an empty collection - there's no
- // error, but there's no content either.
- return new List();
- }
+ var info = new FunctionInfo();
+ info.Name = method.Name;
+ info.ReturnType = returnType;
+ info.Parameters = p;
+ return info;
+ }
- var errors =
- compilationResult.Value.Diagnostics.Where(d => d.Severity == Diagnostic.DiagnosticSeverity.Error);
+ ///
+ /// If , will search
+ /// all assemblies that have been defined using an for commands and actions, when this
+ /// project is loaded into a . Otherwise,
+ /// will be used.
+ ///
+ ///
+ public static bool searchAllAssembliesForActions = true;
- if (errors.Count() > 0)
- {
- GD.PrintErr("Can't generate a strings table from a Yarn Project that contains compile errors", null);
- return null;
- }
- return GetStringTableEntries(project, compilationResult.Value);
+ private static void CreateYarnInternalLocalizationAssets(YarnProject project,
+ CompilationResult compilationResult)
+ {
+ // Will we need to create a default localization? This variable
+ // will be set to false if any of the languages we've
+ // configured in languagesToSourceAssets is the default
+ // language.
+ var shouldAddDefaultLocalization = true;
+ if (project.JSONProject.Localisation == null)
+ {
+ project.JSONProject.Localisation =
+ new System.Collections.Generic.Dictionary();
}
- private static CompilationResult? CompileStringsOnly(YarnProject project)
+ if (shouldAddDefaultLocalization)
{
- var scriptPaths = project.JSONProject.SourceFiles.Where(s => s != null)
- .Select(s => ProjectSettings.GlobalizePath(s)).ToList();
+ // We didn't add a localization for the default language.
+ // Create one for it now.
+ var stringTableEntries = GetStringTableEntries(project, compilationResult);
+
+ var developmentLocalization = project.baseLocalization ?? new Localization();
+ developmentLocalization.Clear();
+ developmentLocalization.ResourceName = $"Default ({project.defaultLanguage})";
+ developmentLocalization.LocaleCode = project.defaultLanguage;
- if (!scriptPaths.Any())
+ // Add these new lines to the development localisation's asset
+ foreach (var entry in stringTableEntries)
{
- // We have no scripts to work with.
- return null;
+ developmentLocalization.AddLocalisedStringToAsset(entry.ID, entry);
}
- // We now now compile!
- var job = CompilationJob.CreateFromFiles(scriptPaths);
- job.CompilationType = CompilationJob.Type.StringsOnly;
+ project.baseLocalization = developmentLocalization;
- return Yarn.Compiler.Compiler.Compile(job);
+ // Since this is the default language, also populate the line metadata.
+ project.LineMetadata ??= new LineMetadata();
+ project.LineMetadata.Clear();
+ project.LineMetadata.AddMetadata(LineMetadataTableEntriesFromCompilationResult(compilationResult));
}
+ }
- private static IEnumerable LineMetadataTableEntriesFromCompilationResult(
- CompilationResult result)
+ ///
+ /// Generates a collection of
+ /// objects, one for each line in this Yarn Project's scripts.
+ ///
+ /// An IEnumerable containing a for each of the lines in the Yarn
+ /// Project, or if the Yarn Project contains
+ /// errors.
+ public static IEnumerable GenerateStringsTable(YarnProject project)
+ {
+ CompilationResult? compilationResult = CompileStringsOnly(project);
+
+ if (!compilationResult.HasValue)
{
- return result.StringTable.Select(x =>
- {
- var meta = new LineMetadataTableEntry();
- meta.ID = x.Key;
- meta.File = ProjectSettings.LocalizePath(x.Value.fileName);
- meta.Node = x.Value.nodeName;
- meta.LineNumber = x.Value.lineNumber.ToString();
- meta.Metadata = RemoveLineIDFromMetadata(x.Value.metadata).ToArray();
- return meta;
- }).Where(x => x.Metadata.Length > 0);
+ // We only get no value if we have no scripts to work with.
+ // In this case, return an empty collection - there's no
+ // error, but there's no content either.
+ return new List();
}
- private static IEnumerable GetStringTableEntries(YarnProject project,
- CompilationResult result)
+ var errors =
+ compilationResult.Value.Diagnostics.Where(d => d.Severity == Diagnostic.DiagnosticSeverity.Error);
+
+ if (errors.Count() > 0)
{
- return result.StringTable.Select(x =>
- {
- var entry = new StringTableEntry();
-
- entry.ID = x.Key;
- entry.Language = project.defaultLanguage;
- entry.Text = x.Value.text;
- entry.File = ProjectSettings.LocalizePath(x.Value.fileName);
- entry.Node = x.Value.nodeName;
- entry.LineNumber = x.Value.lineNumber.ToString();
- entry.Lock = YarnImporter.GetHashString(x.Value.text, 8);
- entry.Comment = GenerateCommentWithLineMetadata(x.Value.metadata);
- return entry;
- }
- );
+ GD.PrintErr("Can't generate a strings table from a Yarn Project that contains compile errors", null);
+ return null;
}
- ///
- /// Generates a string with the line metadata. This string is intended
- /// to be used in the "comment" column of a strings table CSV. Because
- /// of this, it will ignore the line ID if it exists (which is also
- /// part of the line metadata).
- ///
- /// The metadata from a given line.
- /// A string prefixed with "Line metadata: ", followed by each
- /// piece of metadata separated by whitespace. If no metadata exists or
- /// only the line ID is part of the metadata, returns an empty string
- /// instead.
- private static string GenerateCommentWithLineMetadata(string[] metadata)
+ return GetStringTableEntries(project, compilationResult.Value);
+ }
+
+ private static CompilationResult? CompileStringsOnly(YarnProject project)
+ {
+ var scriptPaths = project.JSONProject.SourceFiles.Where(s => s != null)
+ .Select(s => ProjectSettings.GlobalizePath(s)).ToList();
+
+ if (!scriptPaths.Any())
{
- var cleanedMetadata = RemoveLineIDFromMetadata(metadata);
+ // We have no scripts to work with.
+ return null;
+ }
+
+ // We now now compile!
+ var job = CompilationJob.CreateFromFiles(scriptPaths);
+ job.CompilationType = CompilationJob.Type.StringsOnly;
- if (cleanedMetadata.Count() == 0)
+ return Yarn.Compiler.Compiler.Compile(job);
+ }
+
+ private static IEnumerable LineMetadataTableEntriesFromCompilationResult(
+ CompilationResult result)
+ {
+ return result.StringTable.Select(x =>
+ {
+ var meta = new LineMetadataTableEntry();
+ meta.ID = x.Key;
+ meta.File = ProjectSettings.LocalizePath(x.Value.fileName);
+ meta.Node = x.Value.nodeName;
+ meta.LineNumber = x.Value.lineNumber.ToString();
+ meta.Metadata = RemoveLineIDFromMetadata(x.Value.metadata).ToArray();
+ return meta;
+ }).Where(x => x.Metadata.Length > 0);
+ }
+
+ private static IEnumerable GetStringTableEntries(YarnProject project,
+ CompilationResult result)
+ {
+ return result.StringTable.Select(x =>
{
- return string.Empty;
- }
+ var entry = new StringTableEntry();
- return $"Line metadata: {string.Join(" ", cleanedMetadata)}";
- }
+ entry.ID = x.Key;
+ entry.Language = project.defaultLanguage;
+ entry.Text = x.Value.text;
+ entry.File = ProjectSettings.LocalizePath(x.Value.fileName);
+ entry.Node = x.Value.nodeName;
+ entry.LineNumber = x.Value.lineNumber.ToString();
+ entry.Lock = YarnImporter.GetHashString(x.Value.text, 8);
+ entry.Comment = GenerateCommentWithLineMetadata(x.Value.metadata);
+ return entry;
+ }
+ );
+ }
+ ///
+ /// Generates a string with the line metadata. This string is intended
+ /// to be used in the "comment" column of a strings table CSV. Because
+ /// of this, it will ignore the line ID if it exists (which is also
+ /// part of the line metadata).
+ ///
+ /// The metadata from a given line.
+ /// A string prefixed with "Line metadata: ", followed by each
+ /// piece of metadata separated by whitespace. If no metadata exists or
+ /// only the line ID is part of the metadata, returns an empty string
+ /// instead.
+ private static string GenerateCommentWithLineMetadata(string[] metadata)
+ {
+ var cleanedMetadata = RemoveLineIDFromMetadata(metadata);
- ///
- /// Removes any line ID entry from an array of line metadata.
- /// Line metadata will always contain a line ID entry if it's set. For
- /// example, if a line contains "#line:1eaf1e55", its line metadata
- /// will always have an entry with "line:1eaf1e55".
- ///
- /// The array with line metadata.
- /// An IEnumerable with any line ID entries removed.
- private static IEnumerable RemoveLineIDFromMetadata(string[] metadata)
+ if (cleanedMetadata.Count() == 0)
{
- return metadata.Where(x => !x.StartsWith("line:"));
+ return string.Empty;
}
- ///
- /// Update any .yarn scripts in the project to add #line: tags with
- /// unique IDs.
- ///
- /// The YarnProject to update the scripts for
- /// reference to the EditorInterface
- public static void AddLineTagsToFilesInYarnProject(YarnProject project)
- {
- // First, gather all existing line tags across ALL yarn
- // projects, so that we don't accidentally overwrite an
- // existing one. Do this by finding all yarn scripts in all
- // yarn projects, and get the string tags inside them.
+ return $"Line metadata: {string.Join(" ", cleanedMetadata)}";
+ }
- var allYarnFiles =
- // Get the path for each script
- // remove any nulls, in case any are found
- // get all yarn projects across the entire project
- LoadAllYarnProjects()
- // Get all of their source scripts, as a single sequence
- .SelectMany(proj => proj.JSONProject.SourceFiles).ToList()
- .Where(path => path != null);
+
+ ///
+ /// Removes any line ID entry from an array of line metadata.
+ /// Line metadata will always contain a line ID entry if it's set. For
+ /// example, if a line contains "#line:1eaf1e55", its line metadata
+ /// will always have an entry with "line:1eaf1e55".
+ ///
+ /// The array with line metadata.
+ /// An IEnumerable with any line ID entries removed.
+ private static IEnumerable RemoveLineIDFromMetadata(string[] metadata)
+ {
+ return metadata.Where(x => !x.StartsWith("line:"));
+ }
+
+ ///
+ /// Update any .yarn scripts in the project to add #line: tags with
+ /// unique IDs.
+ ///
+ /// The YarnProject to update the scripts for
+ /// reference to the EditorInterface
+ public static void AddLineTagsToFilesInYarnProject(YarnProject project)
+ {
+ // First, gather all existing line tags across ALL yarn
+ // projects, so that we don't accidentally overwrite an
+ // existing one. Do this by finding all yarn scripts in all
+ // yarn projects, and get the string tags inside them.
+
+ var allYarnFiles =
+ // Get the path for each script
+ // remove any nulls, in case any are found
+ // get all yarn projects across the entire project
+ LoadAllYarnProjects()
+ // Get all of their source scripts, as a single sequence
+ .SelectMany(proj => proj.JSONProject.SourceFiles).ToList()
+ .Where(path => path != null);
#if YARNSPINNER_DEBUG
- var stopwatch = Stopwatch.StartNew();
+ var stopwatch = Stopwatch.StartNew();
#endif
- var library = new Library();
+ var library = new Library();
- // Compile all of these, and get whatever existing string tags
- // they had. Do each in isolation so that we can continue even
- // if a file contains a parse error.
- var allExistingTags = allYarnFiles.SelectMany(path =>
- {
- // Compile this script in strings-only mode to get
- // string entries
- var compilationJob = CompilationJob.CreateFromFiles(ProjectSettings.GlobalizePath(path));
- compilationJob.CompilationType = CompilationJob.Type.StringsOnly;
- compilationJob.Library = library;
- var result = Yarn.Compiler.Compiler.Compile(compilationJob);
+ // Compile all of these, and get whatever existing string tags
+ // they had. Do each in isolation so that we can continue even
+ // if a file contains a parse error.
+ var allExistingTags = allYarnFiles.SelectMany(path =>
+ {
+ // Compile this script in strings-only mode to get
+ // string entries
+ var compilationJob = CompilationJob.CreateFromFiles(ProjectSettings.GlobalizePath(path));
+ compilationJob.CompilationType = CompilationJob.Type.StringsOnly;
+ compilationJob.Library = library;
+ var result = Yarn.Compiler.Compiler.Compile(compilationJob);
- bool containsErrors = result.Diagnostics
- .Any(d => d.Severity == Diagnostic.DiagnosticSeverity.Error);
+ bool containsErrors = result.Diagnostics
+ .Any(d => d.Severity == Diagnostic.DiagnosticSeverity.Error);
- if (containsErrors)
+ if (containsErrors)
+ {
+ GD.PrintErr($"Can't check for existing line tags in {path} because it contains errors.");
+ return new string[]
{
- GD.PrintErr($"Can't check for existing line tags in {path} because it contains errors.");
- return new string[]
- {
- };
- }
+ };
+ }
- return result.StringTable.Where(i => i.Value.isImplicitTag == false).Select(i => i.Key);
- }).ToList(); // immediately execute this query so we can determine timing information
+ return result.StringTable.Where(i => i.Value.isImplicitTag == false).Select(i => i.Key);
+ }).ToList(); // immediately execute this query so we can determine timing information
#if YARNSPINNER_DEBUG
- stopwatch.Stop();
- GD.Print($"Checked {allYarnFiles.Count()} yarn files for line tags in {stopwatch.ElapsedMilliseconds}ms");
+ stopwatch.Stop();
+ GD.Print($"Checked {allYarnFiles.Count()} yarn files for line tags in {stopwatch.ElapsedMilliseconds}ms");
#endif
- var modifiedFiles = new List();
+ var modifiedFiles = new List();
- try
+ try
+ {
+ foreach (var script in project.JSONProject.SourceFiles)
{
- foreach (var script in project.JSONProject.SourceFiles)
- {
- var assetPath = ProjectSettings.GlobalizePath(script);
- var contents = File.ReadAllText(assetPath);
-
- // Produce a version of this file that contains line
- // tags added where they're needed.
- var tagged = Yarn.Compiler.Utility.TagLines(contents, allExistingTags);
+ var assetPath = ProjectSettings.GlobalizePath(script);
+ var contents = File.ReadAllText(assetPath);
- var taggedVersion = tagged.Item1;
+ // Produce a version of this file that contains line
+ // tags added where they're needed.
+ var tagged = Yarn.Compiler.Utility.TagLines(contents, allExistingTags);
- // if the file has an error it returns null
- // we want to bail out then otherwise we'd wipe the yarn file
- if (taggedVersion == null)
- {
- continue;
- }
+ var taggedVersion = tagged.Item1;
- // If this produced a modified version of the file,
- // write it out and re-import it.
- if (contents != taggedVersion)
- {
- modifiedFiles.Add(Path.GetFileNameWithoutExtension(assetPath));
- File.WriteAllText(assetPath, taggedVersion, Encoding.UTF8);
- }
+ // if the file has an error it returns null
+ // we want to bail out then otherwise we'd wipe the yarn file
+ if (taggedVersion == null)
+ {
+ continue;
}
- }
- catch (Exception e)
- {
- GD.PrintErr($"Encountered an error when updating scripts: {e}");
- return;
- }
- // Report on the work we did.
- if (modifiedFiles.Count > 0)
- {
- GD.Print($"Updated the following files: {string.Join(", ", modifiedFiles)}");
- // trigger reimport
- YarnSpinnerPlugin.editorInterface.GetResourceFilesystem().ScanSources();
- }
- else
- {
- GD.Print("No files needed updating.");
+ // If this produced a modified version of the file,
+ // write it out and re-import it.
+ if (contents != taggedVersion)
+ {
+ modifiedFiles.Add(Path.GetFileNameWithoutExtension(assetPath));
+ File.WriteAllText(assetPath, taggedVersion, Encoding.UTF8);
+ }
}
}
+ catch (Exception e)
+ {
+ GD.PrintErr($"Encountered an error when updating scripts: {e}");
+ return;
+ }
- ///
- /// Load all known YarnProject resources in the project
- ///
- /// a list of all YarnProject resources
- public static List LoadAllYarnProjects()
+ // Report on the work we did.
+ if (modifiedFiles.Count > 0)
{
- var projects = new List();
- var allProjects = FindAllYarnProjects();
- foreach (var path in allProjects)
- {
- projects.Add(ResourceLoader.Load(path.ToString()));
- }
+ GD.Print($"Updated the following files: {string.Join(", ", modifiedFiles)}");
+ // trigger reimport
+ YarnSpinnerPlugin.editorInterface.GetResourceFilesystem().ScanSources();
+ }
+ else
+ {
+ GD.Print("No files needed updating.");
+ }
+ }
- return projects;
+ ///
+ /// Load all known YarnProject resources in the project
+ ///
+ /// a list of all YarnProject resources
+ public static List LoadAllYarnProjects()
+ {
+ var projects = new List();
+ var allProjects = FindAllYarnProjects();
+ foreach (var path in allProjects)
+ {
+ projects.Add(ResourceLoader.Load(path.ToString()));
}
+
+ return projects;
}
}
#endif
\ No newline at end of file
diff --git a/addons/YarnSpinner-Godot/Editor/YarnProjectImporter.cs b/addons/YarnSpinner-Godot/Editor/YarnProjectImporter.cs
index 04243ea..962917a 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnProjectImporter.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnProjectImporter.cs
@@ -5,90 +5,89 @@
using Godot;
using Godot.Collections;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+///
+/// A for YarnSpinner JSON project files (.yarnproject files)
+///
+public partial class YarnProjectImporter : EditorImportPlugin
{
- ///
- /// A for YarnSpinner JSON project files (.yarnproject files)
- ///
- public partial class YarnProjectImporter : EditorImportPlugin
+ public override string[] _GetRecognizedExtensions() =>
+ new[]
+ {
+ "yarnproject"
+ };
+
+ public override string _GetImporterName()
{
- public override string[] _GetRecognizedExtensions() =>
- new[]
- {
- "yarnproject"
- };
+ return "yarnproject";
+ }
- public override string _GetImporterName()
- {
- return "yarnproject";
- }
+ public override string _GetVisibleName()
+ {
+ return "Yarn Project";
+ }
- public override string _GetVisibleName()
- {
- return "Yarn Project";
- }
+ public override string _GetSaveExtension() => "tres";
- public override string _GetSaveExtension() => "tres";
+ public override string _GetResourceType()
+ {
+ return "Resource";
+ }
- public override string _GetResourceType()
- {
- return "Resource";
- }
+ public override int _GetPresetCount()
+ {
+ return 0;
+ }
- public override int _GetPresetCount()
- {
- return 0;
- }
+ public override float _GetPriority()
+ {
+ return 1.0f;
+ }
- public override float _GetPriority()
- {
- return 1.0f;
- }
+ public override int _GetImportOrder()
+ {
+ return 0;
+ }
- public override int _GetImportOrder()
+ public override Array _GetImportOptions(string path, int presetIndex)
+ {
+ return new Array();
+ }
+
+ public override Error _Import(
+ string assetPath,
+ string savePath,
+ Dictionary options,
+ Array platformVariants,
+ Array genFiles)
+ {
+ var stopwatch = new System.Diagnostics.Stopwatch();
+ stopwatch.Start();
+ YarnProject godotProject = null;
+ var fullSavePath = $"{savePath}.{_GetSaveExtension()}";
+ try
{
- return 0;
+ godotProject = ResourceLoader.Load(assetPath);
}
-
- public override Array _GetImportOptions(string path, int presetIndex)
+ catch (Exception e)
{
- return new Array();
+ GD.PushError(
+ $"Error loading existing {nameof(YarnProject)}: {e.Message}\n{e.StackTrace}. Creating new resource.");
}
- public override Error _Import(
- string assetPath,
- string savePath,
- Dictionary options,
- Array platformVariants,
- Array genFiles)
+ godotProject ??= new YarnProject();
+ godotProject.JSONProjectPath = assetPath;
+ godotProject.ImportPath = fullSavePath;
+ godotProject.ResourceName = Path.GetFileName(assetPath);
+ var saveErr = ResourceSaver.Save(godotProject, godotProject.ImportPath);
+ if (saveErr != Error.Ok)
{
- var stopwatch = new System.Diagnostics.Stopwatch();
- stopwatch.Start();
- YarnProject godotProject = null;
- var fullSavePath = $"{savePath}.{_GetSaveExtension()}";
- try
- {
- godotProject = ResourceLoader.Load(assetPath);
- }
- catch (Exception e)
- {
- GD.PushError(
- $"Error loading existing {nameof(YarnProject)}: {e.Message}\n{e.StackTrace}. Creating new resource.");
- }
-
- godotProject ??= new YarnProject();
- godotProject.JSONProjectPath = assetPath;
- godotProject.ImportPath = fullSavePath;
- godotProject.ResourceName = Path.GetFileName(assetPath);
- var saveErr = ResourceSaver.Save(godotProject, godotProject.ImportPath);
- if (saveErr != Error.Ok)
- {
- GD.PrintErr($"Error saving .yarnproject file import: {saveErr.ToString()}");
- }
-
- YarnProjectEditorUtility.UpdateYarnProject(godotProject);
- return (int) Error.Ok;
+ GD.PrintErr($"Error saving .yarnproject file import: {saveErr.ToString()}");
}
+
+ YarnProjectEditorUtility.UpdateYarnProject(godotProject);
+ return (int) Error.Ok;
}
}
#endif
\ No newline at end of file
diff --git a/addons/YarnSpinner-Godot/Editor/YarnProjectInspectorPlugin.cs b/addons/YarnSpinner-Godot/Editor/YarnProjectInspectorPlugin.cs
index ea2fbb8..f8f71d4 100644
--- a/addons/YarnSpinner-Godot/Editor/YarnProjectInspectorPlugin.cs
+++ b/addons/YarnSpinner-Godot/Editor/YarnProjectInspectorPlugin.cs
@@ -11,646 +11,645 @@
using YarnSpinnerGodot.Editor.UI;
-namespace YarnSpinnerGodot.Editor
+namespace YarnSpinnerGodot.Editor;
+
+[Tool]
+public partial class YarnProjectInspectorPlugin : EditorInspectorPlugin
{
- [Tool]
- public partial class YarnProjectInspectorPlugin : EditorInspectorPlugin
+ private YarnCompileErrorsPropertyEditor _compileErrorsPropertyEditor;
+ private ScrollContainer _parseErrorControl;
+ private YarnProject _project;
+
+ private readonly PackedScene _fileNameLabelScene =
+ ResourceLoader.Load(
+ "res://addons/YarnSpinner-Godot/Editor/UI/FilenameLabel.tscn");
+
+ private readonly PackedScene _errorTextLabelScene =
+ ResourceLoader.Load(
+ "res://addons/YarnSpinner-Godot/Editor/UI/ErrorTextLabel.tscn");
+
+ private readonly PackedScene _contextLabelScene =
+ ResourceLoader.Load(
+ "res://addons/YarnSpinner-Godot/Editor/UI/ContextLabel.tscn");
+
+ private VBoxContainer _errorContainer;
+ private RichTextLabel _sourceScriptsListLabel;
+ private LineEditWithSubmit _localeTextEntry;
+ private bool _addLocaleConnected;
+ private string _pendingCSVFileLocaleCode;
+ private LineEdit _baseLocaleInput;
+
+ public override bool _CanHandle(GodotObject obj)
+ {
+ return obj is YarnProject;
+ }
+
+ public override bool _ParseProperty(GodotObject @object, Variant.Type type,
+ string path,
+ PropertyHint hint, string hintText, PropertyUsageFlags usage, bool wide)
{
- private YarnCompileErrorsPropertyEditor _compileErrorsPropertyEditor;
- private ScrollContainer _parseErrorControl;
- private YarnProject _project;
-
- private readonly PackedScene _fileNameLabelScene =
- ResourceLoader.Load(
- "res://addons/YarnSpinner-Godot/Editor/UI/FilenameLabel.tscn");
-
- private readonly PackedScene _errorTextLabelScene =
- ResourceLoader.Load(
- "res://addons/YarnSpinner-Godot/Editor/UI/ErrorTextLabel.tscn");
-
- private readonly PackedScene _contextLabelScene =
- ResourceLoader.Load(
- "res://addons/YarnSpinner-Godot/Editor/UI/ContextLabel.tscn");
-
- private VBoxContainer _errorContainer;
- private RichTextLabel _sourceScriptsListLabel;
- private LineEditWithSubmit _localeTextEntry;
- private bool _addLocaleConnected;
- private string _pendingCSVFileLocaleCode;
- private LineEdit _baseLocaleInput;
-
- public override bool _CanHandle(GodotObject obj)
+ if (@object is not YarnProject project)
{
- return obj is YarnProject;
+ return false;
}
- public override bool _ParseProperty(GodotObject @object, Variant.Type type,
- string path,
- PropertyHint hint, string hintText, PropertyUsageFlags usage, bool wide)
+ if (IsTresYarnProject(project))
{
- if (@object is not YarnProject project)
- {
- return false;
- }
+ return true;
+ }
- if (IsTresYarnProject(project))
+ try
+ {
+ _project = project;
+ // hide some properties that are not editable by the user
+ string[] hideProperties =
+ {
+ nameof(YarnProject.LastImportHadAnyStrings),
+ nameof(YarnProject.LastImportHadImplicitStringIDs),
+ nameof(YarnProject.IsSuccessfullyParsed),
+ nameof(YarnProject.CompiledYarnProgramBase64),
+ nameof(YarnProject.baseLocalization),
+ nameof(YarnProject.ImportPath),
+ nameof(YarnProject.JSONProjectPath),
+ // can't use nameof for private fields here
+ "_baseLocalizationJSON",
+ "_lineMetadataJSON",
+ "_listOfFunctionsJSON",
+ };
+ if (hideProperties.Contains(path))
{
+ // hide these properties from inspector
return true;
}
- try
+ if (path == nameof(YarnProject.ProjectErrors))
{
- _project = project;
- // hide some properties that are not editable by the user
- string[] hideProperties =
+ _compileErrorsPropertyEditor =
+ new YarnCompileErrorsPropertyEditor();
+ AddPropertyEditor(path, _compileErrorsPropertyEditor);
+ _parseErrorControl = new ScrollContainer
{
- nameof(YarnProject.LastImportHadAnyStrings),
- nameof(YarnProject.LastImportHadImplicitStringIDs),
- nameof(YarnProject.IsSuccessfullyParsed),
- nameof(YarnProject.CompiledYarnProgramBase64),
- nameof(YarnProject.baseLocalization),
- nameof(YarnProject.ImportPath),
- nameof(YarnProject.JSONProjectPath),
- // can't use nameof for private fields here
- "_baseLocalizationJSON",
- "_lineMetadataJSON",
- "_listOfFunctionsJSON",
+ SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
+ SizeFlagsVertical = Control.SizeFlags.ExpandFill,
};
- if (hideProperties.Contains(path))
+ var errorAreaHeight = 40;
+ if (_project.ProjectErrors != null &&
+ _project.ProjectErrors.Length > 0)
{
- // hide these properties from inspector
- return true;
+ errorAreaHeight = 200;
}
- if (path == nameof(YarnProject.ProjectErrors))
- {
- _compileErrorsPropertyEditor =
- new YarnCompileErrorsPropertyEditor();
- AddPropertyEditor(path, _compileErrorsPropertyEditor);
- _parseErrorControl = new ScrollContainer
- {
- SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
- SizeFlagsVertical = Control.SizeFlags.ExpandFill,
- };
- var errorAreaHeight = 40;
- if (_project.ProjectErrors != null &&
- _project.ProjectErrors.Length > 0)
- {
- errorAreaHeight = 200;
- }
+ _parseErrorControl.CustomMinimumSize =
+ new Vector2(0, errorAreaHeight);
- _parseErrorControl.CustomMinimumSize =
- new Vector2(0, errorAreaHeight);
+ _errorContainer = new VBoxContainer
+ {
+ SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
+ SizeFlagsVertical = Control.SizeFlags.ExpandFill,
+ };
+ _parseErrorControl.AddChild(_errorContainer);
+ _compileErrorsPropertyEditor.Connect(
+ YarnCompileErrorsPropertyEditor.SignalName.OnErrorsUpdate,
+ Callable.From(RenderCompilationErrors));
+ RenderCompilationErrors();
+ AddCustomControl(_parseErrorControl);
+ return true;
+ }
- _errorContainer = new VBoxContainer
+ if (path == "_serializedDeclarationsJSON")
+ {
+ var header = new HBoxContainer();
+ header.AddChild(new Label
+ {
+ Text = " Story Variables",
+ SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
+ SizeFlagsVertical = Control.SizeFlags.ExpandFill,
+ });
+ header.AddChild(new Label
+ {
+ Text = _project.SerializedDeclarations == null || _project.SerializedDeclarations.Length == 0
+ ? "None"
+ : _project.SerializedDeclarations.Length.ToString(CultureInfo.InvariantCulture),
+ SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
+ SizeFlagsVertical = Control.SizeFlags.ExpandFill,
+ });
+ AddCustomControl(header);
+ if (_project.SerializedDeclarations is {Length: >= 1})
+ {
+ var scrollContainer = new ScrollContainer
{
SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
SizeFlagsVertical = Control.SizeFlags.ExpandFill,
};
- _parseErrorControl.AddChild(_errorContainer);
- _compileErrorsPropertyEditor.Connect(
- YarnCompileErrorsPropertyEditor.SignalName.OnErrorsUpdate,
- Callable.From(RenderCompilationErrors));
- RenderCompilationErrors();
- AddCustomControl(_parseErrorControl);
- return true;
- }
- if (path == "_serializedDeclarationsJSON")
- {
- var header = new HBoxContainer();
- header.AddChild(new Label
+ var vbox = new VBoxContainer
{
- Text = " Story Variables",
SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
- SizeFlagsVertical = Control.SizeFlags.ExpandFill,
- });
- header.AddChild(new Label
- {
- Text = _project.SerializedDeclarations == null || _project.SerializedDeclarations.Length == 0
- ? "None"
- : _project.SerializedDeclarations.Length.ToString(CultureInfo.InvariantCulture),
- SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
- SizeFlagsVertical = Control.SizeFlags.ExpandFill,
- });
- AddCustomControl(header);
- if (_project.SerializedDeclarations is {Length: >= 1})
+ SizeFlagsVertical = Control.SizeFlags.ShrinkBegin,
+ };
+ scrollContainer.AddChild(vbox);
+ foreach (var declaration in _project.SerializedDeclarations)
{
- var scrollContainer = new ScrollContainer
+ var labelText = $"{declaration.name} ({declaration.typeName})\n";
+ if (declaration.isImplicit)
{
- SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
- SizeFlagsVertical = Control.SizeFlags.ExpandFill,
- };
+ labelText += "Implicitly declared.";
+ }
+ else
+ {
+ labelText += $"Declared in {declaration.sourceYarnAssetPath}\n";
+ }
- var vbox = new VBoxContainer
+ var typeName = declaration.typeName;
+ var defaultValue = "";
+ if (typeName == BuiltinTypes.String.Name)
{
- SizeFlagsHorizontal = Control.SizeFlags.ExpandFill,
- SizeFlagsVertical = Control.SizeFlags.ShrinkBegin,
- };
- scrollContainer.AddChild(vbox);
- foreach (var declaration in _project.SerializedDeclarations)
+ defaultValue = declaration.defaultValueString;
+ }
+ else if (typeName == BuiltinTypes.Boolean.Name)
{
- var labelText = $"{declaration.name} ({declaration.typeName})\n";
- if (declaration.isImplicit)
- {
- labelText += "Implicitly declared.";
- }
- else
- {
- labelText += $"Declared in {declaration.sourceYarnAssetPath}\n";
- }
-
- var typeName = declaration.typeName;
- var defaultValue = "";
- if (typeName == BuiltinTypes.String.Name)
- {
- defaultValue = declaration.defaultValueString;
- }
- else if (typeName == BuiltinTypes.Boolean.Name)
- {
- defaultValue = declaration.defaultValueBool.ToString();
- }
- else if (typeName == BuiltinTypes.Number.Name)
- {
- defaultValue = declaration.defaultValueNumber.ToString(CultureInfo.InvariantCulture);
- }
-
- labelText += $"Default value: {defaultValue}\n";
- var label = _fileNameLabelScene.Instantiate