From eaa90aef75fe041c666fa896096d13b3a398795e Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Fri, 3 Apr 2015 16:32:49 +0100 Subject: [PATCH 01/30] Initial localisation support via CSV files --- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 75 ++++ .../Flowchart/Editor/LanguageEditor.cs.meta | 12 + Assets/Fungus/Flowchart/Scripts/CSVSupport.cs | 73 ++++ .../Flowchart/Scripts/CSVSupport.cs.meta | 12 + Assets/Fungus/Flowchart/Scripts/Language.cs | 379 ++++++++++++++++++ .../Fungus/Flowchart/Scripts/Language.cs.meta | 12 + Assets/Fungus/Narrative/Editor/MenuEditor.cs | 4 + Assets/Fungus/Narrative/Editor/SayEditor.cs | 6 +- Assets/Fungus/Narrative/Scripts/Character.cs | 34 +- .../Fungus/Narrative/Scripts/Commands/Menu.cs | 32 +- .../Fungus/Narrative/Scripts/Commands/Say.cs | 34 +- 11 files changed, 667 insertions(+), 6 deletions(-) create mode 100644 Assets/Fungus/Flowchart/Editor/LanguageEditor.cs create mode 100644 Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta create mode 100644 Assets/Fungus/Flowchart/Scripts/CSVSupport.cs create mode 100644 Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta create mode 100644 Assets/Fungus/Flowchart/Scripts/Language.cs create mode 100644 Assets/Fungus/Flowchart/Scripts/Language.cs.meta diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs new file mode 100644 index 00000000..4ed9798b --- /dev/null +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -0,0 +1,75 @@ +using UnityEditor; +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Rotorz.ReorderableList; + +namespace Fungus +{ + + [CustomEditor(typeof(Language))] + public class LanguageEditor : Editor + { + protected SerializedProperty activeLanguageProp; + protected SerializedProperty localizedObjectsProp; + + protected virtual void OnEnable() + { + activeLanguageProp = serializedObject.FindProperty("activeLanguage"); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + Language t = target as Language; + + EditorGUILayout.PropertyField(activeLanguageProp); + + GUILayout.BeginHorizontal(); + + if (GUILayout.Button(new GUIContent("Export Strings File"))) + { + ExportStrings(t); + } + + GUILayout.Space(8); + + if (GUILayout.Button(new GUIContent("Import Strings File"))) + { + ImportStrings(t); + } + + GUILayout.EndHorizontal(); + + serializedObject.ApplyModifiedProperties(); + } + + public virtual void ExportStrings(Language language) + { + string path = EditorUtility.SaveFilePanel("Export strings", "", + "strings.csv", ""); + if (path.Length == 0) + { + return; + } + + string csvData = language.ExportCSV(); + File.WriteAllText(path, csvData); + } + + public virtual void ImportStrings(Language language) + { + string path = EditorUtility.OpenFilePanel("Import strings", "", ""); + if (path.Length == 0) + { + return; + } + + string stringsFile = File.ReadAllText(path); + language.ImportCSV(stringsFile); + } + } + +} diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta new file mode 100644 index 00000000..5448fada --- /dev/null +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 73e0ffd2fe9ba4afb995e1587c027556 +timeCreated: 1427887512 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs new file mode 100644 index 00000000..f92ec78a --- /dev/null +++ b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs @@ -0,0 +1,73 @@ +using UnityEngine; +using System.Collections; +using System.Text.RegularExpressions; +using System.Linq; +using System; + +namespace Fungus +{ + + // Some CSV utilities cobbled together from stack overflow answers + // CSV escape & unescape from http://stackoverflow.com/questions/769621/dealing-with-commas-in-a-csv-file + // http://answers.unity3d.com/questions/144200/are-there-any-csv-reader-for-unity3d-without-needi.html + public static class CSVSupport + { + public static string Escape( string s ) + { + s = s.Replace("\n", "\\n"); + + if ( s.Contains( QUOTE ) ) + s = s.Replace( QUOTE, ESCAPED_QUOTE ); + + //if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 ) + s = QUOTE + s + QUOTE; + + return s; + } + + public static string Unescape( string s ) + { + s = s.Replace("\\n", "\n"); + + if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) ) + { + s = s.Substring( 1, s.Length - 2 ); + + if ( s.Contains( ESCAPED_QUOTE ) ) + s = s.Replace( ESCAPED_QUOTE, QUOTE ); + } + + return s; + } + + public static string[] SplitCSVLine(string line) + { + + // '(?[^'\\]*(?:\\[\S\s][^'\\]*)*)' # Either $1: Single quoted string, + + string pattern = @" + # Match one value in valid CSV string. + (?!\s*$) # Don't match empty last value. + \s* # Strip whitespace before value. + (?: # Group for value alternatives. + | ""(?[^""\\]*(?:\\[\S\s][^""\\]*)*)"" # or $2: Double quoted string, + | (?[^,'""\s\\]*(?:\s+[^,'""\s\\]+)*) # or $3: Non-comma, non-quote stuff. + ) # End group of value alternatives. + \s* # Strip whitespace after value. + (?:,|$) # Field ends on comma or EOS. + "; + + string[] values = (from Match m in Regex.Matches(line, pattern, + RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) + select m.Groups[1].Value).ToArray(); + + return values; + } + + + private const string QUOTE = "\""; + private const string ESCAPED_QUOTE = "\"\""; + // private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' }; + } + +} diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta new file mode 100644 index 00000000..2ddf37bd --- /dev/null +++ b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4468f4dcfdfbf46b088949ea57ed6135 +timeCreated: 1427897861 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs new file mode 100644 index 00000000..8d7c7521 --- /dev/null +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -0,0 +1,379 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Fungus +{ + + interface ILocalizable + { + string GetLocalizationID(); + + string GetStandardText(); + + void SetStandardText(string standardText); + + string GetTimestamp(); + + string GetDescription(); + } + + /** + * Multi-language localization support. + */ + public class Language : MonoBehaviour, ISerializationCallbackReceiver + { + /** + * Currently active language, usually defined by a two letter language code (e.g DE = German) + */ + public string activeLanguage = ""; + + [SerializeField] + protected List keys; + + [SerializeField] + protected List values; + + // We store the localized strings in a dictionary for easy lookup, but use lists for serialization + // http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html + protected Dictionary localizedStrings = new Dictionary(); + + // Gameobjects that are being managed for localization. + // Each game object should have a child component that implements ISerializable + // As Unity doesn't provide a persistant object identifier, we use the index + // in this list as a way to uniquely identify string objects + public List localizedObjects = new List(); + + /** + * Temp storage for a single item of standard text read from a scene object. + */ + protected class LanguageItem + { + public string timeStamp; + public string description; + public string standardText; + } + + public virtual void Start() + { + if (activeLanguage.Length > 0) + { + SetActiveLanguage(activeLanguage); + } + } + + /** + * Export all localized strings to an easy to edit CSV file. + */ + public virtual string ExportCSV() + { + // Build a list of the language codes currently in use + string csvHeader = "Key,Timestamp,Description,Standard"; + List languageCodes = FindLanguageCodes(); + foreach (string languageCode in languageCodes) + { + csvHeader += "," + languageCode; + } + + // Collect all the language items present in the scene + Dictionary languageItems = FindLanguageItems(); + + // Build the CSV file using collected language items and the corresponding store localized strings + string csvData = csvHeader + "\n"; + foreach (string stringId in languageItems.Keys) + { + LanguageItem languageItem = languageItems[stringId]; + + string row = CSVSupport.Escape(stringId); + row += "," + CSVSupport.Escape(languageItem.timeStamp); + row += "," + CSVSupport.Escape(languageItem.description); + row += "," + CSVSupport.Escape(languageItem.standardText); + + foreach (string languageCode in languageCodes) + { + string key = stringId + "." + languageCode; + if (localizedStrings.ContainsKey(key)) + { + row += "," + CSVSupport.Escape(localizedStrings[key]); + } + else + { + row += ","; // Empty field + } + } + + csvData += row + "\n"; + } + + return csvData; + } + + /** + * Import strings from a CSV file. + * 1. Any changes to standard text items will be applied to the corresponding scene object. + * 2. Any localized strings will be added to the localization dictionary. + */ + public virtual void ImportCSV(string csvData) + { + // Split into lines + // Excel on Mac exports csv files with \r line endings, so we need to support that too. + string[] lines = csvData.Split('\n', '\r'); + + if (lines.Length == 0) + { + return; + } + + localizedStrings.Clear(); + + // Parse header row + string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); + + for (int i = 1; i < lines.Length; ++i) + { + string line = lines[i]; + + string[] fields = CSVSupport.SplitCSVLine(line); + if (fields.Length < 4) + { + continue; + } + + string stringId = fields[0]; + // Ignore timestamp & notes fields + string standardText = CSVSupport.Unescape(fields[3]); + + PopulateGameString(stringId, standardText); + + // Store localized string in stringDict + for (int j = 4; j < fields.Length; ++j) + { + if (j >= columnNames.Length) + { + continue; + } + string languageCode = columnNames[j]; + string languageEntry = CSVSupport.Unescape(fields[j]); + + if (languageEntry.Length > 0) + { + // The dictionary key is the basic string id with . appended + localizedStrings[stringId + "." + languageCode] = languageEntry; + } + } + } + } + + /** + * Search through the scene + */ + protected Dictionary FindLanguageItems() + { + Dictionary languageItems = new Dictionary(); + + // Export all Say and Menu commands in the scene + Flowchart[] flowcharts = GameObject.FindObjectsOfType(); + foreach (Flowchart flowchart in flowcharts) + { + Block[] blocks = flowchart.GetComponentsInChildren(); + foreach (Block block in blocks) + { + foreach (Command command in block.commandList) + { + string stringID = ""; + string standardText = ""; + + System.Type type = command.GetType(); + if (type == typeof(Say)) + { + stringID = "SAY." + flowchart.name + "." + command.itemId; + Say sayCommand = command as Say; + standardText = sayCommand.storyText; + } + else if (type == typeof(Menu)) + { + stringID = "MENU." + flowchart.name + "." + command.itemId; + Menu menuCommand = command as Menu; + standardText = menuCommand.text; + } + else + { + continue; + } + + LanguageItem languageItem = null; + if (languageItems.ContainsKey(stringID)) + { + languageItem = languageItems[stringID]; + } + else + { + languageItem = new LanguageItem(); + languageItems[stringID] = languageItem; + } + + // Update basic properties,leaving localised strings intact + languageItem.timeStamp = "10/10/2015"; + languageItem.description = "Note"; + languageItem.standardText = standardText; + } + } + } + + return languageItems; + } + + public virtual void PopulateGameString(string stringId, string text) + { + string[] idParts = stringId.Split('.'); + if (idParts.Length == 0) + { + return; + } + + string stringType = idParts[0]; + if (stringType == "SAY") + { + if (idParts.Length != 3) + { + return; + } + + string flowchartName = idParts[1]; + int itemId = int.Parse(idParts[2]); + + GameObject go = GameObject.Find(flowchartName); + Flowchart flowchart = go.GetComponentInChildren(); + if (flowchart != null) + { + foreach (Say say in flowchart.GetComponentsInChildren()) + { + if (say.itemId == itemId) + { + say.storyText = text; + } + } + } + } + else if (stringType == "MENU") + { + if (idParts.Length != 3) + { + return; + } + + string flowchartName = idParts[1]; + int itemId = int.Parse(idParts[2]); + + GameObject go = GameObject.Find(flowchartName); + Flowchart flowchart = go.GetComponentInChildren(); + if (flowchart != null) + { + foreach (Menu menu in flowchart.GetComponentsInChildren()) + { + if (menu.itemId == itemId) + { + menu.text = text; + } + } + } + } + } + + public virtual void SetActiveLanguage(string languageCode) + { + // This function should only ever be called when the game is playing (not in editor). + // If it was called in the editor it would permanently modify the text properties in the scene objects. + if (!Application.isPlaying) + { + return; + } + + List languageCodes = FindLanguageCodes(); + if (!languageCodes.Contains(languageCode)) + { + Debug.LogWarning("Language code " + languageCode + " not found."); + } + + // Find all string keys that match the language code and populate the corresponding game object + foreach (string key in localizedStrings.Keys) + { + if (GetLanguageId(key) == languageCode) + { + PopulateGameString(GetStringId(key), localizedStrings[key]); + } + } + } + + public void OnBeforeSerialize() + { + keys.Clear(); + values.Clear(); + foreach (string key in localizedStrings.Keys) + { + string value = localizedStrings[key]; + keys.Add(key); + values.Add(value); + } + } + + public void OnAfterDeserialize() + { + // Both arrays should be the same length, but use the min length just in case + int minCount = Math.Min(keys.Count, values.Count); + + // Populate the string dict + localizedStrings.Clear(); + for (int i = 0; i < minCount; ++i) + { + string key = keys[i]; + string value = values[i]; + localizedStrings[key] = value; + } + } + + protected virtual string GetStringId(string key) + { + int lastDotIndex = key.LastIndexOf("."); + if (lastDotIndex <= 0 || + lastDotIndex == key.Length - 1) + { + // Malformed key + return ""; + } + + return key.Substring(0, lastDotIndex); + } + + protected virtual string GetLanguageId(string key) + { + int lastDotIndex = key.LastIndexOf("."); + if (lastDotIndex <= 0 || + lastDotIndex == key.Length - 1) + { + // Malformed key + return ""; + } + + return key.Substring(lastDotIndex + 1, key.Length - lastDotIndex - 1); + } + + protected virtual List FindLanguageCodes() + { + // Build a list of the language codes actually in use + List languageCodes = new List(); + foreach (string key in keys) + { + string languageId = GetLanguageId(key); + if (!languageCodes.Contains(languageId)) + { + languageCodes.Add(languageId); + } + } + + return languageCodes; + } + } + +} \ No newline at end of file diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs.meta b/Assets/Fungus/Flowchart/Scripts/Language.cs.meta new file mode 100644 index 00000000..f3417a1f --- /dev/null +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e5724422a635e425bae0af9ffe2615d6 +timeCreated: 1427886378 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/Narrative/Editor/MenuEditor.cs b/Assets/Fungus/Narrative/Editor/MenuEditor.cs index e153b078..4a253caf 100644 --- a/Assets/Fungus/Narrative/Editor/MenuEditor.cs +++ b/Assets/Fungus/Narrative/Editor/MenuEditor.cs @@ -11,6 +11,7 @@ namespace Fungus public class MenuEditor : CommandEditor { protected SerializedProperty textProp; + protected SerializedProperty descriptionProp; protected SerializedProperty targetBlockProp; protected SerializedProperty hideIfVisitedProp; protected SerializedProperty setMenuDialogProp; @@ -18,6 +19,7 @@ namespace Fungus protected virtual void OnEnable() { textProp = serializedObject.FindProperty("text"); + descriptionProp = serializedObject.FindProperty("description"); targetBlockProp = serializedObject.FindProperty("targetBlock"); hideIfVisitedProp = serializedObject.FindProperty("hideIfVisited"); setMenuDialogProp = serializedObject.FindProperty("setMenuDialog"); @@ -34,6 +36,8 @@ namespace Fungus serializedObject.Update(); EditorGUILayout.PropertyField(textProp); + + EditorGUILayout.PropertyField(descriptionProp); BlockEditor.BlockField(targetBlockProp, new GUIContent("Target Block", "Block to call when option is selected"), diff --git a/Assets/Fungus/Narrative/Editor/SayEditor.cs b/Assets/Fungus/Narrative/Editor/SayEditor.cs index 76fee36a..d58f11f8 100644 --- a/Assets/Fungus/Narrative/Editor/SayEditor.cs +++ b/Assets/Fungus/Narrative/Editor/SayEditor.cs @@ -100,6 +100,7 @@ namespace Fungus protected SerializedProperty characterProp; protected SerializedProperty portraitProp; protected SerializedProperty storyTextProp; + protected SerializedProperty descriptionProp; protected SerializedProperty voiceOverClipProp; protected SerializedProperty showAlwaysProp; protected SerializedProperty showCountProp; @@ -114,6 +115,7 @@ namespace Fungus characterProp = serializedObject.FindProperty("character"); portraitProp = serializedObject.FindProperty("portrait"); storyTextProp = serializedObject.FindProperty("storyText"); + descriptionProp = serializedObject.FindProperty("description"); voiceOverClipProp = serializedObject.FindProperty("voiceOverClip"); showAlwaysProp = serializedObject.FindProperty("showAlways"); showCountProp = serializedObject.FindProperty("showCount"); @@ -170,7 +172,9 @@ namespace Fungus } EditorGUILayout.PropertyField(storyTextProp); - + + EditorGUILayout.PropertyField(descriptionProp); + EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(extendPreviousProp); diff --git a/Assets/Fungus/Narrative/Scripts/Character.cs b/Assets/Fungus/Narrative/Scripts/Character.cs index a4abf6af..de99b3f2 100644 --- a/Assets/Fungus/Narrative/Scripts/Character.cs +++ b/Assets/Fungus/Narrative/Scripts/Character.cs @@ -1,12 +1,14 @@ using UnityEngine; +using UnityEngine.Serialization; using System.Collections; using System.Collections.Generic; +using System; namespace Fungus { [ExecuteInEditMode] - public class Character : MonoBehaviour + public class Character : MonoBehaviour, ILocalizable { public string nameText; // We need a separate name as the object name is used for character variations (e.g. "Smurf Happy", "Smurf Sad") public Color nameColor = Color.white; @@ -16,8 +18,9 @@ namespace Fungus public FacingDirection portraitsFace; public PortraitState state; + [FormerlySerializedAs("notes")] [TextArea(5,10)] - public string notes; + public string description; static public List activeCharacters = new List(); @@ -33,6 +36,33 @@ namespace Fungus { activeCharacters.Remove(this); } + + // ILocalizable methods + + public virtual string GetLocalizationID() + { + return "CHARACTER." + nameText; + } + + public virtual string GetStandardText() + { + return nameText; + } + + public virtual void SetStandardText(string standardText) + { + nameText = standardText; + } + + public virtual string GetTimestamp() + { + return DateTime.Now.ToShortDateString(); + } + + public virtual string GetDescription() + { + return description; + } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs b/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs index 763cd8d0..b82cd41b 100644 --- a/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs +++ b/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs @@ -11,7 +11,7 @@ namespace Fungus "Menu", "Displays a multiple choice menu")] [AddComponentMenu("")] - public class Menu : Command + public class Menu : Command, ILocalizable { // Menu displays a menu button which will execute the target block when clicked @@ -22,6 +22,9 @@ namespace Fungus public string text = "Option Text"; + [Tooltip("Notes about the option text for other authors, localization, etc.")] + public string description = ""; + [FormerlySerializedAs("targetSequence")] public Block targetBlock; @@ -113,6 +116,33 @@ namespace Fungus { return false; } + + // ILocalizable methods + + public virtual string GetLocalizationID() + { + return "MENU." + itemId.ToString(); + } + + public virtual string GetStandardText() + { + return text; + } + + public virtual void SetStandardText(string standardText) + { + text = standardText; + } + + public virtual string GetTimestamp() + { + return DateTime.Now.ToShortDateString(); + } + + public virtual string GetDescription() + { + return description; + } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs index 5af02575..f1982852 100644 --- a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs +++ b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs @@ -9,10 +9,13 @@ namespace Fungus "Say", "Writes text in a dialog box.")] [AddComponentMenu("")] - public class Say : Command + public class Say : Command, ILocalizable { [TextArea(5,10)] - public string storyText; + public string storyText = ""; + + [Tooltip("Notes about this story text for other authors, localization, etc.")] + public string description = ""; [Tooltip("Character that is speaking")] public Character character; @@ -161,6 +164,33 @@ namespace Fungus { executionCount = 0; } + + // ILocalizable methods + + public virtual string GetLocalizationID() + { + return "SAY." + itemId.ToString(); + } + + public virtual string GetStandardText() + { + return storyText; + } + + public virtual void SetStandardText(string standardText) + { + storyText = standardText; + } + + public virtual string GetTimestamp() + { + return DateTime.Now.ToShortDateString(); + } + + public virtual string GetDescription() + { + return description; + } } } \ No newline at end of file From 34e23dda805ef616f0ee2cbc2c28d2b0296077f3 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Fri, 3 Apr 2015 16:37:32 +0100 Subject: [PATCH 02/30] Removed localized objects list --- Assets/Fungus/Flowchart/Editor/LanguageEditor.cs | 1 - Assets/Fungus/Flowchart/Scripts/Language.cs | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index 4ed9798b..8bf7d121 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -12,7 +12,6 @@ namespace Fungus public class LanguageEditor : Editor { protected SerializedProperty activeLanguageProp; - protected SerializedProperty localizedObjectsProp; protected virtual void OnEnable() { diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 8d7c7521..c4b351d0 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -39,12 +39,6 @@ namespace Fungus // http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html protected Dictionary localizedStrings = new Dictionary(); - // Gameobjects that are being managed for localization. - // Each game object should have a child component that implements ISerializable - // As Unity doesn't provide a persistant object identifier, we use the index - // in this list as a way to uniquely identify string objects - public List localizedObjects = new List(); - /** * Temp storage for a single item of standard text read from a scene object. */ @@ -79,6 +73,9 @@ namespace Fungus // Collect all the language items present in the scene Dictionary languageItems = FindLanguageItems(); + // Update language items with localization data from CSV file + + // Build the CSV file using collected language items and the corresponding store localized strings string csvData = csvHeader + "\n"; foreach (string stringId in languageItems.Keys) From 00a4f34e0068b24e9d9bed2eadfa70c7c3a53323 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Fri, 3 Apr 2015 20:44:45 +0100 Subject: [PATCH 03/30] Language object now uses a CSV text asset property --- .gitignore | 3 +- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 3 + Assets/Fungus/Flowchart/Scripts/Language.cs | 365 ++++++++++-------- Assets/strings.csv | 32 ++ Assets/strings.csv.meta | 8 + 5 files changed, 242 insertions(+), 169 deletions(-) create mode 100644 Assets/strings.csv create mode 100644 Assets/strings.csv.meta diff --git a/.gitignore b/.gitignore index 3ea60107..f9a51964 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ *.unityproj *.sln -*.userprefs \ No newline at end of file +*.userprefs +Assets/.~lock.strings.csv# diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index 8bf7d121..8f8ba536 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -12,10 +12,12 @@ namespace Fungus public class LanguageEditor : Editor { protected SerializedProperty activeLanguageProp; + protected SerializedProperty localizationFileProp; protected virtual void OnEnable() { activeLanguageProp = serializedObject.FindProperty("activeLanguage"); + localizationFileProp = serializedObject.FindProperty("localizationFile"); } public override void OnInspectorGUI() @@ -25,6 +27,7 @@ namespace Fungus Language t = target as Language; EditorGUILayout.PropertyField(activeLanguageProp); + EditorGUILayout.PropertyField(localizationFileProp); GUILayout.BeginHorizontal(); diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index c4b351d0..7f2bc4c6 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -22,38 +22,38 @@ namespace Fungus /** * Multi-language localization support. */ - public class Language : MonoBehaviour, ISerializationCallbackReceiver + public class Language : MonoBehaviour { /** * Currently active language, usually defined by a two letter language code (e.g DE = German) */ public string activeLanguage = ""; - [SerializeField] - protected List keys; - - [SerializeField] - protected List values; - - // We store the localized strings in a dictionary for easy lookup, but use lists for serialization - // http://docs.unity3d.com/ScriptReference/ISerializationCallbackReceiver.OnBeforeSerialize.html protected Dictionary localizedStrings = new Dictionary(); /** - * Temp storage for a single item of standard text read from a scene object. + * Temp storage for a single item of standard text and its localizations */ protected class LanguageItem { public string timeStamp; public string description; public string standardText; + public Dictionary localizedStrings = new Dictionary(); } + /** + * CSV file containing localization data + */ + public TextAsset localizationFile; + public virtual void Start() { - if (activeLanguage.Length > 0) + if (activeLanguage.Length > 0 && + localizationFile != null && + localizationFile.text.Length > 0) { - SetActiveLanguage(activeLanguage); + SetActiveLanguage(activeLanguage, localizationFile.text); } } @@ -62,21 +62,32 @@ namespace Fungus */ public virtual string ExportCSV() { - // Build a list of the language codes currently in use - string csvHeader = "Key,Timestamp,Description,Standard"; - List languageCodes = FindLanguageCodes(); - foreach (string languageCode in languageCodes) - { - csvHeader += "," + languageCode; - } - // Collect all the language items present in the scene Dictionary languageItems = FindLanguageItems(); // Update language items with localization data from CSV file + if (localizationFile != null && + localizationFile.text.Length > 0) + { + AddLocalisedStrings(languageItems, localizationFile.text); + } + // Build CSV header row and a list of the language codes currently in use + string csvHeader = "Key,Timestamp,Description,Standard"; + List languageCodes = new List(); + foreach (LanguageItem languageItem in languageItems.Values) + { + foreach (string languageCode in languageItem.localizedStrings.Keys) + { + if (!languageCodes.Contains(languageCode)) + { + languageCodes.Add(languageCode); + csvHeader += "," + languageCode; + } + } + } - // Build the CSV file using collected language items and the corresponding store localized strings + // Build the CSV file using collected language items string csvData = csvHeader + "\n"; foreach (string stringId in languageItems.Keys) { @@ -89,10 +100,9 @@ namespace Fungus foreach (string languageCode in languageCodes) { - string key = stringId + "." + languageCode; - if (localizedStrings.ContainsKey(key)) + if (languageItem.localizedStrings.ContainsKey(languageCode)) { - row += "," + CSVSupport.Escape(localizedStrings[key]); + row += "," + CSVSupport.Escape(languageItem.localizedStrings[languageCode]); } else { @@ -106,69 +116,10 @@ namespace Fungus return csvData; } - /** - * Import strings from a CSV file. - * 1. Any changes to standard text items will be applied to the corresponding scene object. - * 2. Any localized strings will be added to the localization dictionary. - */ - public virtual void ImportCSV(string csvData) - { - // Split into lines - // Excel on Mac exports csv files with \r line endings, so we need to support that too. - string[] lines = csvData.Split('\n', '\r'); - - if (lines.Length == 0) - { - return; - } - - localizedStrings.Clear(); - - // Parse header row - string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); - - for (int i = 1; i < lines.Length; ++i) - { - string line = lines[i]; - - string[] fields = CSVSupport.SplitCSVLine(line); - if (fields.Length < 4) - { - continue; - } - - string stringId = fields[0]; - // Ignore timestamp & notes fields - string standardText = CSVSupport.Unescape(fields[3]); - - PopulateGameString(stringId, standardText); - - // Store localized string in stringDict - for (int j = 4; j < fields.Length; ++j) - { - if (j >= columnNames.Length) - { - continue; - } - string languageCode = columnNames[j]; - string languageEntry = CSVSupport.Unescape(fields[j]); - - if (languageEntry.Length > 0) - { - // The dictionary key is the basic string id with . appended - localizedStrings[stringId + "." + languageCode] = languageEntry; - } - } - } - } - - /** - * Search through the scene - */ protected Dictionary FindLanguageItems() { Dictionary languageItems = new Dictionary(); - + // Export all Say and Menu commands in the scene Flowchart[] flowcharts = GameObject.FindObjectsOfType(); foreach (Flowchart flowchart in flowcharts) @@ -198,7 +149,7 @@ namespace Fungus { continue; } - + LanguageItem languageItem = null; if (languageItems.ContainsKey(stringID)) { @@ -209,7 +160,7 @@ namespace Fungus languageItem = new LanguageItem(); languageItems[stringID] = languageItem; } - + // Update basic properties,leaving localised strings intact languageItem.timeStamp = "10/10/2015"; languageItem.description = "Note"; @@ -217,10 +168,124 @@ namespace Fungus } } } - + return languageItems; } + protected virtual void AddLocalisedStrings(Dictionary languageItems, string csvData) + { + // Split into lines + // Excel on Mac exports csv files with \r line endings, so we need to support that too. + string[] lines = csvData.Split('\n', '\r'); + + if (lines.Length == 0) + { + // Early out if no data in file + return; + } + + // Parse header row + string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); + + for (int i = 1; i < lines.Length; ++i) + { + string line = lines[i]; + + string[] fields = CSVSupport.SplitCSVLine(line); + if (fields.Length < 4) + { + continue; + } + + string stringId = fields[0]; + + // Store localized strings for this string id + for (int j = 4; j < fields.Length; ++j) + { + if (j >= columnNames.Length) + { + continue; + } + string languageCode = columnNames[j]; + string languageEntry = CSVSupport.Unescape(fields[j]); + + if (languageEntry.Length > 0) + { + if (languageItems.ContainsKey(stringId)) + { + languageItems[stringId].localizedStrings[languageCode] = languageEntry; + } + } + } + } + } + + public virtual void SetActiveLanguage(string languageCode, string csvData) + { + if (!Application.isPlaying) + { + // This function should only ever be called when the game is playing (not in editor). + return; + } + + localizedStrings.Clear(); + + // Split into lines + // Excel on Mac exports csv files with \r line endings, so we need to support that too. + string[] lines = csvData.Split('\n', '\r'); + + if (lines.Length == 0) + { + // No data rows in file + return; + } + + // Parse header row + string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); + + if (columnNames.Length < 5) + { + // No languages defined in CSV file + return; + } + + int languageIndex = -1; + for (int i = 4; i < columnNames.Length; ++i) + { + if (columnNames[i] == languageCode) + { + languageIndex = i; + break; + } + } + + if (languageIndex == -1) + { + // Language not found + return; + } + + for (int i = 1; i < lines.Length; ++i) + { + string line = lines[i]; + + string[] fields = CSVSupport.SplitCSVLine(line); + if (fields.Length < languageIndex + 1) + { + continue; + } + + string stringId = fields[0]; + string languageEntry = CSVSupport.Unescape(fields[languageIndex]); + + if (languageEntry.Length > 0) + { + localizedStrings[stringId] = languageEntry; + PopulateGameString(stringId, languageEntry); + } + } + } + public virtual void PopulateGameString(string stringId, string text) { string[] idParts = stringId.Split('.'); @@ -228,7 +293,7 @@ namespace Fungus { return; } - + string stringType = idParts[0]; if (stringType == "SAY") { @@ -236,10 +301,10 @@ namespace Fungus { return; } - + string flowchartName = idParts[1]; int itemId = int.Parse(idParts[2]); - + GameObject go = GameObject.Find(flowchartName); Flowchart flowchart = go.GetComponentInChildren(); if (flowchart != null) @@ -259,7 +324,7 @@ namespace Fungus { return; } - + string flowchartName = idParts[1]; int itemId = int.Parse(idParts[2]); @@ -278,98 +343,62 @@ namespace Fungus } } - public virtual void SetActiveLanguage(string languageCode) + /** + * Import strings from a CSV file. + * 1. Any changes to standard text items will be applied to the corresponding scene object. + * 2. Any localized strings will be added to the localization dictionary. + */ + public virtual void ImportCSV(string csvData) { - // This function should only ever be called when the game is playing (not in editor). - // If it was called in the editor it would permanently modify the text properties in the scene objects. - if (!Application.isPlaying) - { - return; - } + /* + // Split into lines + // Excel on Mac exports csv files with \r line endings, so we need to support that too. + string[] lines = csvData.Split('\n', '\r'); - List languageCodes = FindLanguageCodes(); - if (!languageCodes.Contains(languageCode)) + if (lines.Length == 0) { - Debug.LogWarning("Language code " + languageCode + " not found."); + return; } - // Find all string keys that match the language code and populate the corresponding game object - foreach (string key in localizedStrings.Keys) - { - if (GetLanguageId(key) == languageCode) - { - PopulateGameString(GetStringId(key), localizedStrings[key]); - } - } - } + localizedStrings.Clear(); - public void OnBeforeSerialize() - { - keys.Clear(); - values.Clear(); - foreach (string key in localizedStrings.Keys) - { - string value = localizedStrings[key]; - keys.Add(key); - values.Add(value); - } - } - - public void OnAfterDeserialize() - { - // Both arrays should be the same length, but use the min length just in case - int minCount = Math.Min(keys.Count, values.Count); + // Parse header row + string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); - // Populate the string dict - localizedStrings.Clear(); - for (int i = 0; i < minCount; ++i) + for (int i = 1; i < lines.Length; ++i) { - string key = keys[i]; - string value = values[i]; - localizedStrings[key] = value; - } - } + string line = lines[i]; - protected virtual string GetStringId(string key) - { - int lastDotIndex = key.LastIndexOf("."); - if (lastDotIndex <= 0 || - lastDotIndex == key.Length - 1) - { - // Malformed key - return ""; - } - - return key.Substring(0, lastDotIndex); - } + string[] fields = CSVSupport.SplitCSVLine(line); + if (fields.Length < 4) + { + continue; + } - protected virtual string GetLanguageId(string key) - { - int lastDotIndex = key.LastIndexOf("."); - if (lastDotIndex <= 0 || - lastDotIndex == key.Length - 1) - { - // Malformed key - return ""; - } + string stringId = fields[0]; + // Ignore timestamp & notes fields + string standardText = CSVSupport.Unescape(fields[3]); - return key.Substring(lastDotIndex + 1, key.Length - lastDotIndex - 1); - } + PopulateGameString(stringId, standardText); - protected virtual List FindLanguageCodes() - { - // Build a list of the language codes actually in use - List languageCodes = new List(); - foreach (string key in keys) - { - string languageId = GetLanguageId(key); - if (!languageCodes.Contains(languageId)) + // Store localized string in stringDict + for (int j = 4; j < fields.Length; ++j) { - languageCodes.Add(languageId); + if (j >= columnNames.Length) + { + continue; + } + string languageCode = columnNames[j]; + string languageEntry = CSVSupport.Unescape(fields[j]); + + if (languageEntry.Length > 0) + { + // The dictionary key is the basic string id with . appended + localizedStrings[stringId + "." + languageCode] = languageEntry; + } } } - - return languageCodes; + */ } } diff --git a/Assets/strings.csv b/Assets/strings.csv new file mode 100644 index 00000000..4d3c1a21 --- /dev/null +++ b/Assets/strings.csv @@ -0,0 +1,32 @@ +"Key","Timestamp","Description","Standard","FR","DE","ES" +"SAY.Flowchart.75","10/10/2015","Note","{t}(Do I really want to do this?){/t} Zero","One","Two","Three" +"MENU.Flowchart.76","10/10/2015","Note","Drink the coffee","Five","Six","Seven" +"MENU.Flowchart.77","10/10/2015","Note","Don't drink the coffee",,, +"SAY.Flowchart.0","10/10/2015","Note","{answer}Excellent.",,, +"SAY.Flowchart.1","10/10/2015","Note","All right. It's been 30 minutes. How do you feel?",,, +"SAY.Flowchart.20","10/10/2015","Note","{worried}Like an idiot who should stop encouraging you.",,, +"SAY.Flowchart.21","10/10/2015","Note","No, that's not right.",,, +"SAY.Flowchart.45","10/10/2015","Note","{shout}No nausea? {shout}Dizziness? {shout}Feeling of sudden and impending doom?",,, +"SAY.Flowchart.22","10/10/2015","Note","Wait, {question}{flash=0.1}what?",,, +"SAY.Flowchart.23","10/10/2015","Note","Hmm... I'll have to revise my {clue}hypothesis…",,, +"SAY.Flowchart.2","10/10/2015","Note","No thanks. The last time I drank your coffee, I spent the day running from an imaginary dog.",,, +"SAY.Flowchart.3","10/10/2015","Note","The hallucinogen was in the {answer}gas, not the coffee.",,, +"SAY.Flowchart.4","10/10/2015","Note","{shout}Still not ok{wp},{/wp} Sherlock!",,, +"SAY.Flowchart.5","10/10/2015","Note","Suit yourself.",,, +"SAY.Flowchart.6","10/10/2015","Note","THE EXPERIMENT œ˙é®√","Non","Nein","No" +"SAY.Flowchart.58","10/10/2015","Note","Ah John,\n {pleased}there you are.\nI've been looking everywhere for you!","Mon frere","Mein frere","Bonjo" +"SAY.Flowchart.7","10/10/2015","Note","{confused}I do live here, you know.",,, +"SAY.Flowchart.8","10/10/2015","Note","{answer}{flash=0.1}Well you arrived at just the right time.",,, +"SAY.Flowchart.30","10/10/2015","Note"," Here, I need you to drink this.",,, +"SAY.Flowchart.9","10/10/2015","Note","{worried}... Why?",,, +"SAY.Flowchart.10","10/10/2015","Note","It's for an experiment.",,, +"SAY.Flowchart.35","10/10/2015","Note"," Don't worry. It won't kill you.",,, +"SAY.Flowchart.11","10/10/2015","Note","{clue}Your words inspire such confidence.",,, +"SAY.Flowchart.12","10/10/2015","Note","Why don't you test it yourself?",,, +"SAY.Flowchart.13","10/10/2015","Note","{question}I can't observe the effects of the experiment if I'm the one participating.",,, +"SAY.Flowchart.74","10/10/2015","Note","Of course.",,, +"SAY.Flowchart.80","10/10/2015","Note","(What should I do now?)",,, +"MENU.Flowchart.78","10/10/2015","Note","Talk to Sherlock.",,, +"MENU.Flowchart.79","10/10/2015","Note","Leave",,, +"SAY.Flowchart.66","10/10/2015","Note","Right.... Good luck with that.",,, +"SAY.Flowchart.70","10/10/2015","Note","Your {stat-up}courage{/stat-up} has increased!",,, diff --git a/Assets/strings.csv.meta b/Assets/strings.csv.meta new file mode 100644 index 00000000..3e1be37a --- /dev/null +++ b/Assets/strings.csv.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eb17c0268d57044eb92109b71e847180 +timeCreated: 1428075678 +licenseType: Free +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: From e063596031dff1f78a054b79ecc2e68dbb9dc97f Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Sat, 4 Apr 2015 22:28:44 +0100 Subject: [PATCH 04/30] Added a robust CSV parser. Localisation file is read at load time. --- Assets/CsvParser.cs | 218 ++++++++++++++++++ Assets/CsvParser.cs.meta | 12 + Assets/Fungus/Flowchart/Scripts/CSVSupport.cs | 27 +-- Assets/Fungus/Flowchart/Scripts/Language.cs | 141 +++-------- Assets/Fungus/Narrative/Scripts/Character.cs | 29 +-- .../Fungus/Narrative/Scripts/Commands/Menu.cs | 29 +-- .../Fungus/Narrative/Scripts/Commands/Say.cs | 29 +-- 7 files changed, 270 insertions(+), 215 deletions(-) create mode 100755 Assets/CsvParser.cs create mode 100644 Assets/CsvParser.cs.meta diff --git a/Assets/CsvParser.cs b/Assets/CsvParser.cs new file mode 100755 index 00000000..7d702aad --- /dev/null +++ b/Assets/CsvParser.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ideafixxxer.CsvParser +{ + public class CsvParser + { + private const char CommaCharacter = ','; + private const char QuoteCharacter = '"'; + + #region Nested types + + private abstract class ParserState + { + public static readonly LineStartState LineStartState = new LineStartState(); + public static readonly ValueStartState ValueStartState = new ValueStartState(); + public static readonly ValueState ValueState = new ValueState(); + public static readonly QuotedValueState QuotedValueState = new QuotedValueState(); + public static readonly QuoteState QuoteState = new QuoteState(); + + public abstract ParserState AnyChar(char ch, ParserContext context); + public abstract ParserState Comma(ParserContext context); + public abstract ParserState Quote(ParserContext context); + public abstract ParserState EndOfLine(ParserContext context); + } + + private class LineStartState : ParserState + { + public override ParserState AnyChar(char ch, ParserContext context) + { + context.AddChar(ch); + return ValueState; + } + + public override ParserState Comma(ParserContext context) + { + context.AddValue(); + return ValueStartState; + } + + public override ParserState Quote(ParserContext context) + { + return QuotedValueState; + } + + public override ParserState EndOfLine(ParserContext context) + { + context.AddLine(); + return LineStartState; + } + } + + private class ValueStartState : LineStartState + { + public override ParserState EndOfLine(ParserContext context) + { + context.AddValue(); + context.AddLine(); + return LineStartState; + } + } + + private class ValueState : ParserState + { + public override ParserState AnyChar(char ch, ParserContext context) + { + context.AddChar(ch); + return ValueState; + } + + public override ParserState Comma(ParserContext context) + { + context.AddValue(); + return ValueStartState; + } + + public override ParserState Quote(ParserContext context) + { + context.AddChar(QuoteCharacter); + return ValueState; + } + + public override ParserState EndOfLine(ParserContext context) + { + context.AddValue(); + context.AddLine(); + return LineStartState; + } + } + + private class QuotedValueState : ParserState + { + public override ParserState AnyChar(char ch, ParserContext context) + { + context.AddChar(ch); + return QuotedValueState; + } + + public override ParserState Comma(ParserContext context) + { + context.AddChar(CommaCharacter); + return QuotedValueState; + } + + public override ParserState Quote(ParserContext context) + { + return QuoteState; + } + + public override ParserState EndOfLine(ParserContext context) + { + context.AddChar('\r'); + context.AddChar('\n'); + return QuotedValueState; + } + } + + private class QuoteState : ParserState + { + public override ParserState AnyChar(char ch, ParserContext context) + { + //undefined, ignore " + context.AddChar(ch); + return QuotedValueState; + } + + public override ParserState Comma(ParserContext context) + { + context.AddValue(); + return ValueStartState; + } + + public override ParserState Quote(ParserContext context) + { + context.AddChar(QuoteCharacter); + return QuotedValueState; + } + + public override ParserState EndOfLine(ParserContext context) + { + context.AddValue(); + context.AddLine(); + return LineStartState; + } + } + + private class ParserContext + { + private readonly StringBuilder _currentValue = new StringBuilder(); + private readonly List _lines = new List(); + private readonly List _currentLine = new List(); + + public void AddChar(char ch) + { + _currentValue.Append(ch); + } + + public void AddValue() + { + _currentLine.Add(_currentValue.ToString()); + _currentValue.Remove(0, _currentValue.Length); + } + + public void AddLine() + { + _lines.Add(_currentLine.ToArray()); + _currentLine.Clear(); + } + + public List GetAllLines() + { + if (_currentValue.Length > 0) + { + AddValue(); + } + if (_currentLine.Count > 0) + { + AddLine(); + } + return _lines; + } + } + + #endregion + + public string[][] Parse(string csvData) + { + var context = new ParserContext(); + + string[] lines = csvData.Split('\n'); + + ParserState currentState = ParserState.LineStartState; + foreach (string next in lines) + { + foreach (char ch in next) + { + switch (ch) + { + case CommaCharacter: + currentState = currentState.Comma(context); + break; + case QuoteCharacter: + currentState = currentState.Quote(context); + break; + default: + currentState = currentState.AnyChar(ch, context); + break; + } + } + currentState = currentState.EndOfLine(context); + } + List allLines = context.GetAllLines(); + return allLines.ToArray(); + } + } +} \ No newline at end of file diff --git a/Assets/CsvParser.cs.meta b/Assets/CsvParser.cs.meta new file mode 100644 index 00000000..8c45d08a --- /dev/null +++ b/Assets/CsvParser.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 803c0d4d8bc9447d1b20e1f4fb86120f +timeCreated: 1428171346 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs index f92ec78a..95921102 100644 --- a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs +++ b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs @@ -39,32 +39,7 @@ namespace Fungus return s; } - - public static string[] SplitCSVLine(string line) - { - - // '(?[^'\\]*(?:\\[\S\s][^'\\]*)*)' # Either $1: Single quoted string, - - string pattern = @" - # Match one value in valid CSV string. - (?!\s*$) # Don't match empty last value. - \s* # Strip whitespace before value. - (?: # Group for value alternatives. - | ""(?[^""\\]*(?:\\[\S\s][^""\\]*)*)"" # or $2: Double quoted string, - | (?[^,'""\s\\]*(?:\s+[^,'""\s\\]+)*) # or $3: Non-comma, non-quote stuff. - ) # End group of value alternatives. - \s* # Strip whitespace after value. - (?:,|$) # Field ends on comma or EOS. - "; - - string[] values = (from Match m in Regex.Matches(line, pattern, - RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) - select m.Groups[1].Value).ToArray(); - - return values; - } - - + private const string QUOTE = "\""; private const string ESCAPED_QUOTE = "\"\""; // private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' }; diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 7f2bc4c6..b55170ed 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -2,23 +2,12 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; +using Ideafixxxer.CsvParser; namespace Fungus { - interface ILocalizable - { - string GetLocalizationID(); - - string GetStandardText(); - - void SetStandardText(string standardText); - - string GetTimestamp(); - - string GetDescription(); - } - /** * Multi-language localization support. */ @@ -36,7 +25,6 @@ namespace Fungus */ protected class LanguageItem { - public string timeStamp; public string description; public string standardText; public Dictionary localizedStrings = new Dictionary(); @@ -73,7 +61,7 @@ namespace Fungus } // Build CSV header row and a list of the language codes currently in use - string csvHeader = "Key,Timestamp,Description,Standard"; + string csvHeader = "Key,Description,Standard"; List languageCodes = new List(); foreach (LanguageItem languageItem in languageItems.Values) { @@ -94,7 +82,6 @@ namespace Fungus LanguageItem languageItem = languageItems[stringId]; string row = CSVSupport.Escape(stringId); - row += "," + CSVSupport.Escape(languageItem.timeStamp); row += "," + CSVSupport.Escape(languageItem.description); row += "," + CSVSupport.Escape(languageItem.standardText); @@ -121,6 +108,7 @@ namespace Fungus Dictionary languageItems = new Dictionary(); // Export all Say and Menu commands in the scene + // To make it easier to localize, we preserve the command order in each exported block. Flowchart[] flowcharts = GameObject.FindObjectsOfType(); foreach (Flowchart flowchart in flowcharts) { @@ -131,19 +119,22 @@ namespace Fungus { string stringID = ""; string standardText = ""; - + string description = ""; + System.Type type = command.GetType(); if (type == typeof(Say)) { stringID = "SAY." + flowchart.name + "." + command.itemId; Say sayCommand = command as Say; standardText = sayCommand.storyText; + description = sayCommand.description; } else if (type == typeof(Menu)) { stringID = "MENU." + flowchart.name + "." + command.itemId; Menu menuCommand = command as Menu; standardText = menuCommand.text; + description = menuCommand.description; } else { @@ -162,9 +153,8 @@ namespace Fungus } // Update basic properties,leaving localised strings intact - languageItem.timeStamp = "10/10/2015"; - languageItem.description = "Note"; languageItem.standardText = standardText; + languageItem.description = description; } } } @@ -174,33 +164,37 @@ namespace Fungus protected virtual void AddLocalisedStrings(Dictionary languageItems, string csvData) { - // Split into lines - // Excel on Mac exports csv files with \r line endings, so we need to support that too. - string[] lines = csvData.Split('\n', '\r'); + CsvParser csvParser = new CsvParser(); + string[][] csvTable = csvParser.Parse(csvData); - if (lines.Length == 0) + if (csvTable.Length <= 1) { - // Early out if no data in file + // No data rows in file return; } - + // Parse header row - string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); + string[] columnNames = csvTable[0]; - for (int i = 1; i < lines.Length; ++i) + for (int i = 1; i < csvTable.Length; ++i) { - string line = lines[i]; - - string[] fields = CSVSupport.SplitCSVLine(line); + string[] fields = csvTable[i]; if (fields.Length < 4) { + // No localized string fields present continue; } string stringId = fields[0]; + if (!languageItems.ContainsKey(stringId)) + { + continue; + } + // Store localized strings for this string id - for (int j = 4; j < fields.Length; ++j) + LanguageItem languageItem = languageItems[stringId]; + for (int j = 3; j < fields.Length; ++j) { if (j >= columnNames.Length) { @@ -211,10 +205,7 @@ namespace Fungus if (languageEntry.Length > 0) { - if (languageItems.ContainsKey(stringId)) - { - languageItems[stringId].localizedStrings[languageCode] = languageEntry; - } + languageItem.localizedStrings[languageCode] = languageEntry; } } } @@ -230,18 +221,17 @@ namespace Fungus localizedStrings.Clear(); - // Split into lines - // Excel on Mac exports csv files with \r line endings, so we need to support that too. - string[] lines = csvData.Split('\n', '\r'); - - if (lines.Length == 0) + CsvParser csvParser = new CsvParser(); + string[][] csvTable = csvParser.Parse(csvData); + + if (csvTable.Length <= 1) { // No data rows in file return; } - + // Parse header row - string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); + string[] columnNames = csvTable[0]; if (columnNames.Length < 5) { @@ -250,7 +240,7 @@ namespace Fungus } int languageIndex = -1; - for (int i = 4; i < columnNames.Length; ++i) + for (int i = 3; i < columnNames.Length; ++i) { if (columnNames[i] == languageCode) { @@ -265,11 +255,10 @@ namespace Fungus return; } - for (int i = 1; i < lines.Length; ++i) + for (int i = 1; i < csvTable.Length; ++i) { - string line = lines[i]; - - string[] fields = CSVSupport.SplitCSVLine(line); + string[] fields = csvTable[i]; + if (fields.Length < languageIndex + 1) { continue; @@ -342,64 +331,6 @@ namespace Fungus } } } - - /** - * Import strings from a CSV file. - * 1. Any changes to standard text items will be applied to the corresponding scene object. - * 2. Any localized strings will be added to the localization dictionary. - */ - public virtual void ImportCSV(string csvData) - { - /* - // Split into lines - // Excel on Mac exports csv files with \r line endings, so we need to support that too. - string[] lines = csvData.Split('\n', '\r'); - - if (lines.Length == 0) - { - return; - } - - localizedStrings.Clear(); - - // Parse header row - string[] columnNames = CSVSupport.SplitCSVLine(lines[0]); - - for (int i = 1; i < lines.Length; ++i) - { - string line = lines[i]; - - string[] fields = CSVSupport.SplitCSVLine(line); - if (fields.Length < 4) - { - continue; - } - - string stringId = fields[0]; - // Ignore timestamp & notes fields - string standardText = CSVSupport.Unescape(fields[3]); - - PopulateGameString(stringId, standardText); - - // Store localized string in stringDict - for (int j = 4; j < fields.Length; ++j) - { - if (j >= columnNames.Length) - { - continue; - } - string languageCode = columnNames[j]; - string languageEntry = CSVSupport.Unescape(fields[j]); - - if (languageEntry.Length > 0) - { - // The dictionary key is the basic string id with . appended - localizedStrings[stringId + "." + languageCode] = languageEntry; - } - } - } - */ - } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Character.cs b/Assets/Fungus/Narrative/Scripts/Character.cs index de99b3f2..82d9e319 100644 --- a/Assets/Fungus/Narrative/Scripts/Character.cs +++ b/Assets/Fungus/Narrative/Scripts/Character.cs @@ -8,7 +8,7 @@ namespace Fungus { [ExecuteInEditMode] - public class Character : MonoBehaviour, ILocalizable + public class Character : MonoBehaviour { public string nameText; // We need a separate name as the object name is used for character variations (e.g. "Smurf Happy", "Smurf Sad") public Color nameColor = Color.white; @@ -36,33 +36,6 @@ namespace Fungus { activeCharacters.Remove(this); } - - // ILocalizable methods - - public virtual string GetLocalizationID() - { - return "CHARACTER." + nameText; - } - - public virtual string GetStandardText() - { - return nameText; - } - - public virtual void SetStandardText(string standardText) - { - nameText = standardText; - } - - public virtual string GetTimestamp() - { - return DateTime.Now.ToShortDateString(); - } - - public virtual string GetDescription() - { - return description; - } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs b/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs index b82cd41b..5ae26e31 100644 --- a/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs +++ b/Assets/Fungus/Narrative/Scripts/Commands/Menu.cs @@ -11,7 +11,7 @@ namespace Fungus "Menu", "Displays a multiple choice menu")] [AddComponentMenu("")] - public class Menu : Command, ILocalizable + public class Menu : Command { // Menu displays a menu button which will execute the target block when clicked @@ -116,33 +116,6 @@ namespace Fungus { return false; } - - // ILocalizable methods - - public virtual string GetLocalizationID() - { - return "MENU." + itemId.ToString(); - } - - public virtual string GetStandardText() - { - return text; - } - - public virtual void SetStandardText(string standardText) - { - text = standardText; - } - - public virtual string GetTimestamp() - { - return DateTime.Now.ToShortDateString(); - } - - public virtual string GetDescription() - { - return description; - } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs index f1982852..0a75aced 100644 --- a/Assets/Fungus/Narrative/Scripts/Commands/Say.cs +++ b/Assets/Fungus/Narrative/Scripts/Commands/Say.cs @@ -9,7 +9,7 @@ namespace Fungus "Say", "Writes text in a dialog box.")] [AddComponentMenu("")] - public class Say : Command, ILocalizable + public class Say : Command { [TextArea(5,10)] public string storyText = ""; @@ -164,33 +164,6 @@ namespace Fungus { executionCount = 0; } - - // ILocalizable methods - - public virtual string GetLocalizationID() - { - return "SAY." + itemId.ToString(); - } - - public virtual string GetStandardText() - { - return storyText; - } - - public virtual void SetStandardText(string standardText) - { - storyText = standardText; - } - - public virtual string GetTimestamp() - { - return DateTime.Now.ToShortDateString(); - } - - public virtual string GetDescription() - { - return description; - } } } \ No newline at end of file From 5d2433e570fac6fcd8b24fa91dc9176f0f510e64 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Tue, 7 Apr 2015 16:59:39 +0100 Subject: [PATCH 05/30] Removed Import CSV button --- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index 8f8ba536..16dc1a69 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -29,22 +29,11 @@ namespace Fungus EditorGUILayout.PropertyField(activeLanguageProp); EditorGUILayout.PropertyField(localizationFileProp); - GUILayout.BeginHorizontal(); - - if (GUILayout.Button(new GUIContent("Export Strings File"))) + if (GUILayout.Button(new GUIContent("Export to CSV"))) { ExportStrings(t); } - GUILayout.Space(8); - - if (GUILayout.Button(new GUIContent("Import Strings File"))) - { - ImportStrings(t); - } - - GUILayout.EndHorizontal(); - serializedObject.ApplyModifiedProperties(); } @@ -60,18 +49,6 @@ namespace Fungus string csvData = language.ExportCSV(); File.WriteAllText(path, csvData); } - - public virtual void ImportStrings(Language language) - { - string path = EditorUtility.OpenFilePanel("Import strings", "", ""); - if (path.Length == 0) - { - return; - } - - string stringsFile = File.ReadAllText(path); - language.ImportCSV(stringsFile); - } } } From d91ad823369d4cf919ef02471bfdeee441b48296 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Tue, 7 Apr 2015 17:02:02 +0100 Subject: [PATCH 06/30] Improved performance of populating localized strings #8 --- Assets/Fungus/Flowchart/Scripts/Language.cs | 31 +++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index b55170ed..79513937 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -255,6 +255,13 @@ namespace Fungus return; } + // Cache a lookup table of flowcharts in the scene + Dictionary flowchartDict = new Dictionary(); + foreach (Flowchart flowChart in GameObject.FindObjectsOfType()) + { + flowchartDict[flowChart.name] = flowChart; + } + for (int i = 1; i < csvTable.Length; ++i) { string[] fields = csvTable[i]; @@ -270,12 +277,12 @@ namespace Fungus if (languageEntry.Length > 0) { localizedStrings[stringId] = languageEntry; - PopulateGameString(stringId, languageEntry); + PopulateGameString(stringId, languageEntry, flowchartDict); } } } - public virtual void PopulateGameString(string stringId, string text) + public virtual void PopulateGameString(string stringId, string text, Dictionary flowchartDict) { string[] idParts = stringId.Split('.'); if (idParts.Length == 0) @@ -291,11 +298,15 @@ namespace Fungus return; } - string flowchartName = idParts[1]; + string flowchartId = idParts[1]; + if (!flowchartDict.ContainsKey(flowchartId)) + { + return; + } + Flowchart flowchart = flowchartDict[flowchartId]; + int itemId = int.Parse(idParts[2]); - GameObject go = GameObject.Find(flowchartName); - Flowchart flowchart = go.GetComponentInChildren(); if (flowchart != null) { foreach (Say say in flowchart.GetComponentsInChildren()) @@ -314,11 +325,15 @@ namespace Fungus return; } - string flowchartName = idParts[1]; + string flowchartId = idParts[1]; + if (!flowchartDict.ContainsKey(flowchartId)) + { + return; + } + Flowchart flowchart = flowchartDict[flowchartId]; + int itemId = int.Parse(idParts[2]); - GameObject go = GameObject.Find(flowchartName); - Flowchart flowchart = go.GetComponentInChildren(); if (flowchart != null) { foreach (Menu menu in flowchart.GetComponentsInChildren()) From db02c4255469f4dd14a7469dd3cf89352ec68b9c Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Wed, 8 Apr 2015 21:17:07 +0100 Subject: [PATCH 07/30] Moved CSVParser to thirdparty folder --- Assets/Fungus/Thirdparty/CSVParser.meta | 9 +++++++++ Assets/{ => Fungus/Thirdparty/CSVParser}/CsvParser.cs | 0 .../{ => Fungus/Thirdparty/CSVParser}/CsvParser.cs.meta | 0 3 files changed, 9 insertions(+) create mode 100644 Assets/Fungus/Thirdparty/CSVParser.meta rename Assets/{ => Fungus/Thirdparty/CSVParser}/CsvParser.cs (100%) rename Assets/{ => Fungus/Thirdparty/CSVParser}/CsvParser.cs.meta (100%) diff --git a/Assets/Fungus/Thirdparty/CSVParser.meta b/Assets/Fungus/Thirdparty/CSVParser.meta new file mode 100644 index 00000000..355e936b --- /dev/null +++ b/Assets/Fungus/Thirdparty/CSVParser.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3469ab31c1c9d4c2da1ae42edc001ded +folderAsset: yes +timeCreated: 1428523768 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CsvParser.cs b/Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs similarity index 100% rename from Assets/CsvParser.cs rename to Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs diff --git a/Assets/CsvParser.cs.meta b/Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs.meta similarity index 100% rename from Assets/CsvParser.cs.meta rename to Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs.meta From f5e1c89936c7b337dc414800839ddcbcc319b9c2 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Wed, 8 Apr 2015 21:38:13 +0100 Subject: [PATCH 08/30] Flowcharts use a localisation id property when exporting strings #8 --- Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs | 3 +++ Assets/Fungus/Flowchart/Scripts/Flowchart.cs | 6 ++++++ Assets/Fungus/Flowchart/Scripts/Language.cs | 14 ++++++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs b/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs index 09585f73..ccd4b8a2 100644 --- a/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs @@ -23,6 +23,7 @@ namespace Fungus protected SerializedProperty hideComponentsProp; protected SerializedProperty runSlowDurationProp; protected SerializedProperty saveSelectionProp; + protected SerializedProperty localizationIdProp; protected SerializedProperty variablesProp; protected virtual void OnEnable() @@ -32,6 +33,7 @@ namespace Fungus hideComponentsProp = serializedObject.FindProperty("hideComponents"); runSlowDurationProp = serializedObject.FindProperty("runSlowDuration"); saveSelectionProp = serializedObject.FindProperty("saveSelection"); + localizationIdProp = serializedObject.FindProperty("localizationId"); variablesProp = serializedObject.FindProperty("variables"); } @@ -48,6 +50,7 @@ namespace Fungus EditorGUILayout.PropertyField(hideComponentsProp); EditorGUILayout.PropertyField(runSlowDurationProp); EditorGUILayout.PropertyField(saveSelectionProp); + EditorGUILayout.PropertyField(localizationIdProp); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); diff --git a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs index efd3bb55..c6d117df 100644 --- a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs +++ b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs @@ -109,6 +109,12 @@ namespace Fungus [Tooltip("Saves the selected block and commands when saving the scene.")] public bool saveSelection = true; + /** + * Unique identifier for identifying this flowchart in localized string keys. + */ + [Tooltip("Unique identifier for this flowchart in localized string keys. An id must be provided for Language string export to work.")] + public string localizationId = ""; + /** * Unique id to assign to the next created item. * Increases monotonically every time a new item is added to the Flowchart. diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 79513937..08b12743 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -112,6 +112,12 @@ namespace Fungus Flowchart[] flowcharts = GameObject.FindObjectsOfType(); foreach (Flowchart flowchart in flowcharts) { + // Have to set a unique localization id to export strings + if (flowchart.localizationId.Length == 0) + { + continue; + } + Block[] blocks = flowchart.GetComponentsInChildren(); foreach (Block block in blocks) { @@ -124,14 +130,14 @@ namespace Fungus System.Type type = command.GetType(); if (type == typeof(Say)) { - stringID = "SAY." + flowchart.name + "." + command.itemId; + stringID = "SAY." + flowchart.localizationId + "." + command.itemId; Say sayCommand = command as Say; standardText = sayCommand.storyText; description = sayCommand.description; } else if (type == typeof(Menu)) { - stringID = "MENU." + flowchart.name + "." + command.itemId; + stringID = "MENU." + flowchart.localizationId + "." + command.itemId; Menu menuCommand = command as Menu; standardText = menuCommand.text; description = menuCommand.description; @@ -233,7 +239,7 @@ namespace Fungus // Parse header row string[] columnNames = csvTable[0]; - if (columnNames.Length < 5) + if (columnNames.Length < 4) { // No languages defined in CSV file return; @@ -259,7 +265,7 @@ namespace Fungus Dictionary flowchartDict = new Dictionary(); foreach (Flowchart flowChart in GameObject.FindObjectsOfType()) { - flowchartDict[flowChart.name] = flowChart; + flowchartDict[flowChart.localizationId] = flowChart; } for (int i = 1; i < csvTable.Length; ++i) From 36274e134fbf744af173cbbe4ece3f634a156187 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Wed, 8 Apr 2015 22:01:39 +0100 Subject: [PATCH 09/30] Localise character names #8 --- Assets/Fungus/Flowchart/Scripts/Language.cs | 48 ++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 08b12743..70225e25 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -106,7 +106,16 @@ namespace Fungus protected Dictionary FindLanguageItems() { Dictionary languageItems = new Dictionary(); - + + // Export all character names + foreach (Character character in GameObject.FindObjectsOfType()) + { + LanguageItem languageItem = new LanguageItem(); + languageItem.standardText = character.nameText; + languageItem.description = character.description; + languageItems["CHARACTER." + character.nameText] = languageItem; + } + // Export all Say and Menu commands in the scene // To make it easier to localize, we preserve the command order in each exported block. Flowchart[] flowcharts = GameObject.FindObjectsOfType(); @@ -261,6 +270,13 @@ namespace Fungus return; } + // Cache a lookup table of characters in the scene + Dictionary characterDict = new Dictionary(); + foreach (Character character in GameObject.FindObjectsOfType()) + { + characterDict[character.nameText] = character; + } + // Cache a lookup table of flowcharts in the scene Dictionary flowchartDict = new Dictionary(); foreach (Flowchart flowChart in GameObject.FindObjectsOfType()) @@ -283,12 +299,15 @@ namespace Fungus if (languageEntry.Length > 0) { localizedStrings[stringId] = languageEntry; - PopulateGameString(stringId, languageEntry, flowchartDict); + PopulateGameString(stringId, languageEntry, flowchartDict, characterDict); } } } - public virtual void PopulateGameString(string stringId, string text, Dictionary flowchartDict) + public virtual void PopulateGameString(string stringId, + string localizedText, + Dictionary flowchartDict, + Dictionary characterDict) { string[] idParts = stringId.Split('.'); if (idParts.Length == 0) @@ -319,7 +338,7 @@ namespace Fungus { if (say.itemId == itemId) { - say.storyText = text; + say.storyText = localizedText; } } } @@ -346,11 +365,30 @@ namespace Fungus { if (menu.itemId == itemId) { - menu.text = text; + menu.text = localizedText; } } } } + else if (stringType == "CHARACTER") + { + if (idParts.Length != 2) + { + return; + } + + string characterName = idParts[1]; + if (!characterDict.ContainsKey(characterName)) + { + return; + } + + Character character = characterDict[characterName]; + if (character != null) + { + character.nameText = localizedText; + } + } } } From c94840384f0a08f44d48f7e7d5ebfdf03c5b442c Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 09:30:28 +0100 Subject: [PATCH 10/30] Renamed Export String to Export Localisation File --- Assets/Fungus/Flowchart/Editor/LanguageEditor.cs | 14 ++++++++------ Assets/Fungus/Flowchart/Scripts/Language.cs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index 16dc1a69..e735c81b 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -29,24 +29,26 @@ namespace Fungus EditorGUILayout.PropertyField(activeLanguageProp); EditorGUILayout.PropertyField(localizationFileProp); - if (GUILayout.Button(new GUIContent("Export to CSV"))) + if (GUILayout.Button(new GUIContent("Export Localization File"))) { - ExportStrings(t); + ExportLocalizationFile(t); } serializedObject.ApplyModifiedProperties(); } - public virtual void ExportStrings(Language language) + public virtual void ExportLocalizationFile(Language language) { string path = EditorUtility.SaveFilePanel("Export strings", "", - "strings.csv", ""); + "localization.csv", ""); if (path.Length == 0) { return; } - - string csvData = language.ExportCSV(); + + Debug.Log(path); + + string csvData = language.ExportLocalizationFile(); File.WriteAllText(path, csvData); } } diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 70225e25..9d4af892 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -48,7 +48,7 @@ namespace Fungus /** * Export all localized strings to an easy to edit CSV file. */ - public virtual string ExportCSV() + public virtual string ExportLocalizationFile() { // Collect all the language items present in the scene Dictionary languageItems = FindLanguageItems(); From 8daa859a777b282f16ca4ab8fddd66890d554822 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 10:07:26 +0100 Subject: [PATCH 11/30] Export all standard text to an easily editable text format #8 --- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 24 +++++- Assets/Fungus/Flowchart/Scripts/Language.cs | 83 +++++++++++++++---- 2 files changed, 85 insertions(+), 22 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index e735c81b..c9060f80 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -34,23 +34,39 @@ namespace Fungus ExportLocalizationFile(t); } + if (GUILayout.Button(new GUIContent("Export Standard Text"))) + { + ExportStandardText(t); + } + serializedObject.ApplyModifiedProperties(); } public virtual void ExportLocalizationFile(Language language) { - string path = EditorUtility.SaveFilePanel("Export strings", "", + string path = EditorUtility.SaveFilePanel("Export Localization File", "", "localization.csv", ""); if (path.Length == 0) { return; } - Debug.Log(path); - - string csvData = language.ExportLocalizationFile(); + string csvData = language.GetCSVData(); File.WriteAllText(path, csvData); } + + public virtual void ExportStandardText(Language language) + { + string path = EditorUtility.SaveFilePanel("Export Standard Text", "", + "standard.txt", ""); + if (path.Length == 0) + { + return; + } + + string textData = language.GetStandardText(); + File.WriteAllText(path, textData); + } } } diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 9d4af892..bfdccf33 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -46,9 +46,9 @@ namespace Fungus } /** - * Export all localized strings to an easy to edit CSV file. + * Convert all language items and localized strings to an easy to edit CSV format. */ - public virtual string ExportLocalizationFile() + public virtual string GetCSVData() { // Collect all the language items present in the scene Dictionary languageItems = FindLanguageItems(); @@ -57,7 +57,7 @@ namespace Fungus if (localizationFile != null && localizationFile.text.Length > 0) { - AddLocalisedStrings(languageItems, localizationFile.text); + AddLocalizedStrings(languageItems, localizationFile.text); } // Build CSV header row and a list of the language codes currently in use @@ -103,6 +103,9 @@ namespace Fungus return csvData; } + /** + * Buidls a dictionary of localizable objects in the scene. + */ protected Dictionary FindLanguageItems() { Dictionary languageItems = new Dictionary(); @@ -110,10 +113,12 @@ namespace Fungus // Export all character names foreach (Character character in GameObject.FindObjectsOfType()) { + // String id for character names is CHARACTER. LanguageItem languageItem = new LanguageItem(); languageItem.standardText = character.nameText; languageItem.description = character.description; - languageItems["CHARACTER." + character.nameText] = languageItem; + string stringId = "CHARACTER." + character.nameText; + languageItems[stringId] = languageItem; } // Export all Say and Menu commands in the scene @@ -132,24 +137,30 @@ namespace Fungus { foreach (Command command in block.commandList) { - string stringID = ""; + string stringId = ""; string standardText = ""; string description = ""; System.Type type = command.GetType(); if (type == typeof(Say)) { - stringID = "SAY." + flowchart.localizationId + "." + command.itemId; + // String id for Say commands is SAY... Say sayCommand = command as Say; standardText = sayCommand.storyText; description = sayCommand.description; + stringId = "SAY." + flowchart.localizationId + "." + sayCommand.itemId + "."; + if (sayCommand.character != null) + { + stringId += sayCommand.character.nameText; + } } else if (type == typeof(Menu)) { - stringID = "MENU." + flowchart.localizationId + "." + command.itemId; + // String id for Menu commands is MENU.. Menu menuCommand = command as Menu; standardText = menuCommand.text; description = menuCommand.description; + stringId = "MENU." + flowchart.localizationId + "." + menuCommand.itemId; } else { @@ -157,14 +168,14 @@ namespace Fungus } LanguageItem languageItem = null; - if (languageItems.ContainsKey(stringID)) + if (languageItems.ContainsKey(stringId)) { - languageItem = languageItems[stringID]; + languageItem = languageItems[stringId]; } else { languageItem = new LanguageItem(); - languageItems[stringID] = languageItem; + languageItems[stringId] = languageItem; } // Update basic properties,leaving localised strings intact @@ -177,7 +188,10 @@ namespace Fungus return languageItems; } - protected virtual void AddLocalisedStrings(Dictionary languageItems, string csvData) + /** + * Adds localized strings from CSV file data to a dictionary of language items in the scene. + */ + protected virtual void AddLocalizedStrings(Dictionary languageItems, string csvData) { CsvParser csvParser = new CsvParser(); string[][] csvTable = csvParser.Parse(csvData); @@ -226,6 +240,10 @@ namespace Fungus } } + /** + * Scan a localization CSV file and copies the strings for the specified language code + * into the text properties of the appropriate scene objects. + */ public virtual void SetActiveLanguage(string languageCode, string csvData) { if (!Application.isPlaying) @@ -299,15 +317,18 @@ namespace Fungus if (languageEntry.Length > 0) { localizedStrings[stringId] = languageEntry; - PopulateGameString(stringId, languageEntry, flowchartDict, characterDict); + PopulateTextProperty(stringId, languageEntry, flowchartDict, characterDict); } } } - public virtual void PopulateGameString(string stringId, - string localizedText, - Dictionary flowchartDict, - Dictionary characterDict) + /** + * Populates the text property of a single scene object with localized text. + */ + public virtual void PopulateTextProperty(string stringId, + string localizedText, + Dictionary flowchartDict, + Dictionary characterDict) { string[] idParts = stringId.Split('.'); if (idParts.Length == 0) @@ -318,11 +339,11 @@ namespace Fungus string stringType = idParts[0]; if (stringType == "SAY") { - if (idParts.Length != 3) + if (idParts.Length != 4) { return; } - + string flowchartId = idParts[1]; if (!flowchartDict.ContainsKey(flowchartId)) { @@ -390,6 +411,32 @@ namespace Fungus } } } + + /** + * Returns all standard text for SAY & MENU commands in the scene using an + * easy to edit custom text format. + */ + public virtual string GetStandardText() + { + // Collect all the language items present in the scene + Dictionary languageItems = FindLanguageItems(); + + string textData = ""; + foreach (string stringId in languageItems.Keys) + { + if (!stringId.StartsWith("SAY.") && !(stringId.StartsWith("MENU."))) + { + continue; + } + + LanguageItem languageItem = languageItems[stringId]; + + textData += "#" + stringId + "\n"; + textData += languageItem.standardText.Trim() + "\n\n"; + } + + return textData; + } } } \ No newline at end of file From 2cb88cc634bb65e8a6f820f2fba895aceacc3888 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 11:09:23 +0100 Subject: [PATCH 12/30] Import standard text file format #8 --- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 30 ++++++++--- Assets/Fungus/Flowchart/Scripts/Language.cs | 51 +++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index c9060f80..8afc0f41 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -24,19 +24,24 @@ namespace Fungus { serializedObject.Update(); - Language t = target as Language; + Language language = target as Language; EditorGUILayout.PropertyField(activeLanguageProp); EditorGUILayout.PropertyField(localizationFileProp); if (GUILayout.Button(new GUIContent("Export Localization File"))) { - ExportLocalizationFile(t); + ExportLocalizationFile(language); } if (GUILayout.Button(new GUIContent("Export Standard Text"))) { - ExportStandardText(t); + ExportStandardText(language); + } + + if (GUILayout.Button(new GUIContent("Import Standard Text"))) + { + ImportStandardText(language); } serializedObject.ApplyModifiedProperties(); @@ -44,7 +49,7 @@ namespace Fungus public virtual void ExportLocalizationFile(Language language) { - string path = EditorUtility.SaveFilePanel("Export Localization File", "", + string path = EditorUtility.SaveFilePanel("Export Localization File", "Assets/", "localization.csv", ""); if (path.Length == 0) { @@ -53,12 +58,12 @@ namespace Fungus string csvData = language.GetCSVData(); File.WriteAllText(path, csvData); + AssetDatabase.Refresh(); } public virtual void ExportStandardText(Language language) { - string path = EditorUtility.SaveFilePanel("Export Standard Text", "", - "standard.txt", ""); + string path = EditorUtility.SaveFilePanel("Export Standard Text", "Assets/", "standard.txt", ""); if (path.Length == 0) { return; @@ -66,6 +71,19 @@ namespace Fungus string textData = language.GetStandardText(); File.WriteAllText(path, textData); + AssetDatabase.Refresh(); + } + + public virtual void ImportStandardText(Language language) + { + string path = EditorUtility.OpenFilePanel("Import Standard Text", "Assets/", "txt"); + if (path.Length == 0) + { + return; + } + + string textData = File.ReadAllText(path); + language.SetStandardText(textData); } } diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index bfdccf33..5062c5f5 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -437,6 +437,57 @@ namespace Fungus return textData; } + + /** + * Sets standard text on scene objects by parsing a text data file. + */ + public virtual void SetStandardText(string textData) + { + // Cache a lookup table of characters in the scene + Dictionary characterDict = new Dictionary(); + foreach (Character character in GameObject.FindObjectsOfType()) + { + characterDict[character.nameText] = character; + } + + // Cache a lookup table of flowcharts in the scene + Dictionary flowchartDict = new Dictionary(); + foreach (Flowchart flowChart in GameObject.FindObjectsOfType()) + { + flowchartDict[flowChart.localizationId] = flowChart; + } + + string[] lines = textData.Split('\n'); + + string stringId = ""; + string buffer = ""; + foreach (string line in lines) + { + // Check for string id line + if (line.StartsWith("#")) + { + if (stringId.Length > 0) + { + // Write buffered text to the appropriate text property + PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict); + } + + // Set the string id for the follow text lines + stringId = line.Substring(1, line.Length - 1); + buffer = ""; + } + else + { + buffer += line; + } + } + + // Handle last buffered entry + if (stringId.Length > 0) + { + PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict); + } + } } } \ No newline at end of file From 1d99ed5cb973c9623ce659cdc757ced190698ae0 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 11:09:56 +0100 Subject: [PATCH 13/30] Export unquoted CSV fields when possible #8 --- Assets/Fungus/Flowchart/Scripts/CSVSupport.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs index 95921102..ef964fde 100644 --- a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs +++ b/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs @@ -19,8 +19,8 @@ namespace Fungus if ( s.Contains( QUOTE ) ) s = s.Replace( QUOTE, ESCAPED_QUOTE ); - //if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 ) - s = QUOTE + s + QUOTE; + if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 ) + s = QUOTE + s + QUOTE; return s; } @@ -42,7 +42,7 @@ namespace Fungus private const string QUOTE = "\""; private const string ESCAPED_QUOTE = "\"\""; - // private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' }; + private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' }; } } From d86ea2e7d2810dae51271ff76afbe63d72c072dc Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 11:40:54 +0100 Subject: [PATCH 14/30] Added log info for number of exported/imported items #8 --- Assets/Fungus/Flowchart/Scripts/Language.cs | 64 +++++++++++++++------ 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 5062c5f5..4c9e601a 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -76,6 +76,7 @@ namespace Fungus } // Build the CSV file using collected language items + int rowCount = 0; string csvData = csvHeader + "\n"; foreach (string stringId in languageItems.Keys) { @@ -98,8 +99,11 @@ namespace Fungus } csvData += row + "\n"; + rowCount++; } + Debug.Log("Exported " + rowCount + " localization text items."); + return csvData; } @@ -323,31 +327,31 @@ namespace Fungus } /** - * Populates the text property of a single scene object with localized text. + * Populates the text property of a single scene object with a new text value. */ - public virtual void PopulateTextProperty(string stringId, - string localizedText, + public virtual bool PopulateTextProperty(string stringId, + string newText, Dictionary flowchartDict, Dictionary characterDict) { string[] idParts = stringId.Split('.'); if (idParts.Length == 0) { - return; + return false; } - + string stringType = idParts[0]; if (stringType == "SAY") { if (idParts.Length != 4) { - return; + return false; } string flowchartId = idParts[1]; if (!flowchartDict.ContainsKey(flowchartId)) { - return; + return false; } Flowchart flowchart = flowchartDict[flowchartId]; @@ -357,9 +361,11 @@ namespace Fungus { foreach (Say say in flowchart.GetComponentsInChildren()) { - if (say.itemId == itemId) + if (say.itemId == itemId && + say.storyText != newText) { - say.storyText = localizedText; + say.storyText = newText; + return true; } } } @@ -368,13 +374,13 @@ namespace Fungus { if (idParts.Length != 3) { - return; + return false; } string flowchartId = idParts[1]; if (!flowchartDict.ContainsKey(flowchartId)) { - return; + return false; } Flowchart flowchart = flowchartDict[flowchartId]; @@ -384,9 +390,11 @@ namespace Fungus { foreach (Menu menu in flowchart.GetComponentsInChildren()) { - if (menu.itemId == itemId) + if (menu.itemId == itemId && + menu.text != newText) { - menu.text = localizedText; + menu.text = newText; + return true; } } } @@ -395,21 +403,25 @@ namespace Fungus { if (idParts.Length != 2) { - return; + return false; } string characterName = idParts[1]; if (!characterDict.ContainsKey(characterName)) { - return; + return false; } Character character = characterDict[characterName]; - if (character != null) + if (character != null && + character.nameText != newText) { - character.nameText = localizedText; + character.nameText = newText; + return true; } } + + return false; } /** @@ -422,6 +434,7 @@ namespace Fungus Dictionary languageItems = FindLanguageItems(); string textData = ""; + int rowCount = 0; foreach (string stringId in languageItems.Keys) { if (!stringId.StartsWith("SAY.") && !(stringId.StartsWith("MENU."))) @@ -433,8 +446,11 @@ namespace Fungus textData += "#" + stringId + "\n"; textData += languageItem.standardText.Trim() + "\n\n"; + rowCount++; } + Debug.Log("Exported " + rowCount + " standard text items."); + return textData; } @@ -459,6 +475,8 @@ namespace Fungus string[] lines = textData.Split('\n'); + int updatedCount = 0; + string stringId = ""; string buffer = ""; foreach (string line in lines) @@ -469,7 +487,10 @@ namespace Fungus if (stringId.Length > 0) { // Write buffered text to the appropriate text property - PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict); + if (PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict)) + { + updatedCount++; + } } // Set the string id for the follow text lines @@ -485,8 +506,13 @@ namespace Fungus // Handle last buffered entry if (stringId.Length > 0) { - PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict); + if (PopulateTextProperty(stringId, buffer.Trim(), flowchartDict, characterDict)) + { + updatedCount++; + } } + + Debug.Log("Updated " + updatedCount + " standard text items."); } } From 8ebc4efe294408d7e2ed40a90495507136fa0ace Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:12:23 +0100 Subject: [PATCH 15/30] Add undo support on import. Use notifications instead of logging. #8 --- .../Fungus/Flowchart/Editor/LanguageEditor.cs | 20 ++++++++++++-- Assets/Fungus/Flowchart/Scripts/Language.cs | 27 ++++++++++++++++--- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs index 8afc0f41..885ec7b5 100644 --- a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs @@ -59,6 +59,8 @@ namespace Fungus string csvData = language.GetCSVData(); File.WriteAllText(path, csvData); AssetDatabase.Refresh(); + + ShowNotification(language); } public virtual void ExportStandardText(Language language) @@ -72,8 +74,10 @@ namespace Fungus string textData = language.GetStandardText(); File.WriteAllText(path, textData); AssetDatabase.Refresh(); - } + ShowNotification(language); + } + public virtual void ImportStandardText(Language language) { string path = EditorUtility.OpenFilePanel("Import Standard Text", "Assets/", "txt"); @@ -83,7 +87,19 @@ namespace Fungus } string textData = File.ReadAllText(path); - language.SetStandardText(textData); + language.SetStandardText(textData); + + ShowNotification(language); + } + + protected virtual void ShowNotification(Language language) + { + EditorWindow window = EditorWindow.GetWindow(typeof(FlowchartWindow), false, "Flowchart"); + if (window != null) + { + window.ShowNotification(new GUIContent(language.notificationText)); + language.notificationText = ""; + } } } diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Flowchart/Scripts/Language.cs index 4c9e601a..940f2299 100644 --- a/Assets/Fungus/Flowchart/Scripts/Language.cs +++ b/Assets/Fungus/Flowchart/Scripts/Language.cs @@ -1,4 +1,7 @@ using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +#endif using System; using System.Collections; using System.Collections.Generic; @@ -35,6 +38,12 @@ namespace Fungus */ public TextAsset localizationFile; + /** + * Stores any notification message from export / import methods. + */ + [NonSerialized] + public string notificationText = ""; + public virtual void Start() { if (activeLanguage.Length > 0 && @@ -102,7 +111,7 @@ namespace Fungus rowCount++; } - Debug.Log("Exported " + rowCount + " localization text items."); + notificationText = "Exported " + rowCount + " localization text items."; return csvData; } @@ -364,6 +373,10 @@ namespace Fungus if (say.itemId == itemId && say.storyText != newText) { + #if UNITY_EDITOR + Undo.RecordObject(say, "Set Text"); + #endif + say.storyText = newText; return true; } @@ -393,6 +406,10 @@ namespace Fungus if (menu.itemId == itemId && menu.text != newText) { + #if UNITY_EDITOR + Undo.RecordObject(menu, "Set Text"); + #endif + menu.text = newText; return true; } @@ -416,6 +433,10 @@ namespace Fungus if (character != null && character.nameText != newText) { + #if UNITY_EDITOR + Undo.RecordObject(character, "Set Text"); + #endif + character.nameText = newText; return true; } @@ -449,7 +470,7 @@ namespace Fungus rowCount++; } - Debug.Log("Exported " + rowCount + " standard text items."); + notificationText = "Exported " + rowCount + " standard text items."; return textData; } @@ -512,7 +533,7 @@ namespace Fungus } } - Debug.Log("Updated " + updatedCount + " standard text items."); + notificationText = "Updated " + updatedCount + " standard text items."; } } From df4296eb808ace90b27aac2e8b2b6c290f5da49a Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:17:52 +0100 Subject: [PATCH 16/30] Removed FountainExporter & StringsParser classes #8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We’ve decided against using the Fountain format for text import / export as it’s too easy for users to incorrectly format the text. --- .../Flowchart/Editor/FlowchartEditor.cs | 8 - .../Flowchart/Editor/FountainExporter.cs | 187 ------------------ .../Fungus/Flowchart/Scripts/StringsParser.cs | 96 --------- .../Flowchart/Scripts/StringsParser.cs.meta | 8 - 4 files changed, 299 deletions(-) delete mode 100644 Assets/Fungus/Flowchart/Editor/FountainExporter.cs delete mode 100644 Assets/Fungus/Flowchart/Scripts/StringsParser.cs delete mode 100644 Assets/Fungus/Flowchart/Scripts/StringsParser.cs.meta diff --git a/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs b/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs index ccd4b8a2..5e671054 100644 --- a/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs +++ b/Assets/Fungus/Flowchart/Editor/FlowchartEditor.cs @@ -58,14 +58,6 @@ namespace Fungus { EditorWindow.GetWindow(typeof(FlowchartWindow), false, "Flowchart"); } - if (GUILayout.Button(new GUIContent("Export Text", "Export all story text in .fountain format."))) - { - FountainExporter.ExportStrings(flowchart); - } - if (GUILayout.Button(new GUIContent("Import Text", "Import story text from a file in .fountain format."))) - { - FountainExporter.ImportStrings(flowchart); - } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); diff --git a/Assets/Fungus/Flowchart/Editor/FountainExporter.cs b/Assets/Fungus/Flowchart/Editor/FountainExporter.cs deleted file mode 100644 index e45fd6b7..00000000 --- a/Assets/Fungus/Flowchart/Editor/FountainExporter.cs +++ /dev/null @@ -1,187 +0,0 @@ -using UnityEditor; -using UnityEngine; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.IO; - -namespace Fungus -{ - - /** - * Import and export a Fungus story in the .fountain screenplay format. - * The exported file contains special tags in note blocks which map the - * story text to the corresponding commands. - */ - public class FountainExporter - { - - public static void ExportStrings(Flowchart flowchart) - { - if (flowchart == null) - { - return; - } - - string path = EditorUtility.SaveFilePanel("Export strings", "", - flowchart.name + ".txt", ""); - - if(path.Length == 0) - { - return; - } - - // Write out character names - - string exportText = "Title: " + flowchart.name + "\n"; - exportText += "Draft date: " + System.DateTime.Today.ToString("d") + "\n"; - exportText += "\n"; - - // In every block, write out Say & Menu text in order - Block[] blocks = flowchart.GetComponentsInChildren(); - foreach (Block block in blocks) - { - // Check for any Say, Menu or Comment commands - bool hasText = false; - foreach (Command c in block.commandList) - { - System.Type t = c.GetType(); - if (t == typeof(Say) || - t == typeof(Menu) || - t == typeof(Comment)) - { - hasText = true; - } - } - if (!hasText) - { - continue; - } - - exportText += "." + block.blockName.ToUpper() + "\n\n"; - - foreach (Command c in block.commandList) - { - if (c.GetType() == typeof(Say)) - { - string idText = ""; - Say say = c as Say; - - if (say.character == null) - { - exportText += "NO CHARACTER\n"; - } - else - { - exportText += say.character.nameText.ToUpper() + "\n"; - } - - idText += "[[Say," + c.itemId + "]]\n"; - - exportText += idText; - - // Fountain requires blank dialogue lines to contain 2 spaces or else - // they will be interpreted as ACTION text. - string trimmedText = say.storyText.Trim(); - string[] lines = trimmedText.Split(new [] { '\r', '\n' }); - foreach (string line in lines) - { - string trimmed = line.Trim(); - if (line.Length == 0) - { - exportText += " \n"; - } - else - { - exportText += trimmed + "\n"; - } - } - - exportText += "\n"; - } - else if (c.GetType() == typeof(Menu)) - { - exportText += "MENU\n"; - - string idText = ""; - Menu menu = c as Menu; - idText += "[[Menu," + c.itemId + "]]\n"; - - exportText += idText + menu.text.Trim() + "\n\n"; - } - else if (c.GetType() == typeof(Comment)) - { - string idText = ""; - Comment comment = c as Comment; - idText += "[[Comment," + c.itemId + "]]\n"; - - exportText += idText + comment.commentText.Trim() + "\n\n"; - } - } - } - - File.WriteAllText(path, exportText); - } - - public static void ImportStrings(Flowchart flowchart) - { - string path = EditorUtility.OpenFilePanel("Import strings", "", ""); - - if(path.Length == 0) - { - return; - } - - string stringsFile = File.ReadAllText(path); - - StringsParser parser = new StringsParser(); - List items = parser.ProcessText(stringsFile); - - // Build dict of commands - Dictionary commandDict = new Dictionary(); - foreach (Command c in flowchart.gameObject.GetComponentsInChildren()) - { - commandDict.Add (c.itemId, c); - } - - foreach (StringsParser.StringItem item in items) - { - if (item.parameters.Length != 2) - { - continue; - } - - string stringType = item.parameters[0]; - if (stringType == "Say") - { - int itemId = int.Parse(item.parameters[1]); - Say sayCommand = commandDict[itemId] as Say; - if (sayCommand != null) - { - sayCommand.storyText = item.bodyText; - } - } - else if (stringType == "Menu") - { - int itemId = int.Parse(item.parameters[1]); - Menu menuCommand = commandDict[itemId] as Menu; - if (menuCommand != null) - { - menuCommand.text = item.bodyText; - } - } - else if (stringType == "Comment") - { - int itemId = int.Parse(item.parameters[1]); - Comment commentCommand = commandDict[itemId] as Comment; - if (commentCommand != null) - { - commentCommand.commentText = item.bodyText; - } - } - } - } - } - -} diff --git a/Assets/Fungus/Flowchart/Scripts/StringsParser.cs b/Assets/Fungus/Flowchart/Scripts/StringsParser.cs deleted file mode 100644 index 9dce7ea9..00000000 --- a/Assets/Fungus/Flowchart/Scripts/StringsParser.cs +++ /dev/null @@ -1,96 +0,0 @@ -using UnityEngine; -using System.Collections; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Fungus; - -namespace Fungus -{ - /** - * Parses an exported strings file using the Fountain file format for screenplays - * See http://fountain.io for details. - * We only support a small subset of Fountain markup, and use note tags to embed meta data to - * bind dialogue text to the corresponding Say / Menu commands. - */ - public class StringsParser - { - public class StringItem - { - public string[] parameters; - public string bodyText; - } - - public virtual List ProcessText(string text) - { - List items = new List(); - - // Split text into lines. Add a newline at end to ensure last command is always parsed - string[] lines = Regex.Split(text + "\n", "(?<=\n)"); - - int i = 0; - while (i < lines.Length) - { - string line = lines[i].Trim(); - - if (!(line.StartsWith("[[") && line.EndsWith("]]"))) - { - i++; - continue; - } - - string blockTag = line.Substring(2, line.Length - 4); - - // Find next empty line, #, [[ or eof - int start = i + 1; - int end = lines.Length - 1; - for (int j = start; j <= end; ++j) - { - string line2 = lines[j].Trim(); - - if (line2.Length == 0 || - line2.StartsWith("#") || - line2.StartsWith("[[")) - { - end = j; - break; - } - } - - if (end > start) - { - string blockBuffer = ""; - for (int j = start; j <= end; ++j) - { - blockBuffer += lines[j].Trim() + "\n"; - } - - blockBuffer = blockBuffer.Trim(); - - StringItem item = CreateItem(blockTag, blockBuffer); - if (item != null) - { - items.Add(item); - } - } - - i = end + 1; - } - - return items; - } - - protected StringItem CreateItem(string commandInfo, string bodyText) - { - string[] parameters = commandInfo.Split(new char[] { ',' }); - if (parameters.Length > 0) - { - StringItem item = new StringItem(); - item.parameters = parameters; - item.bodyText = bodyText; - return item; - } - - return null; - } - } -} diff --git a/Assets/Fungus/Flowchart/Scripts/StringsParser.cs.meta b/Assets/Fungus/Flowchart/Scripts/StringsParser.cs.meta deleted file mode 100644 index 03e7f056..00000000 --- a/Assets/Fungus/Flowchart/Scripts/StringsParser.cs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0f02aedc631824200a4abe95774a44f5 -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: From d1645bad00877bc8fd860a05186c817383ed5a09 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:49:01 +0100 Subject: [PATCH 17/30] Removed meta file for FountainExporter.cs #8 --- .../Fungus/Flowchart/Editor/FountainExporter.cs.meta | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 Assets/Fungus/Flowchart/Editor/FountainExporter.cs.meta diff --git a/Assets/Fungus/Flowchart/Editor/FountainExporter.cs.meta b/Assets/Fungus/Flowchart/Editor/FountainExporter.cs.meta deleted file mode 100644 index e54b9dc3..00000000 --- a/Assets/Fungus/Flowchart/Editor/FountainExporter.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: c91ad6ef6a0734046bd93dde4b0e59d1 -timeCreated: 1426502899 -licenseType: Free -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From eda91e066102d178d0efb1f40c75fdaab9c5f0dd Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:49:40 +0100 Subject: [PATCH 18/30] Removed old strings.csv file #8 --- Assets/strings.csv | 32 -------------------------------- Assets/strings.csv.meta | 8 -------- 2 files changed, 40 deletions(-) delete mode 100644 Assets/strings.csv delete mode 100644 Assets/strings.csv.meta diff --git a/Assets/strings.csv b/Assets/strings.csv deleted file mode 100644 index 4d3c1a21..00000000 --- a/Assets/strings.csv +++ /dev/null @@ -1,32 +0,0 @@ -"Key","Timestamp","Description","Standard","FR","DE","ES" -"SAY.Flowchart.75","10/10/2015","Note","{t}(Do I really want to do this?){/t} Zero","One","Two","Three" -"MENU.Flowchart.76","10/10/2015","Note","Drink the coffee","Five","Six","Seven" -"MENU.Flowchart.77","10/10/2015","Note","Don't drink the coffee",,, -"SAY.Flowchart.0","10/10/2015","Note","{answer}Excellent.",,, -"SAY.Flowchart.1","10/10/2015","Note","All right. It's been 30 minutes. How do you feel?",,, -"SAY.Flowchart.20","10/10/2015","Note","{worried}Like an idiot who should stop encouraging you.",,, -"SAY.Flowchart.21","10/10/2015","Note","No, that's not right.",,, -"SAY.Flowchart.45","10/10/2015","Note","{shout}No nausea? {shout}Dizziness? {shout}Feeling of sudden and impending doom?",,, -"SAY.Flowchart.22","10/10/2015","Note","Wait, {question}{flash=0.1}what?",,, -"SAY.Flowchart.23","10/10/2015","Note","Hmm... I'll have to revise my {clue}hypothesis…",,, -"SAY.Flowchart.2","10/10/2015","Note","No thanks. The last time I drank your coffee, I spent the day running from an imaginary dog.",,, -"SAY.Flowchart.3","10/10/2015","Note","The hallucinogen was in the {answer}gas, not the coffee.",,, -"SAY.Flowchart.4","10/10/2015","Note","{shout}Still not ok{wp},{/wp} Sherlock!",,, -"SAY.Flowchart.5","10/10/2015","Note","Suit yourself.",,, -"SAY.Flowchart.6","10/10/2015","Note","THE EXPERIMENT œ˙é®√","Non","Nein","No" -"SAY.Flowchart.58","10/10/2015","Note","Ah John,\n {pleased}there you are.\nI've been looking everywhere for you!","Mon frere","Mein frere","Bonjo" -"SAY.Flowchart.7","10/10/2015","Note","{confused}I do live here, you know.",,, -"SAY.Flowchart.8","10/10/2015","Note","{answer}{flash=0.1}Well you arrived at just the right time.",,, -"SAY.Flowchart.30","10/10/2015","Note"," Here, I need you to drink this.",,, -"SAY.Flowchart.9","10/10/2015","Note","{worried}... Why?",,, -"SAY.Flowchart.10","10/10/2015","Note","It's for an experiment.",,, -"SAY.Flowchart.35","10/10/2015","Note"," Don't worry. It won't kill you.",,, -"SAY.Flowchart.11","10/10/2015","Note","{clue}Your words inspire such confidence.",,, -"SAY.Flowchart.12","10/10/2015","Note","Why don't you test it yourself?",,, -"SAY.Flowchart.13","10/10/2015","Note","{question}I can't observe the effects of the experiment if I'm the one participating.",,, -"SAY.Flowchart.74","10/10/2015","Note","Of course.",,, -"SAY.Flowchart.80","10/10/2015","Note","(What should I do now?)",,, -"MENU.Flowchart.78","10/10/2015","Note","Talk to Sherlock.",,, -"MENU.Flowchart.79","10/10/2015","Note","Leave",,, -"SAY.Flowchart.66","10/10/2015","Note","Right.... Good luck with that.",,, -"SAY.Flowchart.70","10/10/2015","Note","Your {stat-up}courage{/stat-up} has increased!",,, diff --git a/Assets/strings.csv.meta b/Assets/strings.csv.meta deleted file mode 100644 index 3e1be37a..00000000 --- a/Assets/strings.csv.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eb17c0268d57044eb92109b71e847180 -timeCreated: 1428075678 -licenseType: Free -TextScriptImporter: - userData: - assetBundleName: - assetBundleVariant: From 1f2b0deecdba6f896dd2879986cdac8fa254b327 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:50:41 +0100 Subject: [PATCH 19/30] Updated serialisation names for scene objects --- .../Sherlock/TheExperiment.unity | 281 ++++++++++-------- 1 file changed, 161 insertions(+), 120 deletions(-) diff --git a/Assets/FungusExamples/Sherlock/TheExperiment.unity b/Assets/FungusExamples/Sherlock/TheExperiment.unity index 340ea564..2805b6e6 100644 --- a/Assets/FungusExamples/Sherlock/TheExperiment.unity +++ b/Assets/FungusExamples/Sherlock/TheExperiment.unity @@ -562,7 +562,7 @@ MonoBehaviour: - {fileID: 21300000, guid: 58f5b79d262f6814bb4ebb44e29efe90, type: 3} - {fileID: 21300000, guid: 84cdbfde1b7d4c24ab7071894480d5db, type: 3} portraitsFace: 1 - notes: + description: --- !u!1 &170680003 GameObject: m_ObjectHideFlags: 0 @@ -3181,10 +3181,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 050fb9e6e72f442b3b883da8a965bdeb, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 73 + itemId: 73 errorMessage: indentLevel: 0 - targetSequence: {fileID: 1390555371} + targetBlock: {fileID: 1390555371} --- !u!114 &1390555292 MonoBehaviour: m_ObjectHideFlags: 2 @@ -3196,11 +3196,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 841589fc622bc494aa5405f416fa1301, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 77 + itemId: 77 errorMessage: indentLevel: 0 text: Don't drink the coffee - targetSequence: {fileID: 1390555302} + description: + targetBlock: {fileID: 1390555302} hideIfVisited: 0 setMenuDialog: {fileID: 0} --- !u!114 &1390555293 @@ -3215,7 +3216,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d2f6487d21a03404cb21b245f0242e79, type: 3} m_Name: m_EditorClassIdentifier: - parentSequence: {fileID: 0} + parentBlock: {fileID: 0} --- !u!114 &1390555294 MonoBehaviour: m_ObjectHideFlags: 2 @@ -3227,11 +3228,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 841589fc622bc494aa5405f416fa1301, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 76 + itemId: 76 errorMessage: indentLevel: 0 text: Drink the coffee - targetSequence: {fileID: 1390555312} + description: + targetBlock: {fileID: 1390555312} hideIfVisited: 0 setMenuDialog: {fileID: 0} --- !u!114 &1390555295 @@ -3249,7 +3251,7 @@ MonoBehaviour: scrollPos: {x: 2878.33252, y: 1016.83801} variablesScrollPos: {x: 0, y: 0} variablesExpanded: 1 - sequenceViewHeight: 411 + blockViewHeight: 400 zoom: 1 scrollViewRect: serializedVersion: 2 @@ -3257,7 +3259,7 @@ MonoBehaviour: y: -1729.35046 width: 5969.4458 height: 2818.85034 - selectedSequence: {fileID: 1390555371} + selectedBlock: {fileID: 1390555371} selectedCommands: - {fileID: 1390555358} variables: @@ -3267,7 +3269,8 @@ MonoBehaviour: colorCommands: 1 hideComponents: 1 saveSelection: 1 - nextCommandId: 93 + localizationId: + nextItemId: 102 --- !u!4 &1390555296 Transform: m_ObjectHideFlags: 0 @@ -3292,10 +3295,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 30 + itemId: 30 errorMessage: indentLevel: 0 storyText: ' Here, I need you to drink this.' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3324,7 +3328,8 @@ MonoBehaviour: y: -1082.83801 width: 120 height: 40 - sequenceName: START + itemId: 96 + blockName: START description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -3367,7 +3372,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 64 + itemId: 64 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -3397,10 +3402,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 75 + itemId: 75 errorMessage: indentLevel: 0 storyText: '{t}(Do I really want to do this?){/t}' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3422,11 +3428,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 841589fc622bc494aa5405f416fa1301, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 79 + itemId: 79 errorMessage: indentLevel: 0 text: Leave - targetSequence: {fileID: 1390555362} + description: + targetBlock: {fileID: 1390555362} hideIfVisited: 0 setMenuDialog: {fileID: 0} --- !u!114 &1390555302 @@ -3447,7 +3454,8 @@ MonoBehaviour: y: -947.838013 width: 120 height: 40 - sequenceName: Don't Drink + itemId: 95 + blockName: Don't Drink description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -3473,10 +3481,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 050fb9e6e72f442b3b883da8a965bdeb, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 17 + itemId: 17 errorMessage: indentLevel: 0 - targetSequence: {fileID: 1390555304} + targetBlock: {fileID: 1390555304} --- !u!114 &1390555304 MonoBehaviour: m_ObjectHideFlags: 2 @@ -3495,7 +3503,8 @@ MonoBehaviour: y: -879.838013 width: 120 height: 40 - sequenceName: What now? + itemId: 98 + blockName: What now? description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -3516,11 +3525,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 841589fc622bc494aa5405f416fa1301, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 78 + itemId: 78 errorMessage: indentLevel: 0 text: Talk to Sherlock. - targetSequence: {fileID: 1390555308} + description: + targetBlock: {fileID: 1390555308} hideIfVisited: 0 setMenuDialog: {fileID: 0} --- !u!114 &1390555306 @@ -3534,10 +3544,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 80 + itemId: 80 errorMessage: indentLevel: 0 storyText: (What should I do now?) + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3565,7 +3576,8 @@ MonoBehaviour: y: -1152.83801 width: 120 height: 40 - sequenceName: Splash + itemId: 101 + blockName: Splash description: runSlowInEditor: 0 eventHandler: {fileID: 1390555325} @@ -3599,7 +3611,8 @@ MonoBehaviour: y: -800.838013 width: 135 height: 40 - sequenceName: Talk to Sherlock + itemId: 97 + blockName: Talk to Sherlock description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -3620,7 +3633,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d1dc785fd3508440db335f3b5654c96c, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 15 + itemId: 15 errorMessage: indentLevel: 0 chooseText: '{t}Changed your mind?{/t}' @@ -3641,7 +3654,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9a61ea20fbb744ca2a363c33ad65cd89, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 16 + itemId: 16 errorMessage: indentLevel: 0 variable: {fileID: 0} @@ -3659,7 +3672,7 @@ MonoBehaviour: stringRef: {fileID: 0} stringVal: optionText: No - targetSequence: {fileID: 1390555304} + targetBlock: {fileID: 1390555304} hideOnSelected: 0 --- !u!114 &1390555311 MonoBehaviour: @@ -3673,7 +3686,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9a61ea20fbb744ca2a363c33ad65cd89, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 14 + itemId: 14 errorMessage: indentLevel: 0 variable: {fileID: 0} @@ -3691,7 +3704,7 @@ MonoBehaviour: stringRef: {fileID: 0} stringVal: optionText: Yes - targetSequence: {fileID: 1390555312} + targetBlock: {fileID: 1390555312} hideOnSelected: 0 --- !u!114 &1390555312 MonoBehaviour: @@ -3711,7 +3724,8 @@ MonoBehaviour: y: -951.838013 width: 120 height: 40 - sequenceName: Drink + itemId: 94 + blockName: Drink description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -3750,10 +3764,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 23 + itemId: 23 errorMessage: indentLevel: 0 storyText: "Hmm... I'll have to revise my {clue}hypothesis\u2026" + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3776,10 +3791,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 22 + itemId: 22 errorMessage: indentLevel: 0 storyText: Wait, {question}{flash=0.1}what? + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3802,10 +3818,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 21 + itemId: 21 errorMessage: indentLevel: 0 storyText: No, that's not right. + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3828,10 +3845,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 20 + itemId: 20 errorMessage: indentLevel: 0 storyText: '{worried}Like an idiot who should stop encouraging you.' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3854,10 +3872,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 1 + itemId: 1 errorMessage: indentLevel: 0 storyText: All right. It's been 30 minutes. How do you feel? + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3880,7 +3899,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 207aecf668a0345388087ccf522f9957, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 19 + itemId: 19 errorMessage: indentLevel: 0 duration: 1 @@ -3900,7 +3919,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 207aecf668a0345388087ccf522f9957, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 18 + itemId: 18 errorMessage: indentLevel: 0 duration: 1 @@ -3920,10 +3939,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 0 + itemId: 0 errorMessage: indentLevel: 0 storyText: '{answer}Excellent.' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3946,10 +3966,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 5 + itemId: 5 errorMessage: indentLevel: 0 storyText: Suit yourself. + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3972,10 +3993,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 4 + itemId: 4 errorMessage: indentLevel: 0 storyText: '{shout}Still not ok{wp},{/wp} Sherlock!' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -3998,10 +4020,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 3 + itemId: 3 errorMessage: indentLevel: 0 storyText: The hallucinogen was in the {answer}gas, not the coffee. + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4024,11 +4047,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 2 + itemId: 2 errorMessage: indentLevel: 0 storyText: No thanks. The last time I drank your coffee, I spent the day running from an imaginary dog. + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4050,7 +4074,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d2f6487d21a03404cb21b245f0242e79, type: 3} m_Name: m_EditorClassIdentifier: - parentSequence: {fileID: 1390555307} + parentBlock: {fileID: 1390555307} --- !u!114 &1390555326 MonoBehaviour: m_ObjectHideFlags: 2 @@ -4062,10 +4086,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 74 + itemId: 74 errorMessage: indentLevel: 0 storyText: Of course. + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4088,10 +4113,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 12 + itemId: 12 errorMessage: indentLevel: 0 storyText: Why don't you test it yourself? + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4114,10 +4140,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 11 + itemId: 11 errorMessage: indentLevel: 0 storyText: '{clue}Your words inspire such confidence.' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4140,10 +4167,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 10 + itemId: 10 errorMessage: indentLevel: 0 storyText: It's for an experiment. + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4166,10 +4194,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 9 + itemId: 9 errorMessage: indentLevel: 0 storyText: '{worried}... Why?' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4192,10 +4221,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 8 + itemId: 8 errorMessage: indentLevel: 0 storyText: '{answer}{flash=0.1}Well you arrived at just the right time.' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4218,10 +4248,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 7 + itemId: 7 errorMessage: indentLevel: 0 storyText: '{confused}I do live here, you know.' + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4244,11 +4275,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 13 + itemId: 13 errorMessage: indentLevel: 0 storyText: '{question}I can''t observe the effects of the experiment if I''m the one participating.' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4271,10 +4303,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 6 + itemId: 6 errorMessage: indentLevel: 0 storyText: THE EXPERIMENT + description: character: {fileID: 0} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4296,10 +4329,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 050fb9e6e72f442b3b883da8a965bdeb, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 86 + itemId: 86 errorMessage: indentLevel: 0 - targetSequence: {fileID: 1390555298} + targetBlock: {fileID: 1390555298} --- !u!114 &1390555336 MonoBehaviour: m_ObjectHideFlags: 2 @@ -4312,10 +4345,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 050fb9e6e72f442b3b883da8a965bdeb, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 24 + itemId: 24 errorMessage: indentLevel: 0 - targetSequence: {fileID: 1390555440} + targetBlock: {fileID: 1390555440} --- !u!114 &1390555337 MonoBehaviour: m_ObjectHideFlags: 2 @@ -4328,7 +4361,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 29 + itemId: 29 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4359,7 +4392,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 28 + itemId: 28 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4390,7 +4423,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 33 + itemId: 33 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 1789234734} @@ -4409,7 +4442,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 32 + itemId: 32 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 1789234734} @@ -4428,7 +4461,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 31 + itemId: 31 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4459,7 +4492,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 27 + itemId: 27 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4490,7 +4523,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 26 + itemId: 26 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4520,7 +4553,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 72 + itemId: 72 errorMessage: indentLevel: 0 control: 2 @@ -4541,7 +4574,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 25 + itemId: 25 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4572,7 +4605,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 40 + itemId: 40 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4603,7 +4636,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 39 + itemId: 39 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4634,7 +4667,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 37 + itemId: 37 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4665,7 +4698,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 38 + itemId: 38 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4696,10 +4729,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 35 + itemId: 35 errorMessage: indentLevel: 0 storyText: ' Don''t worry. It won''t kill you.' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4722,7 +4756,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 36 + itemId: 36 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4753,7 +4787,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 34 + itemId: 34 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4783,7 +4817,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 63 + itemId: 63 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4813,7 +4847,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 65 + itemId: 65 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4843,10 +4877,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 66 + itemId: 66 errorMessage: indentLevel: 0 storyText: Right.... Good luck with that. + description: character: {fileID: 1880195408} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -4868,7 +4903,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 67 + itemId: 67 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -4898,7 +4933,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 85 + itemId: 85 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 1612042692} @@ -4916,7 +4951,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: fb77d0ce495044f6e9feb91b31798e8c, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 92 + itemId: 92 errorMessage: indentLevel: 0 variable: {fileID: 1390555396} @@ -4944,7 +4979,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 84 + itemId: 84 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 884427801} @@ -4962,7 +4997,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3315ad2ebb85443909a1203d56d9344e, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 83 + itemId: 83 errorMessage: indentLevel: 0 duration: 3 @@ -4977,7 +5012,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 82 + itemId: 82 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 1612042692} @@ -5001,7 +5036,8 @@ MonoBehaviour: y: -878.838013 width: 152 height: 40 - sequenceName: 'END: NO COURAGE' + itemId: 99 + blockName: 'END: NO COURAGE' description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -5023,7 +5059,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 207aecf668a0345388087ccf522f9957, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 57 + itemId: 57 errorMessage: indentLevel: 0 duration: 1 @@ -5042,7 +5078,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 56 + itemId: 56 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5072,7 +5108,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 55 + itemId: 55 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5102,10 +5138,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 58 + itemId: 58 errorMessage: indentLevel: 0 storyText: Ah John, {pleased}there you are. + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -5127,7 +5164,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 207aecf668a0345388087ccf522f9957, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 71 + itemId: 71 errorMessage: indentLevel: 0 duration: 1 @@ -5146,7 +5183,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 68 + itemId: 68 errorMessage: indentLevel: 0 control: 2 @@ -5166,10 +5203,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 70 + itemId: 70 errorMessage: indentLevel: 0 storyText: Your {stat-up}courage{/stat-up} has increased! + description: character: {fileID: 0} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -5191,7 +5229,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f1ff0f540016ff64ab1556db6fe1e10f, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 69 + itemId: 69 errorMessage: indentLevel: 0 display: 2 @@ -5217,7 +5255,8 @@ MonoBehaviour: y: -883.838013 width: 132 height: 40 - sequenceName: 'END: COURAGE' + itemId: 100 + blockName: 'END: COURAGE' description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -5238,7 +5277,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 54 + itemId: 54 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5268,7 +5307,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 53 + itemId: 53 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5298,7 +5337,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 52 + itemId: 52 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5328,7 +5367,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 51 + itemId: 51 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5358,7 +5397,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 50 + itemId: 50 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5388,7 +5427,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 49 + itemId: 49 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5418,7 +5457,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 48 + itemId: 48 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5448,7 +5487,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 47 + itemId: 47 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5478,7 +5517,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 46 + itemId: 46 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5508,11 +5547,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ec422cd568a9c4a31ad7c36d0572b9da, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 45 + itemId: 45 errorMessage: indentLevel: 0 storyText: '{shout}No nausea? {shout}Dizziness? {shout}Feeling of sudden and impending doom?' + description: character: {fileID: 137130844} portrait: {fileID: 0} voiceOverClip: {fileID: 0} @@ -5534,7 +5574,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 44 + itemId: 44 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5564,7 +5604,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 43 + itemId: 43 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5594,7 +5634,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 42 + itemId: 42 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5624,7 +5664,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 3ac5ce55bc698fa4290939ef6e426501, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 41 + itemId: 41 errorMessage: indentLevel: 0 stage: {fileID: 0} @@ -5654,7 +5694,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 81 + itemId: 81 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 31336594} @@ -5672,7 +5712,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 91 + itemId: 91 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 884427801} @@ -5690,7 +5730,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: accc065c3e9a6457496f075b1bd49adc, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 90 + itemId: 90 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 31336594} @@ -5708,7 +5748,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 61 + itemId: 61 errorMessage: indentLevel: 0 control: 1 @@ -5728,7 +5768,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 62 + itemId: 62 errorMessage: indentLevel: 0 control: 0 @@ -5748,7 +5788,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 59 + itemId: 59 errorMessage: indentLevel: 0 control: 2 @@ -5768,7 +5808,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: bc30c92f7ffe3d746ac76cd528d616e5, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 60 + itemId: 60 errorMessage: indentLevel: 0 control: 1 @@ -5788,7 +5828,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 10cd462c89cb047158ccfb8a8df3f60a, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 88 + itemId: 88 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 884427801} @@ -5804,7 +5844,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 10cd462c89cb047158ccfb8a8df3f60a, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 89 + itemId: 89 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 31336594} @@ -5820,7 +5860,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 10cd462c89cb047158ccfb8a8df3f60a, type: 3} m_Name: m_EditorClassIdentifier: - commandId: 87 + itemId: 87 errorMessage: indentLevel: 0 spriteRenderer: {fileID: 1612042692} @@ -5857,7 +5897,8 @@ MonoBehaviour: y: -1010.35046 width: 142 height: 40 - sequenceName: Drink the Coffee? + itemId: 93 + blockName: Drink the Coffee? description: runSlowInEditor: 0 eventHandler: {fileID: 0} @@ -6170,7 +6211,7 @@ GameObject: - 4: {fileID: 1675553599} - 212: {fileID: 1675553598} m_Layer: 0 - m_Name: background + m_Name: Background m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -6364,7 +6405,7 @@ MonoBehaviour: - {fileID: 21300000, guid: d7af8fdea3ead3c4b8a4e54d014b255d, type: 3} - {fileID: 21300000, guid: d38d394fe4d92ae4da3d41e6ff3b0385, type: 3} portraitsFace: 2 - notes: + description: --- !u!4 &1880195409 Transform: m_ObjectHideFlags: 0 From d998fd32fdad61b43a62570e5fbc963861a3df67 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:53:37 +0100 Subject: [PATCH 20/30] Moved Language files to Narrative module #8 --- Assets/Fungus/{Flowchart => Narrative}/Editor/LanguageEditor.cs | 0 .../Fungus/{Flowchart => Narrative}/Editor/LanguageEditor.cs.meta | 0 Assets/Fungus/{Flowchart => Narrative}/Scripts/Language.cs | 0 Assets/Fungus/{Flowchart => Narrative}/Scripts/Language.cs.meta | 0 .../{Flowchart/Scripts => Thirdparty/CSVParser}/CSVSupport.cs | 0 .../Scripts => Thirdparty/CSVParser}/CSVSupport.cs.meta | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename Assets/Fungus/{Flowchart => Narrative}/Editor/LanguageEditor.cs (100%) rename Assets/Fungus/{Flowchart => Narrative}/Editor/LanguageEditor.cs.meta (100%) rename Assets/Fungus/{Flowchart => Narrative}/Scripts/Language.cs (100%) rename Assets/Fungus/{Flowchart => Narrative}/Scripts/Language.cs.meta (100%) rename Assets/Fungus/{Flowchart/Scripts => Thirdparty/CSVParser}/CSVSupport.cs (100%) rename Assets/Fungus/{Flowchart/Scripts => Thirdparty/CSVParser}/CSVSupport.cs.meta (100%) diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs b/Assets/Fungus/Narrative/Editor/LanguageEditor.cs similarity index 100% rename from Assets/Fungus/Flowchart/Editor/LanguageEditor.cs rename to Assets/Fungus/Narrative/Editor/LanguageEditor.cs diff --git a/Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta b/Assets/Fungus/Narrative/Editor/LanguageEditor.cs.meta similarity index 100% rename from Assets/Fungus/Flowchart/Editor/LanguageEditor.cs.meta rename to Assets/Fungus/Narrative/Editor/LanguageEditor.cs.meta diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs b/Assets/Fungus/Narrative/Scripts/Language.cs similarity index 100% rename from Assets/Fungus/Flowchart/Scripts/Language.cs rename to Assets/Fungus/Narrative/Scripts/Language.cs diff --git a/Assets/Fungus/Flowchart/Scripts/Language.cs.meta b/Assets/Fungus/Narrative/Scripts/Language.cs.meta similarity index 100% rename from Assets/Fungus/Flowchart/Scripts/Language.cs.meta rename to Assets/Fungus/Narrative/Scripts/Language.cs.meta diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs b/Assets/Fungus/Thirdparty/CSVParser/CSVSupport.cs similarity index 100% rename from Assets/Fungus/Flowchart/Scripts/CSVSupport.cs rename to Assets/Fungus/Thirdparty/CSVParser/CSVSupport.cs diff --git a/Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta b/Assets/Fungus/Thirdparty/CSVParser/CSVSupport.cs.meta similarity index 100% rename from Assets/Fungus/Flowchart/Scripts/CSVSupport.cs.meta rename to Assets/Fungus/Thirdparty/CSVParser/CSVSupport.cs.meta From de001958658f0a0a4720d3fab144f48a12fb5c1d Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 12:56:42 +0100 Subject: [PATCH 21/30] Added Language prefab and menu item #8 --- .../Narrative/Editor/NarrativeMenuItems.cs | 6 +++ .../Narrative/Resources/Language.prefab | 54 +++++++++++++++++++ .../Narrative/Resources/Language.prefab.meta | 8 +++ 3 files changed, 68 insertions(+) create mode 100644 Assets/Fungus/Narrative/Resources/Language.prefab create mode 100644 Assets/Fungus/Narrative/Resources/Language.prefab.meta diff --git a/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs b/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs index 6761b444..14a9ad47 100644 --- a/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs +++ b/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs @@ -50,6 +50,12 @@ namespace Fungus { FlowchartMenuItems.SpawnPrefab("StagePosition"); } + + [MenuItem("Tools/Fungus/Create/Language", false, 57)] + static void CreateLanguage() + { + FlowchartMenuItems.SpawnPrefab("Language"); + } } } \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Resources/Language.prefab b/Assets/Fungus/Narrative/Resources/Language.prefab new file mode 100644 index 00000000..1c1f5241 --- /dev/null +++ b/Assets/Fungus/Narrative/Resources/Language.prefab @@ -0,0 +1,54 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &149266 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + serializedVersion: 4 + m_Component: + - 4: {fileID: 480768} + - 114: {fileID: 11488122} + m_Layer: 0 + m_Name: Language + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &480768 +Transform: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 149266} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.05546069, y: -3.16485739, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 +--- !u!114 &11488122 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 100100000} + m_GameObject: {fileID: 149266} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e5724422a635e425bae0af9ffe2615d6, type: 3} + m_Name: + m_EditorClassIdentifier: + activeLanguage: + localizationFile: {fileID: 0} +--- !u!1001 &100100000 +Prefab: + m_ObjectHideFlags: 1 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 0} + m_Modifications: [] + m_RemovedComponents: [] + m_ParentPrefab: {fileID: 0} + m_RootGameObject: {fileID: 149266} + m_IsPrefabParent: 1 diff --git a/Assets/Fungus/Narrative/Resources/Language.prefab.meta b/Assets/Fungus/Narrative/Resources/Language.prefab.meta new file mode 100644 index 00000000..a3a58803 --- /dev/null +++ b/Assets/Fungus/Narrative/Resources/Language.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ffbd0831d997545eab75c364da082c1b +timeCreated: 1428580452 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: From 4c41ada4a846b7d226e8e415753a4f67951c95bd Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 13:17:35 +0100 Subject: [PATCH 22/30] Renamed Language to Localisation for clarity #8 --- Assets/Fungus/Flowchart/Scripts/Flowchart.cs | 2 +- ...anguageEditor.cs => LocalizationEditor.cs} | 36 ++++----- ...tor.cs.meta => LocalizationEditor.cs.meta} | 4 +- .../Narrative/Editor/NarrativeMenuItems.cs | 6 +- .../{Language.prefab => Localization.prefab} | 0 ...e.prefab.meta => Localization.prefab.meta} | 0 .../Scripts/{Language.cs => Localization.cs} | 80 +++++++++---------- ...{Language.cs.meta => Localization.cs.meta} | 0 8 files changed, 64 insertions(+), 64 deletions(-) rename Assets/Fungus/Narrative/Editor/{LanguageEditor.cs => LocalizationEditor.cs} (66%) rename Assets/Fungus/Narrative/Editor/{LanguageEditor.cs.meta => LocalizationEditor.cs.meta} (76%) rename Assets/Fungus/Narrative/Resources/{Language.prefab => Localization.prefab} (100%) rename Assets/Fungus/Narrative/Resources/{Language.prefab.meta => Localization.prefab.meta} (100%) rename Assets/Fungus/Narrative/Scripts/{Language.cs => Localization.cs} (83%) rename Assets/Fungus/Narrative/Scripts/{Language.cs.meta => Localization.cs.meta} (100%) diff --git a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs index c6d117df..6502f274 100644 --- a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs +++ b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs @@ -112,7 +112,7 @@ namespace Fungus /** * Unique identifier for identifying this flowchart in localized string keys. */ - [Tooltip("Unique identifier for this flowchart in localized string keys. An id must be provided for Language string export to work.")] + [Tooltip("Unique identifier for this flowchart in localized string keys. This id must be provided for localization string export to work.")] public string localizationId = ""; /** diff --git a/Assets/Fungus/Narrative/Editor/LanguageEditor.cs b/Assets/Fungus/Narrative/Editor/LocalizationEditor.cs similarity index 66% rename from Assets/Fungus/Narrative/Editor/LanguageEditor.cs rename to Assets/Fungus/Narrative/Editor/LocalizationEditor.cs index 885ec7b5..0b30477e 100644 --- a/Assets/Fungus/Narrative/Editor/LanguageEditor.cs +++ b/Assets/Fungus/Narrative/Editor/LocalizationEditor.cs @@ -8,8 +8,8 @@ using Rotorz.ReorderableList; namespace Fungus { - [CustomEditor(typeof(Language))] - public class LanguageEditor : Editor + [CustomEditor(typeof(Localization))] + public class LocalizationEditor : Editor { protected SerializedProperty activeLanguageProp; protected SerializedProperty localizationFileProp; @@ -24,30 +24,30 @@ namespace Fungus { serializedObject.Update(); - Language language = target as Language; + Localization localization = target as Localization; EditorGUILayout.PropertyField(activeLanguageProp); EditorGUILayout.PropertyField(localizationFileProp); if (GUILayout.Button(new GUIContent("Export Localization File"))) { - ExportLocalizationFile(language); + ExportLocalizationFile(localization); } if (GUILayout.Button(new GUIContent("Export Standard Text"))) { - ExportStandardText(language); + ExportStandardText(localization); } if (GUILayout.Button(new GUIContent("Import Standard Text"))) { - ImportStandardText(language); + ImportStandardText(localization); } serializedObject.ApplyModifiedProperties(); } - public virtual void ExportLocalizationFile(Language language) + public virtual void ExportLocalizationFile(Localization localization) { string path = EditorUtility.SaveFilePanel("Export Localization File", "Assets/", "localization.csv", ""); @@ -56,14 +56,14 @@ namespace Fungus return; } - string csvData = language.GetCSVData(); + string csvData = localization.GetCSVData(); File.WriteAllText(path, csvData); AssetDatabase.Refresh(); - ShowNotification(language); + ShowNotification(localization); } - public virtual void ExportStandardText(Language language) + public virtual void ExportStandardText(Localization localization) { string path = EditorUtility.SaveFilePanel("Export Standard Text", "Assets/", "standard.txt", ""); if (path.Length == 0) @@ -71,14 +71,14 @@ namespace Fungus return; } - string textData = language.GetStandardText(); + string textData = localization.GetStandardText(); File.WriteAllText(path, textData); AssetDatabase.Refresh(); - ShowNotification(language); + ShowNotification(localization); } - public virtual void ImportStandardText(Language language) + public virtual void ImportStandardText(Localization localization) { string path = EditorUtility.OpenFilePanel("Import Standard Text", "Assets/", "txt"); if (path.Length == 0) @@ -87,18 +87,18 @@ namespace Fungus } string textData = File.ReadAllText(path); - language.SetStandardText(textData); + localization.SetStandardText(textData); - ShowNotification(language); + ShowNotification(localization); } - protected virtual void ShowNotification(Language language) + protected virtual void ShowNotification(Localization localization) { EditorWindow window = EditorWindow.GetWindow(typeof(FlowchartWindow), false, "Flowchart"); if (window != null) { - window.ShowNotification(new GUIContent(language.notificationText)); - language.notificationText = ""; + window.ShowNotification(new GUIContent(localization.notificationText)); + localization.notificationText = ""; } } } diff --git a/Assets/Fungus/Narrative/Editor/LanguageEditor.cs.meta b/Assets/Fungus/Narrative/Editor/LocalizationEditor.cs.meta similarity index 76% rename from Assets/Fungus/Narrative/Editor/LanguageEditor.cs.meta rename to Assets/Fungus/Narrative/Editor/LocalizationEditor.cs.meta index 5448fada..ba8a068c 100644 --- a/Assets/Fungus/Narrative/Editor/LanguageEditor.cs.meta +++ b/Assets/Fungus/Narrative/Editor/LocalizationEditor.cs.meta @@ -1,6 +1,6 @@ fileFormatVersion: 2 -guid: 73e0ffd2fe9ba4afb995e1587c027556 -timeCreated: 1427887512 +guid: ab0caac085485491fb32dbf86efefef1 +timeCreated: 1428581512 licenseType: Free MonoImporter: serializedVersion: 2 diff --git a/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs b/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs index 14a9ad47..ee4450ad 100644 --- a/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs +++ b/Assets/Fungus/Narrative/Editor/NarrativeMenuItems.cs @@ -51,10 +51,10 @@ namespace Fungus FlowchartMenuItems.SpawnPrefab("StagePosition"); } - [MenuItem("Tools/Fungus/Create/Language", false, 57)] - static void CreateLanguage() + [MenuItem("Tools/Fungus/Create/Localization", false, 57)] + static void CreateLocalization() { - FlowchartMenuItems.SpawnPrefab("Language"); + FlowchartMenuItems.SpawnPrefab("Localization"); } } diff --git a/Assets/Fungus/Narrative/Resources/Language.prefab b/Assets/Fungus/Narrative/Resources/Localization.prefab similarity index 100% rename from Assets/Fungus/Narrative/Resources/Language.prefab rename to Assets/Fungus/Narrative/Resources/Localization.prefab diff --git a/Assets/Fungus/Narrative/Resources/Language.prefab.meta b/Assets/Fungus/Narrative/Resources/Localization.prefab.meta similarity index 100% rename from Assets/Fungus/Narrative/Resources/Language.prefab.meta rename to Assets/Fungus/Narrative/Resources/Localization.prefab.meta diff --git a/Assets/Fungus/Narrative/Scripts/Language.cs b/Assets/Fungus/Narrative/Scripts/Localization.cs similarity index 83% rename from Assets/Fungus/Narrative/Scripts/Language.cs rename to Assets/Fungus/Narrative/Scripts/Localization.cs index 940f2299..cab716d1 100644 --- a/Assets/Fungus/Narrative/Scripts/Language.cs +++ b/Assets/Fungus/Narrative/Scripts/Localization.cs @@ -14,7 +14,7 @@ namespace Fungus /** * Multi-language localization support. */ - public class Language : MonoBehaviour + public class Localization : MonoBehaviour { /** * Currently active language, usually defined by a two letter language code (e.g DE = German) @@ -26,7 +26,7 @@ namespace Fungus /** * Temp storage for a single item of standard text and its localizations */ - protected class LanguageItem + protected class TextItem { public string description; public string standardText; @@ -55,26 +55,26 @@ namespace Fungus } /** - * Convert all language items and localized strings to an easy to edit CSV format. + * Convert all text items and localized strings to an easy to edit CSV format. */ public virtual string GetCSVData() { - // Collect all the language items present in the scene - Dictionary languageItems = FindLanguageItems(); + // Collect all the text items present in the scene + Dictionary textItems = FindTextItems(); - // Update language items with localization data from CSV file + // Update text items with localization data from CSV file if (localizationFile != null && localizationFile.text.Length > 0) { - AddLocalizedStrings(languageItems, localizationFile.text); + AddLocalizedStrings(textItems, localizationFile.text); } // Build CSV header row and a list of the language codes currently in use string csvHeader = "Key,Description,Standard"; List languageCodes = new List(); - foreach (LanguageItem languageItem in languageItems.Values) + foreach (TextItem textItem in textItems.Values) { - foreach (string languageCode in languageItem.localizedStrings.Keys) + foreach (string languageCode in textItem.localizedStrings.Keys) { if (!languageCodes.Contains(languageCode)) { @@ -84,22 +84,22 @@ namespace Fungus } } - // Build the CSV file using collected language items + // Build the CSV file using collected text items int rowCount = 0; string csvData = csvHeader + "\n"; - foreach (string stringId in languageItems.Keys) + foreach (string stringId in textItems.Keys) { - LanguageItem languageItem = languageItems[stringId]; + TextItem textItem = textItems[stringId]; string row = CSVSupport.Escape(stringId); - row += "," + CSVSupport.Escape(languageItem.description); - row += "," + CSVSupport.Escape(languageItem.standardText); + row += "," + CSVSupport.Escape(textItem.description); + row += "," + CSVSupport.Escape(textItem.standardText); foreach (string languageCode in languageCodes) { - if (languageItem.localizedStrings.ContainsKey(languageCode)) + if (textItem.localizedStrings.ContainsKey(languageCode)) { - row += "," + CSVSupport.Escape(languageItem.localizedStrings[languageCode]); + row += "," + CSVSupport.Escape(textItem.localizedStrings[languageCode]); } else { @@ -117,21 +117,21 @@ namespace Fungus } /** - * Buidls a dictionary of localizable objects in the scene. + * Buidls a dictionary of localizable text items in the scene. */ - protected Dictionary FindLanguageItems() + protected Dictionary FindTextItems() { - Dictionary languageItems = new Dictionary(); + Dictionary textItems = new Dictionary(); // Export all character names foreach (Character character in GameObject.FindObjectsOfType()) { // String id for character names is CHARACTER. - LanguageItem languageItem = new LanguageItem(); - languageItem.standardText = character.nameText; - languageItem.description = character.description; + TextItem textItem = new TextItem(); + textItem.standardText = character.nameText; + textItem.description = character.description; string stringId = "CHARACTER." + character.nameText; - languageItems[stringId] = languageItem; + textItems[stringId] = textItem; } // Export all Say and Menu commands in the scene @@ -180,31 +180,31 @@ namespace Fungus continue; } - LanguageItem languageItem = null; - if (languageItems.ContainsKey(stringId)) + TextItem textItem = null; + if (textItems.ContainsKey(stringId)) { - languageItem = languageItems[stringId]; + textItem = textItems[stringId]; } else { - languageItem = new LanguageItem(); - languageItems[stringId] = languageItem; + textItem = new TextItem(); + textItems[stringId] = textItem; } // Update basic properties,leaving localised strings intact - languageItem.standardText = standardText; - languageItem.description = description; + textItem.standardText = standardText; + textItem.description = description; } } } - return languageItems; + return textItems; } /** - * Adds localized strings from CSV file data to a dictionary of language items in the scene. + * Adds localized strings from CSV file data to a dictionary of text items in the scene. */ - protected virtual void AddLocalizedStrings(Dictionary languageItems, string csvData) + protected virtual void AddLocalizedStrings(Dictionary textItems, string csvData) { CsvParser csvParser = new CsvParser(); string[][] csvTable = csvParser.Parse(csvData); @@ -229,13 +229,13 @@ namespace Fungus string stringId = fields[0]; - if (!languageItems.ContainsKey(stringId)) + if (!textItems.ContainsKey(stringId)) { continue; } // Store localized strings for this string id - LanguageItem languageItem = languageItems[stringId]; + TextItem textItem = textItems[stringId]; for (int j = 3; j < fields.Length; ++j) { if (j >= columnNames.Length) @@ -247,7 +247,7 @@ namespace Fungus if (languageEntry.Length > 0) { - languageItem.localizedStrings[languageCode] = languageEntry; + textItem.localizedStrings[languageCode] = languageEntry; } } } @@ -451,19 +451,19 @@ namespace Fungus */ public virtual string GetStandardText() { - // Collect all the language items present in the scene - Dictionary languageItems = FindLanguageItems(); + // Collect all the text items present in the scene + Dictionary textItems = FindTextItems(); string textData = ""; int rowCount = 0; - foreach (string stringId in languageItems.Keys) + foreach (string stringId in textItems.Keys) { if (!stringId.StartsWith("SAY.") && !(stringId.StartsWith("MENU."))) { continue; } - LanguageItem languageItem = languageItems[stringId]; + TextItem languageItem = textItems[stringId]; textData += "#" + stringId + "\n"; textData += languageItem.standardText.Trim() + "\n\n"; diff --git a/Assets/Fungus/Narrative/Scripts/Language.cs.meta b/Assets/Fungus/Narrative/Scripts/Localization.cs.meta similarity index 100% rename from Assets/Fungus/Narrative/Scripts/Language.cs.meta rename to Assets/Fungus/Narrative/Scripts/Localization.cs.meta From 0c8b8e79ea1180c8d28ba81af4a02dbb0a6d38fe Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 14:31:37 +0100 Subject: [PATCH 23/30] Renamed localisation prefab #8 --- Assets/Fungus/Narrative/Resources/Localization.prefab | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Fungus/Narrative/Resources/Localization.prefab b/Assets/Fungus/Narrative/Resources/Localization.prefab index 1c1f5241..c9845980 100644 --- a/Assets/Fungus/Narrative/Resources/Localization.prefab +++ b/Assets/Fungus/Narrative/Resources/Localization.prefab @@ -8,9 +8,9 @@ GameObject: serializedVersion: 4 m_Component: - 4: {fileID: 480768} - - 114: {fileID: 11488122} + - 114: {fileID: 11438504} m_Layer: 0 - m_Name: Language + m_Name: Localization m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -28,7 +28,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 ---- !u!114 &11488122 +--- !u!114 &11438504 MonoBehaviour: m_ObjectHideFlags: 1 m_PrefabParentObject: {fileID: 0} From 555660fa753bd377e81a3fb93eb728983a293604 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 14:32:43 +0100 Subject: [PATCH 24/30] Can now add custom localized strings to localisation file #8 --- .../Fungus/Narrative/Scripts/Localization.cs | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/Assets/Fungus/Narrative/Scripts/Localization.cs b/Assets/Fungus/Narrative/Scripts/Localization.cs index cab716d1..2155ff50 100644 --- a/Assets/Fungus/Narrative/Scripts/Localization.cs +++ b/Assets/Fungus/Narrative/Scripts/Localization.cs @@ -21,15 +21,15 @@ namespace Fungus */ public string activeLanguage = ""; - protected Dictionary localizedStrings = new Dictionary(); + protected static Dictionary localizedStrings = new Dictionary(); /** * Temp storage for a single item of standard text and its localizations */ protected class TextItem { - public string description; - public string standardText; + public string description = ""; + public string standardText = ""; public Dictionary localizedStrings = new Dictionary(); } @@ -54,6 +54,20 @@ namespace Fungus } } + /** + * Looks up the specified string in the localized strings table. + * For this to work, a localization file and active language must have been set previously. + */ + public static string GetLocalizedString(string stringId) + { + if (localizedStrings.ContainsKey(stringId)) + { + return localizedStrings[stringId]; + } + + return ""; + } + /** * Convert all text items and localized strings to an easy to edit CSV format. */ @@ -66,7 +80,7 @@ namespace Fungus if (localizationFile != null && localizationFile.text.Length > 0) { - AddLocalizedStrings(textItems, localizationFile.text); + AddCSVDataItems(textItems, localizationFile.text); } // Build CSV header row and a list of the language codes currently in use @@ -204,7 +218,7 @@ namespace Fungus /** * Adds localized strings from CSV file data to a dictionary of text items in the scene. */ - protected virtual void AddLocalizedStrings(Dictionary textItems, string csvData) + protected virtual void AddCSVDataItems(Dictionary textItems, string csvData) { CsvParser csvParser = new CsvParser(); string[][] csvTable = csvParser.Parse(csvData); @@ -221,9 +235,9 @@ namespace Fungus for (int i = 1; i < csvTable.Length; ++i) { string[] fields = csvTable[i]; - if (fields.Length < 4) + if (fields.Length < 3) { - // No localized string fields present + // No standard text or localized string fields present continue; } @@ -231,11 +245,24 @@ namespace Fungus if (!textItems.ContainsKey(stringId)) { - continue; + if (stringId.StartsWith("CHARACTER.") || + stringId.StartsWith("SAY.") || + stringId.StartsWith("MENU.")) + { + // If it's a 'built-in' type this probably means that item has been deleted from its flowchart, + // so there's no need to add a text item for it. + continue; + } + + // Key not found. Assume it's a custom string that we want to retain, so add a text item for it. + TextItem newTextItem = new TextItem(); + newTextItem.description = CSVSupport.Unescape(fields[1]); + newTextItem.standardText = CSVSupport.Unescape(fields[2]); + textItems[stringId] = newTextItem; } - // Store localized strings for this string id TextItem textItem = textItems[stringId]; + for (int j = 3; j < fields.Length; ++j) { if (j >= columnNames.Length) @@ -331,6 +358,10 @@ namespace Fungus { localizedStrings[stringId] = languageEntry; PopulateTextProperty(stringId, languageEntry, flowchartDict, characterDict); + + // We also store the localized string in the localized strings dictionary in + // case it's required later on (e.g. for a variable substitution). + localizedStrings[stringId] = languageEntry; } } } From d2ab3013768a52a27af144442ae92f086e79ffa7 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 15:02:41 +0100 Subject: [PATCH 25/30] All localised strings are now added to a dictionary for easy lookup If no active language is set, the standard text strings will be added to the localisation dictionary. This allows you to use the localisation table to store strings which can be used for variable substitution. --- .../Fungus/Narrative/Scripts/Localization.cs | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/Assets/Fungus/Narrative/Scripts/Localization.cs b/Assets/Fungus/Narrative/Scripts/Localization.cs index 2155ff50..ce87a0ea 100644 --- a/Assets/Fungus/Narrative/Scripts/Localization.cs +++ b/Assets/Fungus/Narrative/Scripts/Localization.cs @@ -46,8 +46,7 @@ namespace Fungus public virtual void Start() { - if (activeLanguage.Length > 0 && - localizationFile != null && + if (localizationFile != null && localizationFile.text.Length > 0) { SetActiveLanguage(activeLanguage, localizationFile.text); @@ -57,15 +56,21 @@ namespace Fungus /** * Looks up the specified string in the localized strings table. * For this to work, a localization file and active language must have been set previously. + * Return null if the string is not found. */ public static string GetLocalizedString(string stringId) { + if (localizedStrings == null) + { + return null; + } + if (localizedStrings.ContainsKey(stringId)) { return localizedStrings[stringId]; } - return ""; + return null; } /** @@ -306,13 +311,14 @@ namespace Fungus // Parse header row string[] columnNames = csvTable[0]; - if (columnNames.Length < 4) + if (columnNames.Length < 3) { // No languages defined in CSV file return; } - int languageIndex = -1; + // First assume standard text column and then look for a matching language column + int languageIndex = 2; for (int i = 3; i < columnNames.Length; ++i) { if (columnNames[i] == languageCode) @@ -322,12 +328,28 @@ namespace Fungus } } - if (languageIndex == -1) + if (languageIndex == 2) { - // Language not found + // Using standard text column + // Add all strings to the localized strings dict, but don't replace standard text in the scene. + // This allows string substitution to work for both standard and localized text strings. + for (int i = 1; i < csvTable.Length; ++i) + { + string[] fields = csvTable[i]; + if (fields.Length < 3) + { + continue; + } + + localizedStrings[fields[0]] = fields[languageIndex]; + } return; } + // Using a localized language text column + // 1. Add all localized text to the localized strings dict + // 2. Update all scene text properties with localized versions + // Cache a lookup table of characters in the scene Dictionary characterDict = new Dictionary(); foreach (Character character in GameObject.FindObjectsOfType()) @@ -358,10 +380,6 @@ namespace Fungus { localizedStrings[stringId] = languageEntry; PopulateTextProperty(stringId, languageEntry, flowchartDict, characterDict); - - // We also store the localized string in the localized strings dictionary in - // case it's required later on (e.g. for a variable substitution). - localizedStrings[stringId] = languageEntry; } } } From 015d6e9204c2fee3a5c0ba49c9555b726ec47aab Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 15:04:28 +0100 Subject: [PATCH 26/30] Use localised strings keys in variable substitution. #8 --- Assets/Fungus/Flowchart/Scripts/Flowchart.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs index 6502f274..f76aa841 100644 --- a/Assets/Fungus/Flowchart/Scripts/Flowchart.cs +++ b/Assets/Fungus/Flowchart/Scripts/Flowchart.cs @@ -678,15 +678,25 @@ namespace Fungus foreach (Match match in results) { string key = match.Value.Substring(2, match.Value.Length - 3); + + // Look for matching variable first foreach (Variable variable in variables) { if (variable.key == key) { string value = variable.ToString(); subbedText = subbedText.Replace(match.Value, value); - break; + return subbedText; } } + + // Next look for matching localized string + string localizedString = Localization.GetLocalizedString(key); + if (localizedString != null) + { + subbedText = subbedText.Replace(match.Value, localizedString); + return subbedText; + } } return subbedText; From 9320f742377b851a08b07a6b5559a6439f0dce18 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 15:05:31 +0100 Subject: [PATCH 27/30] Added wildcard for .~lock files (Excel) --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f9a51964..a6b25bff 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ *.sln *.userprefs -Assets/.~lock.strings.csv# +Assets/.~lock.* From 9e37f1956070707c6f0324e93aa8c63f51c3dcc0 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 16:00:37 +0100 Subject: [PATCH 28/30] SetActiveLanguage is more generic #8 --- .../Fungus/Narrative/Scripts/Localization.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Assets/Fungus/Narrative/Scripts/Localization.cs b/Assets/Fungus/Narrative/Scripts/Localization.cs index ce87a0ea..b629a4ff 100644 --- a/Assets/Fungus/Narrative/Scripts/Localization.cs +++ b/Assets/Fungus/Narrative/Scripts/Localization.cs @@ -1,4 +1,10 @@ -using UnityEngine; +/** + * CSVParser by Ideafixxxer. http://www.codeproject.com/Tips/741941/CSV-Parser-Csharp + * This code is licensed under the CPOL open source license. + * http://www.codeproject.com/info/cpol10.aspx + */ + +using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif @@ -49,7 +55,7 @@ namespace Fungus if (localizationFile != null && localizationFile.text.Length > 0) { - SetActiveLanguage(activeLanguage, localizationFile.text); + SetActiveLanguage(activeLanguage); } } @@ -289,7 +295,7 @@ namespace Fungus * Scan a localization CSV file and copies the strings for the specified language code * into the text properties of the appropriate scene objects. */ - public virtual void SetActiveLanguage(string languageCode, string csvData) + public virtual void SetActiveLanguage(string languageCode) { if (!Application.isPlaying) { @@ -297,10 +303,16 @@ namespace Fungus return; } + if (localizationFile == null) + { + // No localization file set + return; + } + localizedStrings.Clear(); CsvParser csvParser = new CsvParser(); - string[][] csvTable = csvParser.Parse(csvData); + string[][] csvTable = csvParser.Parse(localizationFile.text); if (csvTable.Length <= 1) { From cb7e25b728841fecc7b60c41395625384f0bb4c3 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Thu, 9 Apr 2015 16:00:48 +0100 Subject: [PATCH 29/30] Added Set Language command --- .../Narrative/Scripts/Commands/SetLanguage.cs | 35 +++++++++++++++++++ .../Scripts/Commands/SetLanguage.cs.meta | 12 +++++++ 2 files changed, 47 insertions(+) create mode 100644 Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs create mode 100644 Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs.meta diff --git a/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs b/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs new file mode 100644 index 00000000..57be8053 --- /dev/null +++ b/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using System.Collections; + +namespace Fungus +{ + [CommandInfo("Narrative", + "Set Language", + "Set the active language for the scene. A Localization object with a localization file must be present in the scene.")] + [AddComponentMenu("")] + public class SetLanguage : Command + { + public string languageCode; + + public override void OnEnter() + { + Localization localization = GameObject.FindObjectOfType(); + if (localization != null) + { + localization.SetActiveLanguage(languageCode); + } + + Continue(); + } + + public override string GetSummary() + { + return languageCode; + } + + public override Color GetButtonColor() + { + return new Color32(184, 210, 235, 255); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs.meta b/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs.meta new file mode 100644 index 00000000..712a8ab6 --- /dev/null +++ b/Assets/Fungus/Narrative/Scripts/Commands/SetLanguage.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3fc625e237d6048bf86f34835d8266d9 +timeCreated: 1428591017 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 22427dfe03be2a060d977d4e7c27ab3bcff5cd81 Mon Sep 17 00:00:00 2001 From: chrisgregan Date: Fri, 10 Apr 2015 09:02:49 +0100 Subject: [PATCH 30/30] Renamed SequenceEditor & SequenceInspector to BlockEditor & BlockInspector --- .../Fungus/Flowchart/Editor/{SequenceEditor.cs => BlockEditor.cs} | 0 .../Editor/{SequenceEditor.cs.meta => BlockEditor.cs.meta} | 0 .../Flowchart/Editor/{SequenceInspector.cs => BlockInspector.cs} | 0 .../Editor/{SequenceInspector.cs.meta => BlockInspector.cs.meta} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename Assets/Fungus/Flowchart/Editor/{SequenceEditor.cs => BlockEditor.cs} (100%) rename Assets/Fungus/Flowchart/Editor/{SequenceEditor.cs.meta => BlockEditor.cs.meta} (100%) rename Assets/Fungus/Flowchart/Editor/{SequenceInspector.cs => BlockInspector.cs} (100%) rename Assets/Fungus/Flowchart/Editor/{SequenceInspector.cs.meta => BlockInspector.cs.meta} (100%) diff --git a/Assets/Fungus/Flowchart/Editor/SequenceEditor.cs b/Assets/Fungus/Flowchart/Editor/BlockEditor.cs similarity index 100% rename from Assets/Fungus/Flowchart/Editor/SequenceEditor.cs rename to Assets/Fungus/Flowchart/Editor/BlockEditor.cs diff --git a/Assets/Fungus/Flowchart/Editor/SequenceEditor.cs.meta b/Assets/Fungus/Flowchart/Editor/BlockEditor.cs.meta similarity index 100% rename from Assets/Fungus/Flowchart/Editor/SequenceEditor.cs.meta rename to Assets/Fungus/Flowchart/Editor/BlockEditor.cs.meta diff --git a/Assets/Fungus/Flowchart/Editor/SequenceInspector.cs b/Assets/Fungus/Flowchart/Editor/BlockInspector.cs similarity index 100% rename from Assets/Fungus/Flowchart/Editor/SequenceInspector.cs rename to Assets/Fungus/Flowchart/Editor/BlockInspector.cs diff --git a/Assets/Fungus/Flowchart/Editor/SequenceInspector.cs.meta b/Assets/Fungus/Flowchart/Editor/BlockInspector.cs.meta similarity index 100% rename from Assets/Fungus/Flowchart/Editor/SequenceInspector.cs.meta rename to Assets/Fungus/Flowchart/Editor/BlockInspector.cs.meta