diff --git a/Editor/Analysis/ActionsRegistrationGenerator~/ActionsGenerator.cs b/Editor/Analysis/ActionsRegistrationGenerator~/ActionsGenerator.cs index 6587bcf3..9119a9d7 100644 --- a/Editor/Analysis/ActionsRegistrationGenerator~/ActionsGenerator.cs +++ b/Editor/Analysis/ActionsRegistrationGenerator~/ActionsGenerator.cs @@ -19,11 +19,56 @@ public class ActionRegistrationSourceGenerator : ISourceGenerator public void Execute(GeneratorExecutionContext context) { var output = GetOutput(context); + output.WriteLine(DateTime.Now); + + // we need to know if the settings are configured to not perform codegen to link attributed methods + // this is kinda annoying because the path root of the project settings and the root path of this process are *very* different + // so what we do is we use the included Compilation Assembly additional file that Unity gives us. + // This file if opened has the path of the Unity project, which we can then use to get the settings + // if any stage of this fails then we bail out and assume that codegen is desired + if (context.AdditionalFiles.Any()) + { + var relevants = context.AdditionalFiles.Where(i => i.Path.Contains($"{context.Compilation.AssemblyName}.AdditionalFile.txt")); + if (relevants.Any()) + { + var arsgacsaf = relevants.First(); + if (File.Exists(arsgacsaf.Path)) + { + try + { + var projectPath = File.ReadAllText(arsgacsaf.Path); + var fullPath = Path.Combine(projectPath, Yarn.Unity.Editor.YarnSpinnerProjectSettings.YarnSpinnerProjectSettingsPath); + output.WriteLine($"Attempting to read settings file at {fullPath}"); + + if (!Yarn.Unity.Editor.YarnSpinnerProjectSettings.GetOrCreateSettings(projectPath, output).automaticallyLinkAttributedYarnCommandsAndFunctions) + { + output.WriteLine("Skipping codegen due to settings."); + output.Dispose(); + return; + } + } + catch (Exception e) + { + output.WriteLine($"Unable to determine Yarn settings, settings values will be ignored and codegen will occur: {e.Message}"); + } + } + else + { + output.WriteLine($"The project settings path metadata file does not exist at: {arsgacsaf.Path}. Settings values will be ignored and codegen will occur"); + } + } + else + { + output.WriteLine("Unable to determine Yarn settings path, no file containing the project path metadata was included. Settings values will be ignored and codegen will occur."); + } + } + else + { + output.WriteLine("Unable to determine Yarn settings path as no additional files were included. Settings values will be ignored and codegen will occur."); + } try { - output.WriteLine(DateTime.Now); - output.WriteLine("Source code generation for assembly " + context.Compilation.AssemblyName); if (context.AdditionalFiles.Any()) { @@ -322,18 +367,21 @@ public void Initialize(GeneratorInitializationContext context) context.RegisterForSyntaxNotifications(() => new ClassDeclarationSyntaxReceiver()); } - public ILogger GetOutput(GeneratorExecutionContext context) + public Yarn.Unity.ILogger GetOutput(GeneratorExecutionContext context) { if (GetShouldLogToFile(context)) { var tempPath = System.IO.Path.GetTempPath(); + var path = System.IO.Path.Combine(tempPath, $"{nameof(ActionRegistrationSourceGenerator)}-{context.Compilation.AssemblyName}.txt"); var outFile = System.IO.File.Open(path, System.IO.FileMode.Create); - return new FileLogger(new System.IO.StreamWriter(outFile)); - } else { - return new NullLogger(); + return new Yarn.Unity.FileLogger(new System.IO.StreamWriter(outFile)); + } + else + { + return new Yarn.Unity.NullLogger(); } } @@ -365,52 +413,3 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode) } } } - -public interface ILogger : IDisposable -{ - void Write(object obj); - void WriteLine(object obj); -} - -public class FileLogger : ILogger -{ - System.IO.TextWriter writer; - - public FileLogger(TextWriter writer) - { - this.writer = writer; - } - - public void Dispose() - { - writer.Dispose(); - } - - public void Write(object text) - { - writer.Write(text); - } - - public void WriteLine(object text) - { - writer.WriteLine(text); - } -} - -public class NullLogger : ILogger -{ - public void Dispose() - { - - } - - public void Write(object text) - { - - } - - public void WriteLine(object text) - { - - } -} diff --git a/Editor/Analysis/ActionsRegistrationGenerator~/Generator.csproj b/Editor/Analysis/ActionsRegistrationGenerator~/Generator.csproj index 1880a230..b46a49a8 100644 --- a/Editor/Analysis/ActionsRegistrationGenerator~/Generator.csproj +++ b/Editor/Analysis/ActionsRegistrationGenerator~/Generator.csproj @@ -15,6 +15,9 @@ + + + diff --git a/Editor/ILogger.cs b/Editor/ILogger.cs new file mode 100644 index 00000000..136ceac9 --- /dev/null +++ b/Editor/ILogger.cs @@ -0,0 +1,65 @@ +using System; +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; +#endif + +namespace Yarn.Unity +{ + public interface ILogger : IDisposable + { + void Write(object obj); + void WriteLine(object obj); + } + + public class FileLogger : ILogger + { + System.IO.TextWriter writer; + + public FileLogger(System.IO.TextWriter writer) + { + this.writer = writer; + } + + public void Dispose() + { + writer.Dispose(); + } + + public void Write(object text) + { + writer.Write(text); + } + + public void WriteLine(object text) + { + writer.WriteLine(text); + } + } + + public class UnityLogger : ILogger + { + public void Dispose() { } + + public void Write(object text) + { + WriteLine(text); + } + + public void WriteLine(object text) + { +#if UNITY_EDITOR + Debug.LogWarning(text.ToString()); +#endif + } + } + + public class NullLogger : ILogger + { + public void Dispose() { } + + public void Write(object text) { } + + public void WriteLine(object text) { } + } +} diff --git a/Editor/ILogger.cs.meta b/Editor/ILogger.cs.meta new file mode 100644 index 00000000..e6c1ea2b --- /dev/null +++ b/Editor/ILogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45e3ce698d3364e5790443887a66daff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/MiniJSON.cs b/Editor/MiniJSON.cs new file mode 100644 index 00000000..6810cc0d --- /dev/null +++ b/Editor/MiniJSON.cs @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2013 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Yarn.Unity.Editor +{ + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to doubles. + /// + public static class Json + { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a double, an integer,a string, null, true, or false + public static object Deserialize(string json) + { + // save the string for debug information + if (json == null) + { + return null; + } + + return Parser.Parse(json); + } + + sealed class Parser : IDisposable + { + const string WORD_BREAK = "{}[],:\""; + + public static bool IsWordBreak(char c) + { + return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1; + } + + enum TOKEN + { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + StringReader json; + + Parser(string jsonString) + { + json = new StringReader(jsonString); + } + + public static object Parse(string jsonString) + { + using (var instance = new Parser(jsonString)) + { + return instance.ParseValue(); + } + } + + public void Dispose() + { + json.Dispose(); + json = null; + } + + Dictionary ParseObject() + { + Dictionary table = new Dictionary(); + + // ditch opening brace + json.Read(); + + // { + while (true) + { + switch (NextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + default: + // name + string name = ParseString(); + if (name == null) + { + return null; + } + + // : + if (NextToken != TOKEN.COLON) + { + return null; + } + // ditch the colon + json.Read(); + + // value + table[name] = ParseValue(); + break; + } + } + } + + List ParseArray() + { + List array = new List(); + + // ditch opening bracket + json.Read(); + + // [ + var parsing = true; + while (parsing) + { + TOKEN nextToken = NextToken; + + switch (nextToken) + { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken(nextToken); + + array.Add(value); + break; + } + } + + return array; + } + + object ParseValue() + { + TOKEN nextToken = NextToken; + return ParseByToken(nextToken); + } + + object ParseByToken(TOKEN token) + { + switch (token) + { + case TOKEN.STRING: + return ParseString(); + case TOKEN.NUMBER: + return ParseNumber(); + case TOKEN.CURLY_OPEN: + return ParseObject(); + case TOKEN.SQUARED_OPEN: + return ParseArray(); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString() + { + StringBuilder s = new StringBuilder(); + char c; + + // ditch opening quote + json.Read(); + + bool parsing = true; + while (parsing) + { + + if (json.Peek() == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek() == -1) + { + parsing = false; + break; + } + + c = NextChar; + switch (c) + { + case '"': + case '\\': + case '/': + s.Append(c); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'u': + var hex = new char[4]; + + for (int i = 0; i < 4; i++) + { + hex[i] = NextChar; + } + + s.Append((char)Convert.ToInt32(new string(hex), 16)); + break; + } + break; + default: + s.Append(c); + break; + } + } + + return s.ToString(); + } + + object ParseNumber() + { + string number = NextWord; + + if (number.IndexOf('.') == -1) + { + long parsedInt; + Int64.TryParse(number, out parsedInt); + return parsedInt; + } + + double parsedDouble; + Double.TryParse(number, out parsedDouble); + return parsedDouble; + } + + void EatWhitespace() + { + while (Char.IsWhiteSpace(PeekChar)) + { + json.Read(); + + if (json.Peek() == -1) + { + break; + } + } + } + + char PeekChar + { + get + { + return Convert.ToChar(json.Peek()); + } + } + + char NextChar + { + get + { + return Convert.ToChar(json.Read()); + } + } + + string NextWord + { + get + { + StringBuilder word = new StringBuilder(); + + while (!IsWordBreak(PeekChar)) + { + word.Append(NextChar); + + if (json.Peek() == -1) + { + break; + } + } + + return word.ToString(); + } + } + + TOKEN NextToken + { + get + { + EatWhitespace(); + + if (json.Peek() == -1) + { + return TOKEN.NONE; + } + + switch (PeekChar) + { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read(); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read(); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read(); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + switch (NextWord) + { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + /// + /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + public static string Serialize(object obj) + { + return Serializer.Serialize(obj); + } + + sealed class Serializer + { + StringBuilder builder; + + Serializer() + { + builder = new StringBuilder(); + } + + public static string Serialize(object obj) + { + var instance = new Serializer(); + + instance.SerializeValue(obj); + + return instance.builder.ToString(); + } + + void SerializeValue(object value) + { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) + { + builder.Append("null"); + } + else if ((asStr = value as string) != null) + { + SerializeString(asStr); + } + else if (value is bool) + { + builder.Append((bool)value ? "true" : "false"); + } + else if ((asList = value as IList) != null) + { + SerializeArray(asList); + } + else if ((asDict = value as IDictionary) != null) + { + SerializeObject(asDict); + } + else if (value is char) + { + SerializeString(new string((char)value, 1)); + } + else + { + SerializeOther(value); + } + } + + void SerializeObject(IDictionary obj) + { + bool first = true; + + builder.Append('{'); + + foreach (object e in obj.Keys) + { + if (!first) + { + builder.Append(','); + } + + SerializeString(e.ToString()); + builder.Append(':'); + + SerializeValue(obj[e]); + + first = false; + } + + builder.Append('}'); + } + + void SerializeArray(IList anArray) + { + builder.Append('['); + + bool first = true; + + foreach (object obj in anArray) + { + if (!first) + { + builder.Append(','); + } + + SerializeValue(obj); + + first = false; + } + + builder.Append(']'); + } + + void SerializeString(string str) + { + builder.Append('\"'); + + char[] charArray = str.ToCharArray(); + foreach (var c in charArray) + { + switch (c) + { + case '"': + builder.Append("\\\""); + break; + case '\\': + builder.Append("\\\\"); + break; + case '\b': + builder.Append("\\b"); + break; + case '\f': + builder.Append("\\f"); + break; + case '\n': + builder.Append("\\n"); + break; + case '\r': + builder.Append("\\r"); + break; + case '\t': + builder.Append("\\t"); + break; + default: + int codepoint = Convert.ToInt32(c); + if ((codepoint >= 32) && (codepoint <= 126)) + { + builder.Append(c); + } + else + { + builder.Append("\\u"); + builder.Append(codepoint.ToString("x4")); + } + break; + } + } + + builder.Append('\"'); + } + + void SerializeOther(object value) + { + // NOTE: decimals lose precision during serialization. + // They always have, I'm just letting you know. + // Previously floats and doubles lost precision too. + if (value is float) + { + builder.Append(((float)value).ToString("R")); + } + else if (value is int + || value is uint + || value is long + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong) + { + builder.Append(value); + } + else if (value is double + || value is decimal) + { + builder.Append(Convert.ToDouble(value).ToString("R")); + } + else + { + SerializeString(value.ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/Editor/MiniJSON.cs.meta b/Editor/MiniJSON.cs.meta new file mode 100644 index 00000000..fcc696c0 --- /dev/null +++ b/Editor/MiniJSON.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b4adfe2cc33c4714a7fad372d96d61e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/YarnSpinnerProjectSettings.cs b/Editor/YarnSpinnerProjectSettings.cs index 35195fac..5931d082 100644 --- a/Editor/YarnSpinnerProjectSettings.cs +++ b/Editor/YarnSpinnerProjectSettings.cs @@ -1,12 +1,10 @@ namespace Yarn.Unity.Editor { - using System.Collections.Generic; using System.IO; - using System.Linq; +#if UNITY_EDITOR using UnityEditor; using UnityEngine; - using UnityEngine.UIElements; - using UnityEditor.UIElements; +#endif /// /// Basic data class of unity settings that impact Yarn Spinner. @@ -18,91 +16,123 @@ class YarnSpinnerProjectSettings { public static string YarnSpinnerProjectSettingsPath => Path.Combine("ProjectSettings", "Packages", "dev.yarnspinner", "YarnSpinnerProjectSettings.json"); - [SerializeField] internal bool autoRefreshLocalisedAssets = true; + public bool autoRefreshLocalisedAssets = true; + public bool automaticallyLinkAttributedYarnCommandsAndFunctions = true; - internal static YarnSpinnerProjectSettings GetOrCreateSettings() + // need to make it os the output can be passed in also so it can log + internal static YarnSpinnerProjectSettings GetOrCreateSettings(string path = null, Yarn.Unity.ILogger iLogger = null) { + var settingsPath = YarnSpinnerProjectSettingsPath; + if (path != null) + { + settingsPath = Path.Combine(path, YarnSpinnerProjectSettingsPath); + } + var logger = ValidLogger(iLogger); + YarnSpinnerProjectSettings settings = new YarnSpinnerProjectSettings(); - if (File.Exists(YarnSpinnerProjectSettingsPath)) + if (File.Exists(settingsPath)) { try { - var settingsData = File.ReadAllText(YarnSpinnerProjectSettingsPath); - EditorJsonUtility.FromJsonOverwrite(settingsData, settings); + var settingsData = File.ReadAllText(settingsPath); + settings = YarnSpinnerProjectSettings.FromJson(settingsData, logger); return settings; } catch (System.Exception e) { - Debug.LogWarning($"Failed to load Yarn Spinner project settings at {YarnSpinnerProjectSettingsPath}: {e.Message}"); + logger.WriteLine($"Failed to load Yarn Spinner project settings at {settingsPath}: {e.Message}"); } } + else + { + logger.WriteLine($"No settings file exists at {settingsPath}, will fallback to default settings"); + } settings.autoRefreshLocalisedAssets = true; - settings.WriteSettings(); + settings.automaticallyLinkAttributedYarnCommandsAndFunctions = true; + settings.WriteSettings(path, logger); return settings; } - internal void WriteSettings() + private static YarnSpinnerProjectSettings FromJson(string jsonString, Yarn.Unity.ILogger iLogger = null) { - var jsonValue = EditorJsonUtility.ToJson(this); - - var folder = Path.GetDirectoryName(YarnSpinnerProjectSettingsPath); - if (!Directory.Exists(folder)) + var logger = ValidLogger(iLogger); + + YarnSpinnerProjectSettings settings = new YarnSpinnerProjectSettings(); + var jsonDict = Json.Deserialize(jsonString) as System.Collections.Generic.Dictionary; + if (jsonDict == null) { - Directory.CreateDirectory(folder); + logger.WriteLine($"Failed to parse Yarn Spinner project settings JSON"); + return settings; } + bool automaticallyLinkAttributedYarnCommandsAndFunctions = true; + bool autoRefreshLocalisedAssets = true; try { - File.WriteAllText(YarnSpinnerProjectSettingsPath, jsonValue); + automaticallyLinkAttributedYarnCommandsAndFunctions = (bool)jsonDict["automaticallyLinkAttributedYarnCommandsAndFunctions"]; + autoRefreshLocalisedAssets = (bool)jsonDict["autoRefreshLocalisedAssets"]; } catch (System.Exception e) { - Debug.LogError($"Failed to save Yarn Spinner project settings to {YarnSpinnerProjectSettingsPath}: {e.Message}"); + logger.WriteLine($"Failed to parse Yarn Spinner project settings: {e.Message}"); } - } - } - - class YarnSpinnerProjectSettingsProvider : SettingsProvider - { - private YarnSpinnerProjectSettings baseSettings; - public YarnSpinnerProjectSettingsProvider(string path, SettingsScope scope = SettingsScope.Project) : base(path, scope) { } + settings.automaticallyLinkAttributedYarnCommandsAndFunctions = automaticallyLinkAttributedYarnCommandsAndFunctions; + settings.autoRefreshLocalisedAssets = autoRefreshLocalisedAssets; - public override void OnActivate(string searchContext, VisualElement rootElement) - { - // This function is called when the user clicks on the MyCustom element in the Settings window. - baseSettings = YarnSpinnerProjectSettings.GetOrCreateSettings(); + return settings; } - public override void OnGUI(string searchContext) + internal void WriteSettings(string path = null, Yarn.Unity.ILogger iLogger = null) { - // Use IMGUI to display UI: - EditorGUILayout.LabelField("Automatically update localised assets with Yarn Projects"); + var logger = ValidLogger(iLogger); - using (var changeCheck = new EditorGUI.ChangeCheckScope()) + var settingsPath = YarnSpinnerProjectSettingsPath; + if (path != null) { - var result = EditorGUILayout.Toggle(baseSettings.autoRefreshLocalisedAssets); + settingsPath = Path.Combine(path, settingsPath); + } - if (changeCheck.changed) - { - baseSettings.autoRefreshLocalisedAssets = result; - baseSettings.WriteSettings(); - } + // var jsonValue = EditorJsonUtility.ToJson(this); + var dictForm = new System.Collections.Generic.Dictionary(); + dictForm["automaticallyLinkAttributedYarnCommandsAndFunctions"] = this.automaticallyLinkAttributedYarnCommandsAndFunctions; + dictForm["autoRefreshLocalisedAssets"] = this.autoRefreshLocalisedAssets; + + var jsonValue = Json.Serialize(dictForm); + + var folder = Path.GetDirectoryName(YarnSpinnerProjectSettingsPath); + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + try + { + File.WriteAllText(YarnSpinnerProjectSettingsPath, jsonValue); + } + catch (System.Exception e) + { + logger.WriteLine($"Failed to save Yarn Spinner project settings to {YarnSpinnerProjectSettingsPath}: {e.Message}"); } } - // Register the SettingsProvider - [SettingsProvider] - public static SettingsProvider CreateYarnSpinnerProjectSettingsProvider() + // if the provided logger is valid just return it + // otherwise return the default logger + private static Yarn.Unity.ILogger ValidLogger(Yarn.Unity.ILogger iLogger) { - var provider = new YarnSpinnerProjectSettingsProvider("Project/Yarn Spinner", SettingsScope.Project); - - var keywords = new List() { "yarn", "spinner", "localisation" }; - provider.keywords = keywords; - return provider; + var logger = iLogger; + if (logger == null) + { +#if UNITY_EDITOR + logger = new UnityLogger(); +#else + logger = new NullLogger(); +#endif + } + return logger; } } } diff --git a/Editor/YarnSpinnerProjectSettingsProvider.cs b/Editor/YarnSpinnerProjectSettingsProvider.cs new file mode 100644 index 00000000..98442bbc --- /dev/null +++ b/Editor/YarnSpinnerProjectSettingsProvider.cs @@ -0,0 +1,53 @@ +namespace Yarn.Unity.Editor +{ + using System.Collections.Generic; + using System.IO; + using System.Linq; + using UnityEditor; + using UnityEngine; + using UnityEngine.UIElements; + using UnityEditor.UIElements; + + class YarnSpinnerProjectSettingsProvider : SettingsProvider + { + private YarnSpinnerProjectSettings baseSettings; + + public YarnSpinnerProjectSettingsProvider(string path, SettingsScope scope = SettingsScope.Project) : base(path, scope) { } + + public override void OnActivate(string searchContext, VisualElement rootElement) + { + // This function is called when the user clicks on the MyCustom element in the Settings window. + baseSettings = YarnSpinnerProjectSettings.GetOrCreateSettings(); + } + + public override void OnGUI(string searchContext) + { + using (var changeCheck = new EditorGUI.ChangeCheckScope()) + { + EditorGUILayout.LabelField("Automatically update localised assets with Yarn Projects"); + var localisedAssetUpdate = EditorGUILayout.Toggle(baseSettings.autoRefreshLocalisedAssets); + + EditorGUILayout.LabelField("do codegen"); + var linkingAttributedFuncs = EditorGUILayout.Toggle(baseSettings.automaticallyLinkAttributedYarnCommandsAndFunctions); + + if (changeCheck.changed) + { + baseSettings.autoRefreshLocalisedAssets = localisedAssetUpdate; + baseSettings.automaticallyLinkAttributedYarnCommandsAndFunctions = linkingAttributedFuncs; + baseSettings.WriteSettings(); + } + } + } + + // Register the SettingsProvider + [SettingsProvider] + public static SettingsProvider CreateYarnSpinnerProjectSettingsProvider() + { + var provider = new YarnSpinnerProjectSettingsProvider("Project/Yarn Spinner", SettingsScope.Project); + + var keywords = new List() { "yarn", "spinner", "localisation", "codegen", "attribute" }; + provider.keywords = keywords; + return provider; + } + } +} diff --git a/Editor/YarnSpinnerProjectSettingsProvider.cs.meta b/Editor/YarnSpinnerProjectSettingsProvider.cs.meta new file mode 100644 index 00000000..644dcd5f --- /dev/null +++ b/Editor/YarnSpinnerProjectSettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ba3b32b8f5dd4ee0abbb05c8eef314a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/SourceGenerator/YarnSpinner.Unity.SourceCodeGenerator.dll b/SourceGenerator/YarnSpinner.Unity.SourceCodeGenerator.dll index b90682ab..e9bc1720 100644 Binary files a/SourceGenerator/YarnSpinner.Unity.SourceCodeGenerator.dll and b/SourceGenerator/YarnSpinner.Unity.SourceCodeGenerator.dll differ