added yarn spinner package
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using Yarn.Compiler;
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
using UnityEngine.Localization;
|
||||
|
||||
public class AddAssetsToAssetTableCollectionWizard : EditorWindow
|
||||
{
|
||||
|
||||
private YarnProject? yarnProject;
|
||||
|
||||
private AssetTableCollection? assetTableCollection;
|
||||
|
||||
private Type? _assetType;
|
||||
private Type AssetType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_assetType == null)
|
||||
{
|
||||
var typeName = EditorPrefs.GetString("YarnSpinner_AddAssets_AssetType", string.Empty);
|
||||
if (typeName != string.Empty)
|
||||
{
|
||||
_assetType = System.Type.GetType(typeName, throwOnError: false, ignoreCase: false);
|
||||
}
|
||||
}
|
||||
_assetType ??= typeof(AudioClip);
|
||||
return _assetType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_assetType = value;
|
||||
EditorPrefs.SetString("YarnSpinner_AddAssets_AssetType", _assetType?.AssemblyQualifiedName ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, DefaultAsset?> localesToFolders = new Dictionary<string, DefaultAsset?>();
|
||||
private Type[] allTypes = Array.Empty<Type>();
|
||||
private GUIContent[] allTypeContents = Array.Empty<GUIContent>();
|
||||
System.Collections.ObjectModel.ReadOnlyCollection<UnityEngine.Localization.Locale>? locales = null;
|
||||
|
||||
private Dictionary<LocaleIdentifier, LocalizationTable> _cachedTables = new();
|
||||
|
||||
const string description = "This tool searches Asset Folders for assets of the selected type, and then adds them to an Asset Table Collection. Line Providers, like Unity Localised Line Provider, can then fetch these assets at run-time.";
|
||||
|
||||
[MenuItem("Window/Yarn Spinner/Add Assets to Table Collection")]
|
||||
static void Init()
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
var window = CreateWindow<AddAssetsToAssetTableCollectionWizard>();
|
||||
window.ShowPopup();
|
||||
window.titleContent = new GUIContent("Add Assets to Table Collection");
|
||||
|
||||
if (Selection.activeObject is AssetTableCollection collection)
|
||||
{
|
||||
window.assetTableCollection = collection;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
allTypes = TypeCache.GetTypesDerivedFrom<UnityEngine.Object>().OrderBy(t => t.FullName).ToArray();
|
||||
allTypeContents = allTypes.Select(t => new GUIContent(
|
||||
t.FullName.Replace(".", "/"),
|
||||
EditorGUIUtility.ObjectContent(null, t).image
|
||||
)).ToArray();
|
||||
locales = LocalizationEditorSettings.GetLocales();
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
|
||||
using (new GUILayout.VerticalScope())
|
||||
{
|
||||
|
||||
EditorGUILayout.BeginVertical(EditorStyles.inspectorFullWidthMargins);
|
||||
|
||||
EditorGUILayout.HelpBox(description, MessageType.Info);
|
||||
|
||||
assetTableCollection = EditorGUILayout.ObjectField(new GUIContent("Asset Table Collection", "The asset table collection to add assets to"), assetTableCollection, typeof(AssetTableCollection), allowSceneObjects: false) as AssetTableCollection;
|
||||
|
||||
|
||||
yarnProject = EditorGUILayout.ObjectField(new GUIContent("Yarn Project", "The Yarn Project to add assets for."), yarnProject, typeof(YarnProject), allowSceneObjects: false) as YarnProject;
|
||||
|
||||
var selectedIndex = Array.IndexOf(allTypes, AssetType);
|
||||
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var newSelection = EditorGUILayout.Popup(new GUIContent("Asset Type", "The type of assets to find in the Asset Folders"), selectedIndex, allTypeContents);
|
||||
|
||||
if (change.changed)
|
||||
{
|
||||
AssetType = allTypes[newSelection];
|
||||
}
|
||||
}
|
||||
|
||||
var headerStyle = EditorStyles.boldLabel;
|
||||
|
||||
if (assetTableCollection != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Asset Folders", headerStyle);
|
||||
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
if (locales == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No locales were found in your project. Is Unity Localization installed and correctly configured?", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var locale in locales)
|
||||
{
|
||||
if (_cachedTables.TryGetValue(locale.Identifier, out var localizationTable) == false || localizationTable == null)
|
||||
{
|
||||
if (assetTableCollection != null)
|
||||
{
|
||||
localizationTable = assetTableCollection.GetTable(locale.Identifier);
|
||||
|
||||
_cachedTables[locale.Identifier] = localizationTable;
|
||||
}
|
||||
}
|
||||
|
||||
if (localizationTable == null)
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent(locale.LocaleName), new GUIContent("No table in collection"));
|
||||
continue;
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(localizationTable == null))
|
||||
{
|
||||
localesToFolders.TryGetValue(locale.Identifier.Code, out var currentFolder);
|
||||
|
||||
localesToFolders[locale.Identifier.Code] = EditorGUILayout.ObjectField(
|
||||
new GUIContent(locale.LocaleName, $"The folder to search for {AssetType.Name} assets for the '{locale.LocaleName}' locale"),
|
||||
currentFolder,
|
||||
typeof(DefaultAsset),
|
||||
allowSceneObjects: false) as DefaultAsset;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
var readyToAddAssets = assetTableCollection != null && yarnProject != null && localesToFolders.Where(kv => kv.Value != null).Count() > 0;
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(!readyToAddAssets))
|
||||
{
|
||||
if (GUILayout.Button("Add Assets"))
|
||||
{
|
||||
AddAssets(assetTableCollection!, yarnProject!, localesToFolders!, AssetType);
|
||||
// this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddAssets(AssetTableCollection assetTableCollection, YarnProject yarnProject, IReadOnlyDictionary<string, DefaultAsset> localesToFolders, System.Type assetType)
|
||||
{
|
||||
var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(yarnProject)) as YarnProjectImporter;
|
||||
|
||||
if (importer == null)
|
||||
{
|
||||
throw new InvalidOperationException("Failed to get an importer for Yarn Project");
|
||||
}
|
||||
|
||||
var stringTable = importer.GenerateStringsTable();
|
||||
|
||||
var lineIDs = stringTable.Select(e => e.ID);
|
||||
|
||||
int totalCount = 0;
|
||||
foreach (var locale in LocalizationEditorSettings.GetLocales())
|
||||
{
|
||||
int perLocaleCount = 0;
|
||||
if (localesToFolders.TryGetValue(locale.Identifier.Code, out var folder) == false
|
||||
|| folder == null)
|
||||
{
|
||||
// No folder given for this locale. Skip it!
|
||||
Debug.Log($"Skipping {locale.LocaleName} because no folder was provided");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assetTableCollection.ContainsTable(locale.Identifier) == false)
|
||||
{
|
||||
// No table in this collection for this locale! Skip it!
|
||||
Debug.Log($"Skipping {locale.LocaleName} because no table exists");
|
||||
continue;
|
||||
}
|
||||
|
||||
var path = AssetDatabase.GetAssetPath(folder);
|
||||
|
||||
var idsToAssetPaths = YarnProjectUtility.FindAssetPathsForLineIDs(lineIDs, AssetDatabase.GetAssetPath(folder), assetType);
|
||||
|
||||
foreach (var (lineID, assetPath) in idsToAssetPaths)
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath(assetPath, assetType);
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
// Not the type of asset we're looking for
|
||||
continue;
|
||||
}
|
||||
|
||||
assetTableCollection.AddAssetToTable(locale.Identifier, lineID, asset);
|
||||
|
||||
perLocaleCount += 1;
|
||||
totalCount += 1;
|
||||
}
|
||||
EditorUtility.SetDirty(assetTableCollection);
|
||||
Debug.Log($"Added {perLocaleCount} assets to {locale.LocaleName}");
|
||||
}
|
||||
Debug.Log($"Added {totalCount} assets to asset table collection");
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2c8a684ed88e47a083d7334e5f24ebc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/AddAssetsToAssetTableCollectionWizard.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5952ec9e417d4f3fbfdd8e329bd608f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<ui:Label text="Label" display-tooltip-when-elided="true" name="Title" />
|
||||
<ui:Label text="Label" display-tooltip-when-elided="true" name="Subtitle" />
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90cfaddaa17c84dc79cd95f4448553b2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Commands/CommandElement.uxml
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Yarn.Unity;
|
||||
|
||||
internal class CommandsCollection : IActionRegistration
|
||||
{
|
||||
public List<Actions.CommandRegistration> commandRegistrations = new List<Actions.CommandRegistration>();
|
||||
|
||||
public List<(string Name, Delegate Function)> functionRegistrations = new List<(string Name, Delegate Function)>();
|
||||
|
||||
public IEnumerable<CommandsWindow.IListItem> GetListItems()
|
||||
{
|
||||
foreach (var registrationMethod in Actions.ActionRegistrationMethods)
|
||||
{
|
||||
registrationMethod.Invoke(this, RegistrationType.Compilation);
|
||||
}
|
||||
|
||||
yield return new CommandsWindow.HeaderListItem("Commands");
|
||||
|
||||
foreach (var command in commandRegistrations)
|
||||
{
|
||||
yield return new CommandsWindow.CommandListItem(command);
|
||||
}
|
||||
|
||||
// Add a fake 'stop' command to the list, so that it appears in the
|
||||
// window
|
||||
System.Action fakeStop = () => { };
|
||||
yield return new CommandsWindow.CommandListItem(new Actions.CommandRegistration("stop", fakeStop));
|
||||
}
|
||||
|
||||
public void AddCommandHandler(string commandName, Delegate handler)
|
||||
{
|
||||
commandRegistrations.Add(new Actions.CommandRegistration(commandName, handler));
|
||||
|
||||
}
|
||||
|
||||
public void AddCommandHandler(string commandName, MethodInfo methodInfo)
|
||||
{
|
||||
commandRegistrations.Add(new Actions.CommandRegistration(commandName, methodInfo));
|
||||
}
|
||||
|
||||
public void AddFunction(string name, Delegate implementation) => functionRegistrations.Add((name, implementation));
|
||||
|
||||
public void RemoveCommandHandler(string commandName)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
public void RemoveFunction(string name)
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
public void RegisterFunctionDeclaration(string name, Type returnType, Type[] parameterTypes)
|
||||
{
|
||||
/* TODO: Implement */
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandsWindow : EditorWindow
|
||||
{
|
||||
public interface IListItem { string DisplayName { get; } }
|
||||
|
||||
public class HeaderListItem : IListItem
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public HeaderListItem(string displayName)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandListItem : IListItem
|
||||
{
|
||||
internal Actions.CommandRegistration Command;
|
||||
|
||||
internal CommandListItem(Actions.CommandRegistration command)
|
||||
{
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public string DisplayName => Command.Name;
|
||||
}
|
||||
|
||||
[SerializeField] private VisualTreeAsset? uxml;
|
||||
[SerializeField] private VisualTreeAsset? listItemUXML;
|
||||
[SerializeField] private StyleSheet? stylesheet;
|
||||
|
||||
private List<IListItem> listItems = new();
|
||||
private List<IListItem> filteredListItems = new();
|
||||
|
||||
[MenuItem("Window/Yarn Spinner/Commands...")]
|
||||
static void Summon()
|
||||
{
|
||||
var window = GetWindow<CommandsWindow>("Yarn Commands");
|
||||
window.Show();
|
||||
}
|
||||
|
||||
void CreateGUI()
|
||||
{
|
||||
if (uxml == null)
|
||||
{
|
||||
Debug.LogWarning($"{GetType()}'s {nameof(uxml)} is null");
|
||||
return;
|
||||
}
|
||||
uxml.CloneTree(rootVisualElement);
|
||||
var listView = rootVisualElement.Q<ListView>();
|
||||
|
||||
var searchField = rootVisualElement.Q<UnityEditor.UIElements.ToolbarSearchField>();
|
||||
|
||||
searchField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
UpdateFilter(listView, searchField.value);
|
||||
});
|
||||
|
||||
var commandsCollection = new CommandsCollection();
|
||||
|
||||
listItems = new List<IListItem>(commandsCollection.GetListItems().OrderBy(item => item.DisplayName));
|
||||
|
||||
UpdateFilter(listView, searchField.value);
|
||||
|
||||
// Set ListView.makeItem to initialize each entry in the list.
|
||||
listView.makeItem = () =>
|
||||
{
|
||||
if (listItemUXML == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't create new list item: {nameof(listItemUXML)} is null");
|
||||
}
|
||||
|
||||
var result = listItemUXML.CloneTree();
|
||||
result.styleSheets.Add(stylesheet);
|
||||
result.AddToClassList("commandListItem");
|
||||
return result;
|
||||
};
|
||||
|
||||
// Set ListView.bindItem to bind an initialized entry to a data item.
|
||||
listView.bindItem = (VisualElement element, int index) =>
|
||||
{
|
||||
var listItem = filteredListItems[index];
|
||||
element.Q<Label>("Title").text = listItem.DisplayName;
|
||||
|
||||
element.RemoveFromClassList("header");
|
||||
element.RemoveFromClassList("command");
|
||||
if (listItem is HeaderListItem)
|
||||
{
|
||||
element.AddToClassList("header");
|
||||
}
|
||||
else if (listItem is CommandListItem command)
|
||||
{
|
||||
element.AddToClassList("command");
|
||||
element.Q<Label>("Subtitle").text = "<<" + command.Command.UsageString + ">>";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateFilter(ListView listView, string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
filteredListItems = listItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
filteredListItems = listItems.Where(item =>
|
||||
{
|
||||
if (item is HeaderListItem)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (item is CommandListItem command)
|
||||
{
|
||||
return command.Command.Name.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) != -1;
|
||||
}
|
||||
return true;
|
||||
}).ToList();
|
||||
}
|
||||
listView.itemsSource = filteredListItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 280f575059ceb49eabeb009efa8936bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_ViewDataDictionary: {instanceID: 0}
|
||||
- uxml: {fileID: 9197481963319205126, guid: e71e992188faa4d22b8bdd4b60f0b7bf, type: 3}
|
||||
- listItemUXML: {fileID: 9197481963319205126, guid: 90cfaddaa17c84dc79cd95f4448553b2,
|
||||
type: 3}
|
||||
- stylesheet: {fileID: 7433441132597879392, guid: f8653a3e6bb8c4c45aa986ef57baedbb,
|
||||
type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Commands/CommandsWindow.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,18 @@
|
||||
.header #Title {
|
||||
-unity-font-style: bold;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.command {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.header #Subtitle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.command #Subtitle {
|
||||
white-space: normal;
|
||||
padding-left: 20px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8653a3e6bb8c4c45aa986ef57baedbb
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Commands/CommandsWindow.uss
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,6 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<uie:Toolbar>
|
||||
<uie:ToolbarSearchField focusable="true" style="flex-grow: 1;" />
|
||||
</uie:Toolbar>
|
||||
<ui:ListView focusable="true" fixed-item-height="20" selection-type="None" virtualization-method="DynamicHeight" />
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e71e992188faa4d22b8bdd4b60f0b7bf
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Commands/CommandsWindow.uxml
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d3f060740e1c4baab87c4307c7cc019
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/DialogueRunnerEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 070c401d8278244788305513453ac71a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92b7f4329f39c4b93b9f87a50beb4989
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,148 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37811d3829b0bfc42bfcd782271d279f
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/Asset Icons/LineMetadata
|
||||
Icon.png
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2cbba4ddd142149b0a38697070990deb
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/Asset Icons/Localization
|
||||
Icon.png
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd59b44bd3514406197f8ceb53547969
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/Asset Icons/LocalizationDatabase
|
||||
Icon.png
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6a533d9225cd40ea9ded31d4f686e3b
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/Asset Icons/YarnProject
|
||||
Icon.png
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 6.3 KiB |
@@ -0,0 +1,135 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ed312066ea6f40f6af965f21c818b34
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 1
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/Asset Icons/YarnScript
|
||||
Icon.png
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,134 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eb29ddb696b54505b296d1c7a049150
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerEditorWindow.psd
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,134 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 528a6dd601766934abb8b1053bd798ef
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 1
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 1
|
||||
swizzle: 50462976
|
||||
cookieLightType: 1
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Server
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogo.png
|
||||
uploadId: 968678
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,124 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16f8cd23bf0d0480bb8ecc39be853cda
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 4
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 4
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
customData:
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spriteCustomMetadata:
|
||||
entries: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogoFull.png
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
|
||||
[CustomEditor(typeof(InMemoryVariableStorage))]
|
||||
public class InMemoryVariableStorageEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
var varStorage = (InMemoryVariableStorage)target;
|
||||
|
||||
varStorage.showDebug = EditorGUILayout.Foldout(varStorage.showDebug, "Debug Variables");
|
||||
|
||||
if (!varStorage.showDebug)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Not in Play Mode, so no variables to display!", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
var style = EditorStyles.label;
|
||||
var list = varStorage.GetDebugList();
|
||||
var height = style.CalcHeight(new GUIContent(list), EditorGUIUtility.currentViewWidth);
|
||||
EditorGUILayout.SelectableLabel(list, GUILayout.MaxHeight(height), GUILayout.ExpandHeight(true));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 230a34f0c8ffc4b45b5f098c65d69492
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/InMemoryVariableStorageEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public class LanguageField : BaseField<string>
|
||||
{
|
||||
PopupField<string?> m_Popup;
|
||||
TextField m_TextField;
|
||||
|
||||
Dictionary<string, Culture> KnownCultures = new Dictionary<string, Culture>();
|
||||
CultureInfo? DefaultCulture;
|
||||
|
||||
public LanguageField() : this(null, false) { }
|
||||
|
||||
|
||||
public LanguageField(string? label, bool onlyNeutralCultures = false) : base(label, new Label() { })
|
||||
{
|
||||
var container = new VisualElement();
|
||||
container.style.flexDirection = FlexDirection.Column;
|
||||
container.style.flexGrow = 1;
|
||||
Add(container);
|
||||
// This is the input element instantiated for the base constructor.
|
||||
|
||||
KnownCultures = Cultures.GetCultures().Where(c => !onlyNeutralCultures || c.IsNeutralCulture).ToDictionary(kv => kv.Name);
|
||||
|
||||
DefaultCulture = System.Globalization.CultureInfo.CurrentCulture;
|
||||
|
||||
if (onlyNeutralCultures && DefaultCulture.IsNeutralCulture == false)
|
||||
{
|
||||
DefaultCulture = DefaultCulture.Parent;
|
||||
}
|
||||
|
||||
var cultureChoices = KnownCultures.Keys.Prepend(null).ToList();
|
||||
|
||||
static string FormatCulture(string? cultureName)
|
||||
{
|
||||
if (cultureName == null)
|
||||
{
|
||||
return "Custom";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Cultures.TryGetCulture(cultureName, out var culture)
|
||||
? $"{culture.DisplayName} ({culture.Name})"
|
||||
: cultureName;
|
||||
}
|
||||
}
|
||||
|
||||
m_Popup = new PopupField<string?>(null, cultureChoices, DefaultCulture.Name, FormatCulture, FormatCulture);
|
||||
|
||||
m_Popup.style.flexGrow = 1;
|
||||
|
||||
m_Popup.RegisterValueChangedCallback(OnPopupValueChanged);
|
||||
|
||||
container.Add(m_Popup);
|
||||
|
||||
m_TextField = new TextField();
|
||||
m_TextField.style.flexGrow = 1;
|
||||
m_TextField.RegisterValueChangedCallback(OnTextFieldValueChanged);
|
||||
container.Add(m_TextField);
|
||||
|
||||
m_Popup.style.marginRight = 0;
|
||||
m_TextField.style.marginRight = 0;
|
||||
|
||||
this.style.flexGrow = 1;
|
||||
|
||||
//m_Input.RegisterValueChangedCallback(OnValueChanged);
|
||||
//m_Input2.RegisterValueChangedCallback(OnValueChanged);
|
||||
}
|
||||
|
||||
public override string value
|
||||
{
|
||||
get => base.value; set
|
||||
{
|
||||
Debug.Log($"Language value changed from {base.value} to {value}");
|
||||
base.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTextFieldValueChanged(ChangeEvent<string> evt)
|
||||
{
|
||||
this.value = evt.newValue;
|
||||
}
|
||||
|
||||
void OnPopupValueChanged(ChangeEvent<string?> evt)
|
||||
{
|
||||
if (evt.newValue != null)
|
||||
{
|
||||
this.value = evt.newValue;
|
||||
m_TextField.style.display = DisplayStyle.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The popup has changed to the 'custom' value; show the text field
|
||||
m_TextField.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetValueWithoutNotify(string newValue)
|
||||
{
|
||||
m_TextField.value = newValue;
|
||||
|
||||
if (m_TextField.focusController?.focusedElement == m_TextField)
|
||||
{
|
||||
// The text field has focus; do not change its visibility
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TextField.style.display = (!KnownCultures.ContainsKey(newValue) || m_Popup.value == null) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
if (KnownCultures.ContainsKey(newValue))
|
||||
{
|
||||
m_Popup.SetValueWithoutNotify(newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Popup.SetValueWithoutNotify(null);
|
||||
}
|
||||
|
||||
base.SetValueWithoutNotify(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LanguagePopup
|
||||
{
|
||||
// TODO: Remove, not needed in Unity 2022
|
||||
public static T ReplaceElement<T>(VisualElement oldElement, T newElement) where T : VisualElement
|
||||
{
|
||||
oldElement.parent.Insert(oldElement.parent.IndexOf(oldElement) + 1, newElement);
|
||||
oldElement.RemoveFromHierarchy();
|
||||
return newElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afcc06473aee040aa87e08d80c09c981
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/LanguagePopup.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity.Attributes;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
|
||||
[CustomPropertyDrawer(typeof(LanguageAttribute))]
|
||||
public class LanguageAttributeEditor : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
using (var scope = new EditorGUI.PropertyScope(position, label, property))
|
||||
{
|
||||
// If this property is not a string, show an error label. (We
|
||||
// can't call EditorGUI.PropertyField, because that would cause
|
||||
// an infinite recursion - Unity would invoke this property
|
||||
// drawer again.)
|
||||
if (property.propertyType != SerializedPropertyType.String)
|
||||
{
|
||||
EditorGUI.HelpBox(position, $"{property.name} is not a string.", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Display this property as a dropdown that lets you select a
|
||||
// language.
|
||||
var allCultures = Cultures.GetCultures().ToList();
|
||||
var indices = Enumerable.Range(0, allCultures.Count());
|
||||
|
||||
var culturesToIndicies = allCultures.Zip(indices, (culture, index) => new { culture, index }).ToDictionary(pair => pair.culture.Name, pair => pair.index);
|
||||
|
||||
var value = property.stringValue;
|
||||
|
||||
int currentCultureIndex;
|
||||
|
||||
if (culturesToIndicies.ContainsKey(value))
|
||||
{
|
||||
currentCultureIndex = culturesToIndicies[value];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The property doesn't contain a valid culture name. Show
|
||||
// an 'empty' value, which will be replaced when the user
|
||||
// selects a valid value from the dropdown.
|
||||
currentCultureIndex = -1;
|
||||
}
|
||||
|
||||
var allCultureDisplayNames = allCultures.Select(c => (c.DisplayName + $":({c.Name})")).Select(n => new GUIContent(n)).ToArray();
|
||||
|
||||
using (var changeCheck = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var selectedIndex = EditorGUI.Popup(position, label, currentCultureIndex, allCultureDisplayNames);
|
||||
if (changeCheck.changed)
|
||||
{
|
||||
property.stringValue = allCultures[selectedIndex].Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 321b50cd267214a08ba7310de9a39764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/LanguagePropertyAttributeEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets;
|
||||
#endif
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
internal class ImportLocalizationFromAssetWindow : EditorWindow
|
||||
{
|
||||
private System.Type? assetType;
|
||||
|
||||
public LocalizationEditor? Target { get; private set; }
|
||||
|
||||
public string FieldLabel { get; set; } = "Source Asset";
|
||||
public string? HelpBox { get; set; }
|
||||
|
||||
public static ImportLocalizationFromAssetWindow Show<T>(LocalizationEditor target, string windowTitle, System.Action<T> onImport) where T : UnityEngine.Object
|
||||
{
|
||||
var window = EditorWindow.GetWindow<ImportLocalizationFromAssetWindow>(true, windowTitle);
|
||||
window.Target = target;
|
||||
window.assetType = typeof(T);
|
||||
window.maxSize = new Vector2(300, 200);
|
||||
window.onImport = (Object obj) => onImport((T)obj);
|
||||
window.ShowUtility();
|
||||
return window;
|
||||
}
|
||||
|
||||
UnityEngine.Object? asset = null;
|
||||
private System.Action<UnityEngine.Object>? onImport;
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
// Our target went away; close this window
|
||||
this.Close();
|
||||
}
|
||||
|
||||
asset = EditorGUILayout.ObjectField(FieldLabel, asset, assetType, allowSceneObjects: false);
|
||||
|
||||
if (string.IsNullOrEmpty(this.HelpBox) == false)
|
||||
{
|
||||
EditorGUILayout.HelpBox(this.HelpBox, MessageType.Info);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
using (new EditorGUI.DisabledScope(asset == null))
|
||||
{
|
||||
if (GUILayout.Button("Import") && asset != null)
|
||||
{
|
||||
onImport?.Invoke(asset);
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[CustomEditor(typeof(Localization))]
|
||||
[CanEditMultipleObjects]
|
||||
public class LocalizationEditor : UnityEditor.Editor
|
||||
{
|
||||
private SerializedProperty? entriesProperty;
|
||||
private SerializedProperty? usesUnityAddressablesProperty;
|
||||
private AudioClip? lastPreviewed;
|
||||
private List<Culture>? cultures;
|
||||
private int currentPickerWindow;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
entriesProperty = serializedObject.FindProperty(nameof(Localization.entries));
|
||||
usesUnityAddressablesProperty = serializedObject.FindProperty(nameof(Localization._usesAddressableAssets));
|
||||
lastPreviewed = null;
|
||||
cultures = Cultures.GetCultures().ToList();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Target is not a {typeof(Localization)}");
|
||||
}
|
||||
|
||||
var isSubAsset = AssetDatabase.IsSubAsset(target);
|
||||
|
||||
if (serializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Select a single {nameof(Localization).ToLowerInvariant()} to view its contents.", MessageType.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isSubAsset)
|
||||
{
|
||||
DrawLocalizationContentsPreview(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
EditorGUILayout.PropertyField(usesUnityAddressablesProperty);
|
||||
EditorGUILayout.Space();
|
||||
#else
|
||||
if (usesUnityAddressablesProperty != null && usesUnityAddressablesProperty.boolValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox("This Localization uses Unity Addressables, but the package is not installed.", MessageType.Warning);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
#endif
|
||||
if (GUILayout.Button("Import String from Yarn Project"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<YarnProject>(this, "Import from Yarn Project", ImportFromYarnProject);
|
||||
window.FieldLabel = "Yarn Project";
|
||||
window.HelpBox = $"The lines in the base localisation of the selected Yarn Project will be imported into this {nameof(Localization)}.";
|
||||
}
|
||||
if (GUILayout.Button("Import Strings from CSV"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<TextAsset>(this, "Import from Yarn Project", ImportFromCSV);
|
||||
window.FieldLabel = "CSV File";
|
||||
window.HelpBox = $"The string table entries from the selected CSV file will be imported into this {nameof(Localization)}.\n\nYou can generate a CSV file to use by selecting the Yarn Project and clicking {YarnProjectImporterEditor.AddStringTagsButtonLabel}. You can then translate the CSV file into your target language, and then import it using this window.";
|
||||
}
|
||||
if (GUILayout.Button("Import Assets from Folder"))
|
||||
{
|
||||
var window = ImportLocalizationFromAssetWindow.Show<DefaultAsset>(this, "Import from Yarn Project", (folder) =>
|
||||
{
|
||||
var lineIDs = target.entries.Keys;
|
||||
var paths = YarnProjectUtility.FindAssetPathsForLineIDs(lineIDs, AssetDatabase.GetAssetPath(folder), typeof(UnityEngine.Object));
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var lineID = path.Key;
|
||||
var assetPath = path.Value;
|
||||
|
||||
var asset = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
|
||||
target.AddLocalizedObjectToAsset<UnityEngine.Object>(lineID, asset);
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
if (target.UsesAddressableAssets)
|
||||
{
|
||||
// If we're using addressable assets, make
|
||||
// sure that the asset we just added has an
|
||||
// address
|
||||
EnsureAssetIsAddressable(asset, Localization.GetAddressForLine(lineID, target.name));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
});
|
||||
window.FieldLabel = "Folder";
|
||||
}
|
||||
EditorGUILayout.PropertyField(entriesProperty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (serializedObject.hasModifiedProperties)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays the contents of <paramref name="target"/> as a table.
|
||||
/// </summary>
|
||||
/// <param name="target">The <see cref="Localization"/> to show the
|
||||
/// contents of.</param>
|
||||
/// <param name="showAssets">If true, this method will show any
|
||||
/// assets or addressable assets. If false, this method will only
|
||||
/// show the localized text.</param>
|
||||
private void DrawLocalizationContentsPreview(Localization target)
|
||||
{
|
||||
var lineKeys = target.GetLineIDs();
|
||||
|
||||
// Early out if we don't have any lines
|
||||
if (lineKeys.Count() == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"This {nameof(Localization).ToLowerInvariant()} does not contain any lines.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
var localizedLineContent = new List<(string ID, string Line, Object? Asset)>();
|
||||
|
||||
var anyAssetsFound = false;
|
||||
|
||||
foreach (var key in lineKeys)
|
||||
{
|
||||
|
||||
if (target.entries.TryGetValue(key, out var entry) == false)
|
||||
{
|
||||
// We somehow don't have a value for this line ID?
|
||||
Debug.LogError($"Internal error: failed to find an entry for {key}");
|
||||
EditorGUILayout.HelpBox($"Internal error: failed to find an entry for {key}", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string? text = target.GetLocalizedString(key);
|
||||
Object? asset = null;
|
||||
|
||||
if (target.UsesAddressableAssets)
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
asset = entry.localizedAssetReference?.editorAsset;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
asset = entry.localizedAsset;
|
||||
}
|
||||
|
||||
anyAssetsFound |= asset != null;
|
||||
|
||||
localizedLineContent.Add((key, text ?? string.Empty, asset));
|
||||
}
|
||||
|
||||
foreach (var entry in localizedLineContent)
|
||||
{
|
||||
|
||||
var idContent = new GUIContent(entry.ID);
|
||||
|
||||
// Create a GUIContent that contains the string as its text
|
||||
// and also as its tooltip. This allows the user to mouse
|
||||
// over this line in the inspector and see more of it.
|
||||
var lineContent = new GUIContent(entry.Line, entry.Line);
|
||||
|
||||
// Show the line ID and localized text
|
||||
EditorGUILayout.LabelField(idContent, lineContent);
|
||||
|
||||
if (entry.Asset != null)
|
||||
{
|
||||
// Asset references are never editable here - they're
|
||||
// only updated by the Localization Database. Add a
|
||||
// DisabledGroup here to make all ObjectFields be
|
||||
// interactable, but read-only.
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
|
||||
// Show the object field
|
||||
EditorGUILayout.ObjectField(" ", entry.Asset, typeof(UnityEngine.Object), false);
|
||||
|
||||
// for AudioClips, add a little play preview button
|
||||
if (entry.Asset.GetType() == typeof(UnityEngine.AudioClip))
|
||||
{
|
||||
var rect = GUILayoutUtility.GetLastRect();
|
||||
|
||||
// Localization assets are displayed in an
|
||||
// Inspector that's always disabled, so we need to
|
||||
// manually set the enabled flag to 'true' in order
|
||||
// to let this button be clickable. We'll restore
|
||||
// it after we handle this button.
|
||||
var wasEnabled = GUI.enabled;
|
||||
GUI.enabled = true;
|
||||
|
||||
bool isPlaying = IsClipPlaying((AudioClip)entry.Asset);
|
||||
if (lastPreviewed == (AudioClip)entry.Asset && isPlaying)
|
||||
{
|
||||
rect.width = 54;
|
||||
rect.x += EditorGUIUtility.labelWidth - 56;
|
||||
|
||||
if (GUI.Button(rect, "▣ Stop"))
|
||||
{
|
||||
StopAllClips();
|
||||
lastPreviewed = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.width = 18;
|
||||
rect.x += EditorGUIUtility.labelWidth - 20;
|
||||
if (GUI.Button(rect, "▸"))
|
||||
{
|
||||
PlayClip((AudioClip)entry.Asset);
|
||||
lastPreviewed = (AudioClip)entry.Asset;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the enabled state
|
||||
GUI.enabled = wasEnabled;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
else if (anyAssetsFound)
|
||||
{
|
||||
// Other entries have assets, but not this one. TODO:
|
||||
// show a warning? probably need to make it really
|
||||
// prominent, and possibly allow filtering this view to
|
||||
// show only lines that have no assets?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// below is some terrible reflection needed for the AudioClip
|
||||
// preview terrible hack from
|
||||
// https://forum.unity.com/threads/way-to-play-audio-in-editor-using-an-editor-script.132042/#post-4767824
|
||||
public static void PlayClip(AudioClip clip, int startSample = 0, bool loop = false)
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
// The name of the method we want to invoke changed in 2020.2,
|
||||
// so we'll do a little version testing here
|
||||
string methodName;
|
||||
|
||||
methodName = "PlayPreviewClip";
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
methodName,
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
|
||||
null,
|
||||
new System.Type[] { typeof(AudioClip), typeof(int), typeof(bool) },
|
||||
null
|
||||
);
|
||||
method.Invoke(
|
||||
null,
|
||||
new object[] { clip, startSample, loop }
|
||||
);
|
||||
}
|
||||
|
||||
public static void StopAllClips()
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
// The name of the method we want to invoke changed in 2020.2,
|
||||
// so we'll do a little version testing here
|
||||
string methodName = "StopAllPreviewClips";
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
methodName,
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
|
||||
null,
|
||||
new System.Type[] { },
|
||||
null
|
||||
);
|
||||
method.Invoke(
|
||||
null,
|
||||
new object[] { }
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsClipPlaying(AudioClip clip)
|
||||
{
|
||||
System.Reflection.Assembly unityEditorAssembly = typeof(AudioImporter).Assembly;
|
||||
System.Type audioUtilClass = unityEditorAssembly.GetType("UnityEditor.AudioUtil");
|
||||
|
||||
System.Reflection.MethodInfo method = audioUtilClass.GetMethod(
|
||||
"IsPreviewClipPlaying",
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public
|
||||
);
|
||||
return (bool)method.Invoke(
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
internal void ImportFromYarnProject(YarnProject project)
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lineIDs = project.baseLocalization.GetLineIDs();
|
||||
|
||||
target.UsesAddressableAssets = project.baseLocalization.UsesAddressableAssets;
|
||||
|
||||
foreach (var (id, entry) in project.baseLocalization.entries)
|
||||
{
|
||||
var localizedString = entry.localizedString;
|
||||
if (localizedString != null)
|
||||
{
|
||||
target.AddLocalisedStringToAsset(id, localizedString);
|
||||
}
|
||||
|
||||
Object? asset = null;
|
||||
|
||||
if (project.baseLocalization.UsesAddressableAssets)
|
||||
{
|
||||
#if USE_ADDRESSABLES
|
||||
asset = entry.localizedAssetReference?.editorAsset;
|
||||
#endif
|
||||
}
|
||||
else if (entry.localizedAsset != null)
|
||||
{
|
||||
asset = entry.localizedAsset;
|
||||
}
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
target.AddLocalizedObjectToAsset(id, asset);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
}
|
||||
|
||||
internal void ImportFromCSV(TextAsset asset)
|
||||
{
|
||||
var target = this.target as Localization;
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var stringTable = StringTableEntry.ParseFromCSV(asset.text);
|
||||
|
||||
foreach (var entry in stringTable)
|
||||
{
|
||||
target.AddLocalisedStringToAsset(entry.ID, entry.Text ?? string.Empty);
|
||||
}
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
AssetDatabase.SaveAssetIfDirty(target);
|
||||
|
||||
}
|
||||
catch (System.ArgumentException e)
|
||||
{
|
||||
Debug.LogWarning($"Failed to import localization from CSV because an error was encountered during text parsing: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
internal static void EnsureAssetIsAddressable(Object asset, string defaultAddress)
|
||||
{
|
||||
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out string guid, out long _) == false)
|
||||
{
|
||||
Debug.LogError($"Can't make {asset} addressable: no GUID found", asset);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the existing entry for this asset, if it has one.
|
||||
UnityEditor.AddressableAssets.Settings.AddressableAssetEntry entry = AddressableAssetSettingsDefaultObject.Settings.FindAssetEntry(guid);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
// The asset already has an entry. Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// This asset didn't have an entry. Create one in the default group.
|
||||
Debug.Log($"Marking asset {AssetDatabase.GetAssetPath(asset)} as addressable", asset);
|
||||
|
||||
entry = AddressableAssetSettingsDefaultObject.Settings.CreateOrMoveEntry(guid, AddressableAssetSettingsDefaultObject.Settings.DefaultGroup);
|
||||
|
||||
// Update the entry's address.
|
||||
entry.SetAddress(defaultAddress);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d221cff8c71dc4726a348d8b718becaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/LocalizationEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public class LocalizationEntryElement : VisualElement, INotifyValueChanged<ProjectImportData.LocalizationEntry>
|
||||
{
|
||||
private readonly Foldout foldout;
|
||||
private readonly ObjectField assetFolderField;
|
||||
private readonly ObjectField stringsFileField;
|
||||
private readonly Button deleteButton;
|
||||
private readonly VisualElement stringsFileNotUsedLabel;
|
||||
private readonly LanguageField languagePopup;
|
||||
private readonly Toggle isExternalAssetToggle;
|
||||
private readonly ObjectField externalLocalisationAssetField;
|
||||
private readonly VisualElement externalReferenceFields;
|
||||
private readonly VisualElement internallyGeneratedAssetFields;
|
||||
public event System.Action? OnDelete;
|
||||
ProjectImportData.LocalizationEntry data;
|
||||
|
||||
public bool IsModified { get; private set; }
|
||||
|
||||
private string _projectBaseLanguage;
|
||||
public string ProjectBaseLanguage
|
||||
{
|
||||
get => _projectBaseLanguage;
|
||||
set
|
||||
{
|
||||
_projectBaseLanguage = value;
|
||||
SetValueWithoutNotify(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
public LocalizationEntryElement(VisualTreeAsset asset, ProjectImportData.LocalizationEntry data, string baseLanguage)
|
||||
{
|
||||
asset.CloneTree(this);
|
||||
|
||||
foldout = this.Q<Foldout>("foldout");
|
||||
assetFolderField = this.Q<ObjectField>("assetFolder");
|
||||
stringsFileField = this.Q<ObjectField>("stringsFile");
|
||||
deleteButton = this.Q<Button>("deleteButton");
|
||||
stringsFileNotUsedLabel = this.Q("stringsFileNotUsed");
|
||||
isExternalAssetToggle = this.Q<Toggle>("isExternalAsset");
|
||||
externalLocalisationAssetField = this.Q<ObjectField>("externalLocalisationAsset");
|
||||
externalReferenceFields = this.Q<VisualElement>("externalReferenceFields");
|
||||
internallyGeneratedAssetFields = this.Q<VisualElement>("internallyGeneratedAssetFields");
|
||||
|
||||
assetFolderField.objectType = typeof(DefaultAsset);
|
||||
stringsFileField.objectType = typeof(TextAsset);
|
||||
|
||||
IsModified = false;
|
||||
|
||||
// Dropdowns don't exist in Unity 2019/20(?), so we need to create
|
||||
// one at runtime and swap out a placeholder.
|
||||
var existingPopup = this.Q("languagePlaceholder");
|
||||
languagePopup = new LanguageField("Language");
|
||||
LanguagePopup.ReplaceElement(existingPopup, languagePopup);
|
||||
|
||||
_projectBaseLanguage = baseLanguage;
|
||||
|
||||
|
||||
languagePopup.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
var newEntry = this.value;
|
||||
newEntry.languageID = evt.newValue;
|
||||
this.value = newEntry;
|
||||
});
|
||||
|
||||
isExternalAssetToggle.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
var newEntry = this.value;
|
||||
newEntry.isExternal = evt.newValue;
|
||||
this.value = newEntry;
|
||||
});
|
||||
externalLocalisationAssetField.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
var newEntry = this.value;
|
||||
newEntry.externalLocalization = evt.newValue as Localization;
|
||||
this.value = newEntry;
|
||||
});
|
||||
|
||||
|
||||
stringsFileField.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
var newEntry = this.value;
|
||||
newEntry.stringsFile = evt.newValue as TextAsset;
|
||||
this.value = newEntry;
|
||||
});
|
||||
assetFolderField.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
var newEntry = this.value;
|
||||
newEntry.assetsFolder = evt.newValue as DefaultAsset;
|
||||
this.value = newEntry;
|
||||
});
|
||||
|
||||
deleteButton.clicked += () => OnDelete?.Invoke();
|
||||
|
||||
SetValueWithoutNotify(data);
|
||||
|
||||
}
|
||||
|
||||
public ProjectImportData.LocalizationEntry value
|
||||
{
|
||||
get => data;
|
||||
set
|
||||
{
|
||||
var previous = data;
|
||||
SetValueWithoutNotify(value);
|
||||
using (var evt = ChangeEvent<ProjectImportData.LocalizationEntry>.GetPooled(previous, value))
|
||||
{
|
||||
evt.target = this;
|
||||
SendEvent(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValueWithoutNotify(ProjectImportData.LocalizationEntry data)
|
||||
{
|
||||
this.data = data;
|
||||
Culture culture;
|
||||
var foundCulture = Cultures.TryGetCulture(data.languageID, out culture);
|
||||
|
||||
string foldoutDisplayName = foundCulture ? $"{culture.DisplayName} ({culture.Name})" : $"{data.languageID}";
|
||||
|
||||
languagePopup.SetValueWithoutNotify(data.languageID);
|
||||
assetFolderField.SetValueWithoutNotify(data.assetsFolder);
|
||||
stringsFileField.SetValueWithoutNotify(data.stringsFile);
|
||||
isExternalAssetToggle.SetValueWithoutNotify(data.isExternal);
|
||||
externalLocalisationAssetField.SetValueWithoutNotify(data.externalLocalization);
|
||||
|
||||
bool isBaseLanguage = data.languageID == ProjectBaseLanguage;
|
||||
|
||||
if (isBaseLanguage)
|
||||
{
|
||||
stringsFileField.style.display = DisplayStyle.None;
|
||||
stringsFileNotUsedLabel.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringsFileField.style.display = DisplayStyle.Flex;
|
||||
stringsFileNotUsedLabel.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
internallyGeneratedAssetFields.style.display = data.isExternal ? DisplayStyle.None : DisplayStyle.Flex;
|
||||
externalReferenceFields.style.display = data.isExternal ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
|
||||
deleteButton.SetEnabled(isBaseLanguage == false);
|
||||
|
||||
foldout.text = foldoutDisplayName;
|
||||
}
|
||||
|
||||
internal void ClearModified()
|
||||
{
|
||||
IsModified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0bb769319d8a44820b74cf1d9b6b87ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/LocalizationEntryElement.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09d33ebd4f63743da9e896351e1b7032
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
[CustomPropertyDrawer(typeof(MarkupPalette.BasicMarker))]
|
||||
public class BasicMarkerPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override VisualElement CreatePropertyGUI(SerializedProperty property)
|
||||
{
|
||||
var container = new VisualElement();
|
||||
|
||||
var name = property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Marker));
|
||||
|
||||
var nameField = new PropertyField(name);
|
||||
var showColourField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.CustomColor)));
|
||||
var colourField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Color)));
|
||||
var boldField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Boldened)));
|
||||
var italicsField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Italicised)));
|
||||
var underlinedField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Underlined)));
|
||||
var strikedField = new PropertyField(property.FindPropertyRelative(nameof(MarkupPalette.BasicMarker.Strikedthrough)));
|
||||
|
||||
var foldout = new Foldout { text = name.stringValue };
|
||||
|
||||
showColourField.RegisterCallback((ChangeEvent<bool> b) =>
|
||||
{
|
||||
colourField.style.display = b.newValue ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
});
|
||||
|
||||
foldout.Add(nameField);
|
||||
foldout.Add(showColourField);
|
||||
foldout.Add(colourField);
|
||||
foldout.Add(boldField);
|
||||
foldout.Add(italicsField);
|
||||
foldout.Add(underlinedField);
|
||||
foldout.Add(strikedField);
|
||||
|
||||
container.Add(foldout);
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eaeba2d10a544bf58c014880b8b71dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/BasicMarkerPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(YarnProjectImporter.SerializedDeclaration))]
|
||||
public class DeclarationPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws either a property field or a label field for <paramref
|
||||
/// name="property"/> at <paramref name="position"/>, depending on
|
||||
/// the value of <paramref name="readOnly"/>.
|
||||
/// </summary>
|
||||
/// <param name="position">The rectangle in which to draw the
|
||||
/// control.</param>
|
||||
/// <param name="property">The property to draw a control
|
||||
/// for.</param>
|
||||
/// <param name="readOnly">Whether the property is read-only or
|
||||
/// not.</param>
|
||||
private void DrawPropertyField(Rect position, SerializedProperty property, bool readOnly, string? label = null)
|
||||
{
|
||||
if (label == null)
|
||||
{
|
||||
label = property.displayName;
|
||||
}
|
||||
if (readOnly)
|
||||
{
|
||||
switch (property.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Integer:
|
||||
EditorGUI.LabelField(position, label, property.intValue.ToString());
|
||||
break;
|
||||
case SerializedPropertyType.Boolean:
|
||||
var boolText = property.boolValue ? "True" : "False";
|
||||
EditorGUI.LabelField(position, label, boolText);
|
||||
break;
|
||||
case SerializedPropertyType.Float:
|
||||
EditorGUI.LabelField(position, label, property.floatValue.ToString());
|
||||
break;
|
||||
case SerializedPropertyType.String:
|
||||
EditorGUI.LabelField(position, label, property.stringValue);
|
||||
break;
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
EditorGUI.ObjectField(position, property);
|
||||
}
|
||||
break;
|
||||
case SerializedPropertyType.Enum:
|
||||
var displayValue = property.enumDisplayNames[property.enumValueIndex];
|
||||
EditorGUI.LabelField(position, label, displayValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (property.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.String:
|
||||
property.stringValue = EditorGUI.TextField(position, label, property.stringValue);
|
||||
break;
|
||||
case SerializedPropertyType.Float:
|
||||
property.floatValue = EditorGUI.FloatField(position, label, property.floatValue);
|
||||
break;
|
||||
case SerializedPropertyType.Integer:
|
||||
property.floatValue = EditorGUI.IntField(position, label, property.intValue);
|
||||
break;
|
||||
default:
|
||||
// Just use a regular field for other kinds of
|
||||
// properties
|
||||
EditorGUI.PropertyField(position, property, new GUIContent(label));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
// A serialized declaration is read-only if it came from a Yarn
|
||||
// script. We don't allow editing those in this panel, because
|
||||
// the text of the Yarn script belongs to the user.
|
||||
bool propertyIsReadOnly = property.FindPropertyRelative("sourceYarnAsset").objectReferenceValue != null;
|
||||
|
||||
propertyIsReadOnly |= property.FindPropertyRelative("isImplicit").boolValue;
|
||||
|
||||
const float leftInset = 8;
|
||||
|
||||
Rect RectForFieldIndex(int index, int lineCount = 1)
|
||||
{
|
||||
float verticalOffset = EditorGUIUtility.singleLineHeight * index + EditorGUIUtility.standardVerticalSpacing * index;
|
||||
float height = EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount - 1);
|
||||
|
||||
return new Rect(
|
||||
position.x + leftInset,
|
||||
position.y + verticalOffset,
|
||||
position.width - leftInset,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
var foldoutPosition = RectForFieldIndex(0);
|
||||
|
||||
SerializedProperty nameProperty = property.FindPropertyRelative("name");
|
||||
string name = nameProperty.stringValue;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
name = "Variable";
|
||||
}
|
||||
|
||||
property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, name);
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
var namePosition = RectForFieldIndex(1);
|
||||
var typePosition = RectForFieldIndex(2);
|
||||
var defaultValuePosition = RectForFieldIndex(3);
|
||||
var descriptionPosition = RectForFieldIndex(4, 2);
|
||||
var sourcePosition = RectForFieldIndex(6);
|
||||
|
||||
DrawPropertyField(namePosition, nameProperty, propertyIsReadOnly);
|
||||
|
||||
SerializedProperty typeProperty = property.FindPropertyRelative("typeName");
|
||||
|
||||
if (propertyIsReadOnly)
|
||||
{
|
||||
DrawPropertyField(typePosition, typeProperty, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var popupElements = YarnProjectImporter.SerializedDeclaration.BuiltInTypesList;
|
||||
var popupElementNames = popupElements.Select(t => t.Name).ToList();
|
||||
var selectedIndex = popupElementNames.IndexOf(typeProperty.stringValue);
|
||||
|
||||
var prefixPosition = EditorGUI.PrefixLabel(typePosition, new GUIContent("Type"));
|
||||
|
||||
selectedIndex = EditorGUI.Popup(prefixPosition, selectedIndex, popupElementNames.ToArray());
|
||||
if (selectedIndex >= 0 && selectedIndex <= popupElementNames.Count)
|
||||
{
|
||||
typeProperty.stringValue = popupElementNames[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
SerializedProperty? defaultValueProperty;
|
||||
|
||||
var type = YarnProjectImporter.SerializedDeclaration.BuiltInTypesList.FirstOrDefault(t => t.Name == typeProperty.stringValue);
|
||||
|
||||
if (type == Types.Number)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueNumber");
|
||||
}
|
||||
else if (type == Types.String)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueString");
|
||||
}
|
||||
else if (type == Types.Boolean)
|
||||
{
|
||||
defaultValueProperty = property.FindPropertyRelative("defaultValueBool");
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValueProperty = null;
|
||||
}
|
||||
|
||||
|
||||
if (defaultValueProperty == null)
|
||||
{
|
||||
EditorGUI.LabelField(defaultValuePosition, "Default Value", $"Variable type {typeProperty.stringValue} is not allowed");
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawPropertyField(defaultValuePosition, defaultValueProperty, propertyIsReadOnly, "Default Value");
|
||||
}
|
||||
|
||||
|
||||
// Don't use DrawPropertyField here because we want to use
|
||||
// a special gui style and directly use the string value
|
||||
SerializedProperty descriptionProperty = property.FindPropertyRelative("description");
|
||||
if (propertyIsReadOnly)
|
||||
{
|
||||
descriptionPosition = EditorGUI.PrefixLabel(descriptionPosition, new GUIContent(descriptionProperty.displayName));
|
||||
EditorGUI.SelectableLabel(descriptionPosition, descriptionProperty.stringValue, EditorStyles.wordWrappedLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
var wordWrappedTextField = EditorStyles.textField;
|
||||
wordWrappedTextField.wordWrap = true;
|
||||
|
||||
descriptionProperty.stringValue = EditorGUI.TextField(descriptionPosition, descriptionProperty.displayName, descriptionProperty.stringValue, wordWrappedTextField);
|
||||
}
|
||||
|
||||
if (!propertyIsReadOnly)
|
||||
{
|
||||
EditorGUI.LabelField(sourcePosition, "Declared In", "this file");
|
||||
}
|
||||
else
|
||||
{
|
||||
SerializedProperty sourceProperty = property.FindPropertyRelative("sourceYarnAsset");
|
||||
EditorGUI.ObjectField(sourcePosition, "Declared In", sourceProperty.objectReferenceValue, typeof(TextAsset), false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
|
||||
return GetPropertyHeightImpl(property, label);
|
||||
}
|
||||
|
||||
public static float GetPropertyHeightImpl(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int lines;
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
lines = 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines = 1;
|
||||
}
|
||||
|
||||
return EditorGUIUtility.singleLineHeight * lines + EditorGUIUtility.standardVerticalSpacing * lines + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05c509d58b0f0441995b7356c9876e60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DeclarationPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(FunctionInfo))]
|
||||
public class DerivedFunctionsPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
const float leftInset = 8;
|
||||
|
||||
Rect RectForFieldIndex(int index, int lineCount = 1)
|
||||
{
|
||||
float verticalOffset = EditorGUIUtility.singleLineHeight * index + EditorGUIUtility.standardVerticalSpacing * index;
|
||||
float height = EditorGUIUtility.singleLineHeight * lineCount + EditorGUIUtility.standardVerticalSpacing * (lineCount - 1);
|
||||
|
||||
return new Rect(
|
||||
position.x + leftInset,
|
||||
position.y + verticalOffset,
|
||||
position.width - leftInset,
|
||||
height
|
||||
);
|
||||
}
|
||||
|
||||
var foldoutPosition = RectForFieldIndex(0);
|
||||
|
||||
SerializedProperty nameProperty = property.FindPropertyRelative("Name");
|
||||
string name = nameProperty?.stringValue ?? "FUNCTION NAME";
|
||||
|
||||
property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, name);
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
EditorGUI.indentLevel += 1;
|
||||
var typePosition = RectForFieldIndex(1);
|
||||
var paramPosition = RectForFieldIndex(2);
|
||||
|
||||
SerializedProperty typeProperty = property.FindPropertyRelative("ReturnType");
|
||||
EditorGUI.LabelField(typePosition, typeProperty?.stringValue ?? "RETURN");
|
||||
|
||||
SerializedProperty paramProperty = property.FindPropertyRelative("Parameters");
|
||||
int count = paramProperty?.arraySize ?? 0;
|
||||
if (count > 0)
|
||||
{
|
||||
string[] p = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
p[i] = paramProperty.GetArrayElementAtIndex(i).stringValue;
|
||||
}
|
||||
EditorGUI.LabelField(paramPosition, $"({string.Join(", ", p)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.LabelField(paramPosition, $"No Parameters");
|
||||
}
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
|
||||
int lines = 1;
|
||||
|
||||
if (property.isExpanded)
|
||||
{
|
||||
lines = 3;
|
||||
}
|
||||
|
||||
return EditorGUIUtility.singleLineHeight * lines + EditorGUIUtility.standardVerticalSpacing * lines + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ff5754fb8fe74e3fa7e65606e3feefa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DerivedFunctionsPropertyDrawer.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(DialogueReference))]
|
||||
public class DialogueReferenceDrawer : PropertyDrawer
|
||||
{
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
position = EditorGUI.PrefixLabel(position, label);
|
||||
|
||||
var projectProperty = property.FindPropertyRelative(nameof(DialogueReference.project));
|
||||
var nodeNameProperty = property.FindPropertyRelative(nameof(DialogueReference.nodeName));
|
||||
|
||||
position = GetLineRect(position, out var projectRect);
|
||||
position = GetLineRect(position, out var nodeNameRect);
|
||||
EditorGUI.PropertyField(projectRect, projectProperty, GUIContent.none);
|
||||
EditorGUI.PropertyField(nodeNameRect, nodeNameProperty, GUIContent.none);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a rectangle, computes a rectangle of the same width as the
|
||||
/// input with the height of a single line, taking into account vertical
|
||||
/// spacing.
|
||||
/// </summary>
|
||||
/// <param name="input">A rectangle representing the total area
|
||||
/// availalbe.</param>
|
||||
/// <param name="lineRect">On return, a rectangle with the same width as
|
||||
/// <paramref name="input"/> and with a single line's worth of
|
||||
/// height.</param>
|
||||
/// <returns>The remaining available space.</returns>
|
||||
private Rect GetLineRect(Rect input, out Rect lineRect)
|
||||
{
|
||||
lineRect = input;
|
||||
lineRect.height = EditorGUIUtility.singleLineHeight;
|
||||
|
||||
var remainder = input;
|
||||
var offset = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
|
||||
remainder.y += offset;
|
||||
remainder.height -= offset;
|
||||
return remainder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the height, in pixels, needed for drawing the inspector for
|
||||
/// a <see cref="DialogueReference"/>.
|
||||
/// </summary>
|
||||
/// <param name="property">A serialized property representing a <see
|
||||
/// cref="DialogueReference"/> object.</param>
|
||||
/// <param name="label">The label to display for <paramref
|
||||
/// name="property"/>.</param>
|
||||
/// <returns>The displayed height for the property.</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
const int lineCount = 2;
|
||||
return lineCount * EditorGUIUtility.singleLineHeight +
|
||||
(lineCount - 1) * EditorGUIUtility.standardVerticalSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2e67f1d1bf1140a6910d4cc0225235c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/DialogueReferenceDrawer.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,303 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity.Attributes;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
/// <summary>
|
||||
/// Property drawer for <see cref="DialogueReference"/>
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(YarnNodeAttribute))]
|
||||
public class YarnNodeAttributeDrawer : PropertyDrawer
|
||||
{
|
||||
private const string NodeTextControlNamePrefix = "DialogueReference.NodeName.";
|
||||
|
||||
private YarnProject? lastProject;
|
||||
private string? lastNodeName;
|
||||
private bool referenceExists;
|
||||
private bool editNodeAsText;
|
||||
private bool focusNodeTextField;
|
||||
|
||||
private GUIContent? nodenameContent;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// -- Yarn Project asset reference
|
||||
SerializedProperty projectProp;
|
||||
|
||||
if (this.attribute is not YarnNodeAttribute attribute)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Internal error: attribute is not a {nameof(YarnNodeAttribute)}");
|
||||
}
|
||||
|
||||
var propertyPathComponents = new System.Collections.Generic.Stack<string>(property.propertyPath.Split('.'));
|
||||
|
||||
while (true)
|
||||
{
|
||||
string testPath;
|
||||
|
||||
if (propertyPathComponents.Count == 0)
|
||||
{
|
||||
testPath = attribute.yarnProjectAttribute;
|
||||
}
|
||||
else
|
||||
{
|
||||
var components = new System.Collections.Generic.List<string>(propertyPathComponents);
|
||||
components.Reverse();
|
||||
|
||||
testPath = string.Join(".", components) + "." + attribute.yarnProjectAttribute;
|
||||
}
|
||||
|
||||
projectProp = property.serializedObject.FindProperty(testPath);
|
||||
|
||||
if (projectProp != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (propertyPathComponents.Count > 0)
|
||||
{
|
||||
propertyPathComponents.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (projectProp == null)
|
||||
{
|
||||
EditorGUI.HelpBox(position, $"{attribute.yarnProjectAttribute} does not exist on {property.serializedObject.targetObject.name}", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var controlId = GUIUtility.GetControlID(FocusType.Passive);
|
||||
position = EditorGUI.PrefixLabel(position, controlId, label);
|
||||
|
||||
var indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
var nodeNameFieldPosition = position;
|
||||
|
||||
var project = projectProp.hasMultipleDifferentValues ? null : projectProp.objectReferenceValue as YarnProject;
|
||||
|
||||
// -- Node name drop down
|
||||
|
||||
// If we want to edit this nodes name as a text field, or if we have
|
||||
// multiple values, or if we have no project and we don't need one,
|
||||
// show a text field and not a dropdown.
|
||||
if ((project == null && attribute.requiresYarnProject == false) || editNodeAsText || projectProp.hasMultipleDifferentValues)
|
||||
{
|
||||
var controlName = NodeTextControlNamePrefix + controlId;
|
||||
|
||||
// Multi-selection with different projects, just show a text
|
||||
// field to edit the node name. Most of the time, it will show
|
||||
// the mixed value dash (—).
|
||||
GUI.SetNextControlName(controlName);
|
||||
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var currentText = property.hasMultipleDifferentValues ? "-" : property.stringValue;
|
||||
currentText = EditorGUI.TextField(nodeNameFieldPosition, currentText);
|
||||
if (change.changed)
|
||||
{
|
||||
property.stringValue = currentText;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
if (editNodeAsText)
|
||||
{
|
||||
if (focusNodeTextField)
|
||||
{
|
||||
// Focusing the text field is delayed like this because
|
||||
// the control needs to exist first before we can focus
|
||||
// it
|
||||
focusNodeTextField = false;
|
||||
EditorGUI.FocusTextInControl(controlName);
|
||||
}
|
||||
else if (ShouldEndEditing(controlName))
|
||||
{
|
||||
editNodeAsText = false;
|
||||
HandleUtility.Repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show a dropdown that lets the user choose a node from the
|
||||
// ones present in the Yarn Project.
|
||||
|
||||
// If the Yarn Project is not set, this dropdown is empty and
|
||||
// disabled.
|
||||
if (project == null)
|
||||
{
|
||||
using (new EditorGUI.DisabledGroupScope(true))
|
||||
{
|
||||
EditorGUI.DropdownButton(nodeNameFieldPosition, GUIContent.none, FocusType.Passive);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeName = property.stringValue;
|
||||
var nodeNameSet = !string.IsNullOrEmpty(nodeName);
|
||||
|
||||
// Cached check if node exists in project
|
||||
if (lastProject != project || lastNodeName != nodeName)
|
||||
{
|
||||
lastProject = project;
|
||||
lastNodeName = nodeName;
|
||||
referenceExists = project.Program.Nodes.ContainsKey(nodeName);
|
||||
}
|
||||
|
||||
if (nodenameContent == null)
|
||||
{
|
||||
nodenameContent = new GUIContent();
|
||||
}
|
||||
|
||||
// Show warning icon if not does not exist in selected project
|
||||
|
||||
if (nodeNameSet)
|
||||
{
|
||||
nodenameContent.text = nodeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodenameContent.text = "(Choose Node)";
|
||||
}
|
||||
|
||||
MessageType iconType = MessageType.None;
|
||||
|
||||
if (!nodeNameSet)
|
||||
{
|
||||
iconType = MessageType.Info;
|
||||
}
|
||||
else if (!referenceExists)
|
||||
{
|
||||
iconType = MessageType.Warning;
|
||||
}
|
||||
else
|
||||
{
|
||||
iconType = MessageType.None;
|
||||
}
|
||||
|
||||
switch (iconType)
|
||||
{
|
||||
case MessageType.Info:
|
||||
nodenameContent.image = EditorGUIUtility.isProSkin ? EditorGUIUtility.IconContent("d_console.infoicon.sml").image : EditorGUIUtility.IconContent("console.infoicon.sml").image;
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
nodenameContent.image = EditorGUIUtility.isProSkin ? EditorGUIUtility.IconContent("d_console.warnicon.sml").image : EditorGUIUtility.IconContent("console.warnicon.sml").image;
|
||||
break;
|
||||
default:
|
||||
nodenameContent.image = null;
|
||||
break;
|
||||
}
|
||||
|
||||
var hasMixedNodeValues = property.hasMultipleDifferentValues;
|
||||
EditorGUI.showMixedValue = hasMixedNodeValues;
|
||||
|
||||
// Generate menu with node list only when user actually opens it
|
||||
if (EditorGUI.DropdownButton(nodeNameFieldPosition, nodenameContent, FocusType.Keyboard))
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
|
||||
menu.AddItem(new GUIContent("Edit..."), false, () =>
|
||||
{
|
||||
editNodeAsText = true;
|
||||
focusNodeTextField = true;
|
||||
});
|
||||
|
||||
menu.AddSeparator("");
|
||||
|
||||
menu.AddItem(new GUIContent("<None>"), !nodeNameSet, () =>
|
||||
{
|
||||
property.stringValue = "";
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
|
||||
if (!referenceExists && nodeNameSet && !hasMixedNodeValues)
|
||||
{
|
||||
menu.AddItem(new GUIContent(nodeName + " (Missing)"), true, () =>
|
||||
{
|
||||
property.stringValue = nodeName;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var node in GetNodes(project))
|
||||
{
|
||||
var name = node.Name;
|
||||
|
||||
menu.AddItem(new GUIContent(name), name == nodeName && !hasMixedNodeValues, () =>
|
||||
{
|
||||
property.stringValue = name;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
}
|
||||
|
||||
menu.DropDown(nodeNameFieldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel = indent;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private static IEnumerable<Node> GetNodes(YarnProject project)
|
||||
{
|
||||
foreach (var node in project.Program.Nodes.Values)
|
||||
{
|
||||
if (node.Name.StartsWith("$"))
|
||||
{
|
||||
// Skip smart variable nodes
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isNodeGroup = false;
|
||||
|
||||
foreach (var header in node.Headers)
|
||||
{
|
||||
if (header.Key == Node.NodeGroupHeader)
|
||||
{
|
||||
// This node is part of a node group; don't include it
|
||||
isNodeGroup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNodeGroup)
|
||||
{
|
||||
yield return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldEndEditing(string controlName)
|
||||
{
|
||||
if (GUI.GetNameOfFocusedControl() != controlName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyCode = Event.current.keyCode;
|
||||
if (keyCode != KeyCode.Return && keyCode != KeyCode.KeypadEnter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac84e49b2dc3b4c65a64a401894969d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/PropertyDrawers/YarnNodeAttributeDrawer.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public class SourceFileEntryElement : VisualElement, INotifyValueChanged<string>
|
||||
{
|
||||
private readonly TextField sourceFileField;
|
||||
private readonly Button deleteButton;
|
||||
public event System.Action? OnDelete;
|
||||
|
||||
public bool IsModified { get; private set; }
|
||||
|
||||
public string path = "";
|
||||
|
||||
public SourceFileEntryElement(VisualTreeAsset asset, string path, YarnProjectImporter importer)
|
||||
{
|
||||
asset.CloneTree(this);
|
||||
sourceFileField = this.Q<TextField>("sourceFile");
|
||||
deleteButton = this.Q<Button>("deleteButton");
|
||||
|
||||
IsModified = false;
|
||||
|
||||
sourceFileField.RegisterValueChangedCallback((evt) =>
|
||||
{
|
||||
IsModified = true;
|
||||
this.value = evt.newValue;
|
||||
});
|
||||
|
||||
deleteButton.clicked += () => OnDelete?.Invoke();
|
||||
|
||||
SetValueWithoutNotify(path);
|
||||
}
|
||||
|
||||
public string value
|
||||
{
|
||||
get => path;
|
||||
set
|
||||
{
|
||||
var previous = path;
|
||||
SetValueWithoutNotify(value);
|
||||
using (var evt = ChangeEvent<string>.GetPooled(previous, value))
|
||||
{
|
||||
evt.target = this;
|
||||
SendEvent(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValueWithoutNotify(string data)
|
||||
{
|
||||
this.path = data;
|
||||
sourceFileField.SetValueWithoutNotify(data);
|
||||
}
|
||||
|
||||
public void ClearModified()
|
||||
{
|
||||
this.IsModified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b2fe3167ad87422aa03ae72c9d356b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/SourceFileEntryElement.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58d299d8a9834494ab70ad29ce61c803
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<ui:Foldout text="Language" name="foldout" picking-mode="Ignore">
|
||||
<ui:VisualElement style="flex-direction: row; flex-shrink: 0; flex-grow: 1; justify-content: space-between;">
|
||||
<ui:Label text="(Language placeholder)" display-tooltip-when-elided="true" name="languagePlaceholder" style="flex-grow: 1;" />
|
||||
<ui:Button name="deleteButton" text="Delete" style="flex-shrink: 1; align-items: flex-end;" />
|
||||
</ui:VisualElement>
|
||||
<ui:Toggle label="External Asset" name="isExternalAsset" />
|
||||
<ui:VisualElement name="externalReferenceFields" enabled="true" style="flex-grow: 1; display: flex;">
|
||||
<uie:ObjectField label="Localization Asset" name="externalLocalisationAsset" type="Yarn.Unity.Localization, YarnSpinner.Unity" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="internallyGeneratedAssetFields" style="flex-grow: 1;">
|
||||
<uie:ObjectField label="Strings File" allow-scene-objects="false" type="UnityEngine.TextAsset, UnityEngine.CoreModule" name="stringsFile" />
|
||||
<ui:VisualElement name="stringsFileNotUsed" class="stringsFileNotUsed" style="flex-direction: row;">
|
||||
<ui:Label text="Strings File" display-tooltip-when-elided="true" class="unity-base-field__label" style="margin-left: 3px;" />
|
||||
<ui:Label text="Automatically included" display-tooltip-when-elided="true" class="unity-base-field__label" />
|
||||
</ui:VisualElement>
|
||||
<uie:ObjectField label="Assets Folder" allow-scene-objects="false" type="UnityEditor.DefaultAsset, UnityEditor" name="assetFolder" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement style="align-items: flex-end;" />
|
||||
</ui:Foldout>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de04e2bdef0b44420ace51d11acb9a26
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/USS/Localization.uxml
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,6 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<ui:VisualElement style="flex-direction: row;">
|
||||
<ui:TextField picking-mode="Ignore" name="sourceFile" style="flex-grow: 1;" />
|
||||
<ui:Button text="Delete" display-tooltip-when-elided="true" name="deleteButton" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 538a1dbae42414629a134a058c8848d9
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/USS/SourceFile.uxml
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,20 @@
|
||||
.help-box {
|
||||
background-color: var(--unity-colors-helpbox-background);
|
||||
border-color: var(--unity-colors-helpbox-border);
|
||||
border-width: 1px;
|
||||
border-radius: 2px;
|
||||
padding: 8px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.help-box Label {
|
||||
white-space: normal;
|
||||
padding-bottom: 8px;
|
||||
|
||||
}
|
||||
|
||||
.help-box Label.link {
|
||||
white-space: normal;
|
||||
color: var(--unity-colors-link-text);
|
||||
cursor: link;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb55d9cdb86eb461d9bf7e96af6e9c1e
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/USS/YarnSpinner.uss
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomEditor(typeof(YarnImporter))]
|
||||
public class YarnImporterEditor : ScriptedImporterEditor
|
||||
{
|
||||
public IEnumerable<string> DestinationProjectErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
if (assetTarget is not TextAsset textAsset)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Internal error: {nameof(assetTarget)} is not a {nameof(TextAsset)}");
|
||||
}
|
||||
|
||||
return destinationYarnProjectImporters.SelectMany(i => i.GetErrorsForScript(textAsset)) ?? new List<string>();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<YarnProject>? destinationYarnProjects;
|
||||
private IEnumerable<YarnProjectImporter>? destinationYarnProjectImporters;
|
||||
|
||||
public bool HasErrors => DestinationProjectErrors.Any();
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
UpdateDestinationProjects();
|
||||
}
|
||||
|
||||
private void UpdateDestinationProjects()
|
||||
{
|
||||
if (target is not YarnImporter yarnImporter)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Internal error: target is not {nameof(YarnImporter)}");
|
||||
}
|
||||
destinationYarnProjects = yarnImporter.DestinationProjects;
|
||||
|
||||
if (destinationYarnProjects != null)
|
||||
{
|
||||
destinationYarnProjectImporters = destinationYarnProjects
|
||||
.Select(project => AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(project)))
|
||||
.Where(importer => importer != null)
|
||||
.OfType<YarnProjectImporter>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
// nice header bit with logo and links
|
||||
DialogueRunnerEditor.DrawYarnSpinnerHeader();
|
||||
|
||||
if (target is not YarnImporter yarnImporter)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Internal error: target is not a {nameof(YarnImporter)}", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's a parse error in any of the selected objects,
|
||||
// show an error. If the selected objects have the same
|
||||
// destination program, and there's a compile error in it, show
|
||||
// that.
|
||||
if (HasErrors)
|
||||
{
|
||||
if (serializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Some of the selected scripts have errors.", MessageType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string error in DestinationProjectErrors)
|
||||
{
|
||||
EditorGUILayout.HelpBox(error, MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (destinationYarnProjects != null && destinationYarnProjects.Any() != false)
|
||||
{
|
||||
if (destinationYarnProjects.Count() == 1)
|
||||
{
|
||||
EditorGUILayout.ObjectField("Project", destinationYarnProjects.First(), typeof(YarnProject), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Projects", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel += 1;
|
||||
foreach (var project in destinationYarnProjects)
|
||||
{
|
||||
EditorGUILayout.ObjectField(project, typeof(YarnProject), false);
|
||||
}
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("This script is not currently part of a Yarn Project, so it can't be compiled or loaded into a Dialogue Runner. Either click Create New Yarn Project, or add this folder to an existing Yarn Project's sources list.", MessageType.Info);
|
||||
if (GUILayout.Button("Create New Yarn Project..."))
|
||||
{
|
||||
YarnProjectUtility.CreateYarnProject(yarnImporter);
|
||||
UpdateDestinationProjects();
|
||||
}
|
||||
}
|
||||
|
||||
var settings = YarnSpinnerProjectSettings.GetOrCreateSettings();
|
||||
if (settings.enableDirectLinkToVSCode)
|
||||
{
|
||||
if (GUILayout.Button("Open in VS Code"))
|
||||
{
|
||||
// https://code.visualstudio.com/docs/configure/command-line#_opening-vs-code-with-urls
|
||||
// this implies we should be able to open directly to the line and column
|
||||
// which would be great for errors
|
||||
// or if we show what nodes are inside this file we could jump to them directly
|
||||
// something to explore later
|
||||
|
||||
// as both the dataPath and assetPath include the Assets folder we need to strip that off before we combine these
|
||||
var absolutePathToYarnFile = Path.Combine(Path.GetDirectoryName(Application.dataPath), yarnImporter.assetPath);
|
||||
|
||||
// This approach is bit weird to look at but it gets around a difference of what a URL is between VSCode and C#
|
||||
// The initial thought is "why not use System.Uri.EscapeDataString?"
|
||||
// it encodes "/" as "%2F" and "\" as "%5C" which is technically correct
|
||||
// but vscode doesn't want that it just needs the spaces replaced
|
||||
// so instead we just manually replace all the spaces with "%20"
|
||||
// not the best but it works... for now...
|
||||
absolutePathToYarnFile = absolutePathToYarnFile.Replace(" ", $"%20");
|
||||
|
||||
var vscodeURL = $"vscode://file{absolutePathToYarnFile}";
|
||||
Application.OpenURL(vscodeURL);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
_ = serializedObject.ApplyModifiedProperties();
|
||||
ApplyRevertGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86e7a1afcf36f2847b546e40c89ce697
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnImporterEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
[CustomEditor(typeof(YarnProject))]
|
||||
public class YarnProjectEditor : UnityEditor.Editor
|
||||
{
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(target);
|
||||
var importer = AssetImporter.GetAtPath(assetPath) as YarnProjectImporter;
|
||||
|
||||
ProjectImportData? importData = null;
|
||||
if (importer == null)
|
||||
{
|
||||
// No importer found for this asset. Possibly it's not an asset on disk?
|
||||
return new Label("Yarn Project has no importer");
|
||||
}
|
||||
|
||||
var ui = new VisualElement();
|
||||
|
||||
importData = importer.ImportData;
|
||||
|
||||
if (importData == null)
|
||||
{
|
||||
return new Label("Project failed to import, or needs upgrading.");
|
||||
}
|
||||
|
||||
Foldout foldout;
|
||||
|
||||
var importDataSO = new SerializedObject(importData);
|
||||
|
||||
var yarnScriptsProperty = importDataSO.FindProperty(nameof(ProjectImportData.yarnFiles));
|
||||
var yarnScriptsField = new PropertyField(yarnScriptsProperty, "Yarn Scripts");
|
||||
yarnScriptsField.Bind(importDataSO);
|
||||
ui.Add(yarnScriptsField);
|
||||
foldout = yarnScriptsField.Q<Foldout>();
|
||||
if (foldout != null)
|
||||
{
|
||||
foldout.value = true;
|
||||
}
|
||||
|
||||
var variablesProperty = importDataSO.FindProperty(nameof(ProjectImportData.serializedDeclarations));
|
||||
var variablesField = new PropertyField(variablesProperty, "Variables");
|
||||
variablesField.Bind(importDataSO);
|
||||
foldout = variablesField.Q<Foldout>();
|
||||
if (foldout != null)
|
||||
{
|
||||
foldout.value = true;
|
||||
}
|
||||
|
||||
ui.Add(variablesField);
|
||||
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93828b071989a4569bbd4d8a7b0376b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnProjectEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,894 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AssetImporters;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using Yarn.Compiler;
|
||||
using System.IO;
|
||||
using UnityEditorInternal;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
#nullable enable
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
using UnityEditor.AddressableAssets;
|
||||
#endif
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
#endif
|
||||
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEditor.UIElements;
|
||||
using System;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
|
||||
[CustomEditor(typeof(YarnProjectImporter))]
|
||||
public class YarnProjectImporterEditor : ScriptedImporterEditor
|
||||
{
|
||||
// A runtime-only field that stores the defaultLanguage of the
|
||||
// YarnProjectImporter. Used during Inspector GUI drawing.
|
||||
internal static SerializedProperty? CurrentProjectDefaultLanguageProperty;
|
||||
|
||||
internal const string ProjectUpgradeHelpURL = "https://docs.yarnspinner.dev/using-yarnspinner-with-unity/importing-yarn-files/yarn-projects#upgrading-yarn-projects";
|
||||
internal const string CreateNewIssueURL = "https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues/new?assignees=&labels=bug&projects=&template=bug_report.md&title=Project Import Error";
|
||||
internal const string AddStringTagsButtonLabel = "Add Line Tags to Yarn Scripts";
|
||||
internal const string GenerateStringsFileButtonLabel = "Export Strings and Metadata as CSV";
|
||||
internal const string UpdateExistingStringsFilesButtonLabel = "Update Existing Strings Files";
|
||||
|
||||
private SerializedProperty? useAddressableAssetsProperty;
|
||||
|
||||
|
||||
public VisualTreeAsset? editorUI;
|
||||
public VisualTreeAsset? localizationUIAsset;
|
||||
public VisualTreeAsset? sourceFileUIAsset;
|
||||
public StyleSheet? yarnProjectStyleSheet;
|
||||
|
||||
private VisualElement? uiRoot;
|
||||
|
||||
private string? baseLanguage = null;
|
||||
private List<LocalizationEntryElement> localizationEntryFields = new List<LocalizationEntryElement>();
|
||||
private List<SourceFileEntryElement> sourceEntryFields = new List<SourceFileEntryElement>();
|
||||
|
||||
private VisualElement? localisationFieldsContainer;
|
||||
private VisualElement? sourceFileEntriesContainer;
|
||||
private VisualElement? variableStorageSettingsContainer;
|
||||
|
||||
private SerializedProperty? generateVariablesSourceFileProperty;
|
||||
private SerializedProperty? variablesClassNameProperty;
|
||||
private SerializedProperty? variablesClassNamespaceProperty;
|
||||
private SerializedProperty? variablesClassParentProperty;
|
||||
|
||||
private SerializedProperty? lineTaggerClassProperty;
|
||||
private SerializedProperty? useCustomLineTaggerProperty;
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
private SerializedProperty? useUnityLocalisationSystemProperty;
|
||||
private SerializedProperty? unityLocalisationTableCollectionGUIDProperty;
|
||||
#endif
|
||||
|
||||
private bool AnyModifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return AnyLocalisationModifications
|
||||
|| AnySourceFileModifications
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
private bool AnyLocalisationModifications => LocalisationsAddedOrRemoved || localizationEntryFields.Any(f => f.IsModified) || BaseLanguageNameModified || StringTableModified;
|
||||
|
||||
private bool AnySourceFileModifications => SourceFilesAddedOrRemoved || sourceEntryFields.Any(f => f.IsModified);
|
||||
|
||||
private bool LocalisationsAddedOrRemoved = false;
|
||||
private bool BaseLanguageNameModified = false;
|
||||
private bool SourceFilesAddedOrRemoved = false;
|
||||
private bool StringTableModified = false;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
useAddressableAssetsProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.useAddressableAssets));
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
useUnityLocalisationSystemProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.UseUnityLocalisationSystem));
|
||||
unityLocalisationTableCollectionGUIDProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.unityLocalisationStringTableCollectionGUID));
|
||||
#endif
|
||||
|
||||
generateVariablesSourceFileProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.generateVariablesSourceFile));
|
||||
variablesClassNameProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.variablesClassName));
|
||||
variablesClassNamespaceProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.variablesClassNamespace));
|
||||
variablesClassParentProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.variablesClassParent));
|
||||
|
||||
lineTaggerClassProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.lineTaggerClass));
|
||||
useCustomLineTaggerProperty = serializedObject.FindProperty(nameof(YarnProjectImporter.useCustomLineTagger));
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
if (AnyModifications)
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Unapplied Changes", "The currently selected Yarn Project has unapplied changes. Do you want to apply them or revert?", "Apply", "Revert"))
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
this.SaveChanges();
|
||||
#else
|
||||
this.ApplyAndImport();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Apply()
|
||||
{
|
||||
base.Apply();
|
||||
|
||||
|
||||
if (!(this.target is YarnProjectImporter importer))
|
||||
{
|
||||
throw new InvalidOperationException($"Internal error: importer for {this.target} is not a {nameof(YarnProjectImporter)}!");
|
||||
}
|
||||
|
||||
var data = importer.GetProject()
|
||||
?? throw new InvalidOperationException($"Failed to open project at {importer.assetPath}. Is it damaged?");
|
||||
|
||||
var importerFolder = Path.GetDirectoryName(importer.assetPath);
|
||||
|
||||
var removedLocalisations = data.Localisation.Keys.Except(localizationEntryFields.Select(f => f.value.languageID)).ToList();
|
||||
|
||||
foreach (var removedLocalisation in removedLocalisations)
|
||||
{
|
||||
data.Localisation.Remove(removedLocalisation);
|
||||
}
|
||||
|
||||
data.SourceFilePatterns = this.sourceEntryFields.Select(f => f.value);
|
||||
|
||||
foreach (var locField in localizationEntryFields)
|
||||
{
|
||||
|
||||
// Does this localisation field represent a localisation that
|
||||
// used to be the base localisation, but is now no longer? If it
|
||||
// is, even if it's unmodified, we need to make sure we add it
|
||||
// to the project data.
|
||||
bool wasPreviouslyBaseLocalisation =
|
||||
locField.value.languageID == data.BaseLanguage
|
||||
&& BaseLanguageNameModified;
|
||||
|
||||
// Skip any records that we don't need to touch
|
||||
if (locField.IsModified == false && !wasPreviouslyBaseLocalisation)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var locInfo = new Project.LocalizationInfo();
|
||||
|
||||
if (locField.value.isExternal && locField.value.externalLocalization != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(locField.value.externalLocalization, out var guid, out long _))
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(locField.value.externalLocalization);
|
||||
locInfo.Strings = "unity:" + guid;
|
||||
locInfo.Assets = "unity:" + guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
var stringFile = locField.value.stringsFile;
|
||||
var assetFolder = locField.value.assetsFolder;
|
||||
|
||||
if (stringFile != null)
|
||||
{
|
||||
string stringFilePath = AssetDatabase.GetAssetPath(stringFile);
|
||||
locInfo.Strings = Path.GetRelativePath(importerFolder, stringFilePath);
|
||||
}
|
||||
if (assetFolder != null)
|
||||
{
|
||||
string assetFolderPath = AssetDatabase.GetAssetPath(assetFolder);
|
||||
locInfo.Assets = Path.GetRelativePath(importerFolder, assetFolderPath);
|
||||
}
|
||||
}
|
||||
|
||||
data.Localisation[locField.value.languageID] = locInfo;
|
||||
locField.ClearModified();
|
||||
}
|
||||
|
||||
data.BaseLanguage = this.baseLanguage ?? "unknown";
|
||||
|
||||
if (data.Localisation.TryGetValue(data.BaseLanguage, out var baseLanguageInfo))
|
||||
{
|
||||
if (string.IsNullOrEmpty(baseLanguageInfo.Strings)
|
||||
&& string.IsNullOrEmpty(baseLanguageInfo.Assets))
|
||||
{
|
||||
// We have a localisation info entry, but it doesn't provide
|
||||
// any useful information (the strings field is unused, and
|
||||
// the assets field defaults to empty anyway). Trim it from
|
||||
// the data.
|
||||
data.Localisation.Remove(data.BaseLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var sourceField in this.sourceEntryFields)
|
||||
{
|
||||
sourceField.ClearModified();
|
||||
}
|
||||
|
||||
BaseLanguageNameModified = false;
|
||||
SourceFilesAddedOrRemoved = false;
|
||||
LocalisationsAddedOrRemoved = false;
|
||||
StringTableModified = false;
|
||||
|
||||
data.SaveToFile(importer.assetPath);
|
||||
|
||||
if (localizationEntryFields.Any(f => f.value.languageID == this.baseLanguage) == false)
|
||||
{
|
||||
var newBaseLanguageField = CreateLocalisationEntryElement(new ProjectImportData.LocalizationEntry
|
||||
{
|
||||
assetsFolder = null,
|
||||
stringsFile = null,
|
||||
languageID = baseLanguage ?? "unknown",
|
||||
}, baseLanguage ?? "unknown");
|
||||
localizationEntryFields.Add(newBaseLanguageField);
|
||||
localisationFieldsContainer?.Add(newBaseLanguageField);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DiscardChanges()
|
||||
{
|
||||
localizationEntryFields.Clear();
|
||||
sourceEntryFields.Clear();
|
||||
LocalisationsAddedOrRemoved = false;
|
||||
BaseLanguageNameModified = false;
|
||||
SourceFilesAddedOrRemoved = false;
|
||||
|
||||
base.DiscardChanges();
|
||||
|
||||
var inspectorRoot = uiRoot?.parent;
|
||||
uiRoot?.RemoveFromHierarchy();
|
||||
|
||||
inspectorRoot?.Add(CreateInspectorGUI());
|
||||
}
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
if (!(target is YarnProjectImporter yarnProjectImporter))
|
||||
{
|
||||
throw new InvalidOperationException($"Internal error: importer for {this.target} is not a {nameof(YarnProjectImporter)}!");
|
||||
}
|
||||
|
||||
var importData = yarnProjectImporter.ImportData;
|
||||
|
||||
sourceEntryFields.Clear();
|
||||
localizationEntryFields.Clear();
|
||||
|
||||
var ui = new VisualElement();
|
||||
uiRoot = ui;
|
||||
|
||||
ui.styleSheets.Add(yarnProjectStyleSheet);
|
||||
|
||||
// nice header bit with logo and links
|
||||
var yarnspinnerHeader = new IMGUIContainer(DialogueRunnerEditor.DrawYarnSpinnerHeader);
|
||||
ui.Add(yarnspinnerHeader);
|
||||
|
||||
// if the import data is null it means import has crashed
|
||||
// we need to let the user know and perhaps ask them to file an issue
|
||||
if (importData == null)
|
||||
{
|
||||
ui.Add(CreateCriticalErrorUI());
|
||||
return ui;
|
||||
}
|
||||
|
||||
// next we need to handle the two edge cases
|
||||
// either the importData is for the older format
|
||||
// or it's completely unknown (most likely a error)
|
||||
// in both cases we show the respective custom UI and return
|
||||
switch (importData.ImportStatus)
|
||||
{
|
||||
case ProjectImportData.ImportStatusCode.NeedsUpgradeFromV1:
|
||||
{
|
||||
ui.Add(CreateUpgradeUI(yarnProjectImporter));
|
||||
return ui;
|
||||
}
|
||||
case ProjectImportData.ImportStatusCode.Unknown:
|
||||
{
|
||||
ui.Add(CreateUnknownErrorUI());
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
|
||||
var importDataSO = new SerializedObject(importData);
|
||||
var diagnosticsProperty = importDataSO.FindProperty(nameof(ProjectImportData.diagnostics));
|
||||
|
||||
var errorsContainer = new VisualElement();
|
||||
errorsContainer.name = "errors";
|
||||
|
||||
var sourceFilesContainer = new VisualElement();
|
||||
|
||||
var localisationControls = new VisualElement();
|
||||
|
||||
var yarnInternalControls = new VisualElement();
|
||||
|
||||
var unityControls = new VisualElement();
|
||||
|
||||
var useAddressableAssetsField = new PropertyField(useAddressableAssetsProperty);
|
||||
useAddressableAssetsField.BindProperty(useAddressableAssetsProperty);
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
var useUnityLocalisationSystemField = new PropertyField(useUnityLocalisationSystemProperty);
|
||||
useUnityLocalisationSystemField.BindProperty(useUnityLocalisationSystemProperty);
|
||||
|
||||
// References to string table collections are stored as GUIDs,
|
||||
// because ScriptedImporters can't refer to ScriptableObjects
|
||||
// directly without causing drama. To preserve a good user
|
||||
// experience, we'll add and manage an ObjectField directly.
|
||||
var unityLocalisationTableCollectionField = new ObjectField("String Table Collection");
|
||||
unityLocalisationTableCollectionField.objectType = typeof(StringTableCollection);
|
||||
unityLocalisationTableCollectionField.SetValueWithoutNotify(yarnProjectImporter.UnityLocalisationStringTableCollection);
|
||||
#endif
|
||||
|
||||
localisationFieldsContainer = new VisualElement();
|
||||
sourceFileEntriesContainer = new VisualElement();
|
||||
variableStorageSettingsContainer = new VisualElement();
|
||||
|
||||
localisationControls.style.marginBottom = 8;
|
||||
|
||||
if (importData.diagnostics.Any())
|
||||
{
|
||||
var header = new Label();
|
||||
header.text = "Errors";
|
||||
header.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
|
||||
errorsContainer.Add(header);
|
||||
|
||||
foreach (var error in importData.diagnostics)
|
||||
{
|
||||
var errorContainer = new VisualElement();
|
||||
errorContainer.style.marginLeft = 15;
|
||||
|
||||
var objectField = new ObjectField();
|
||||
objectField.value = error.yarnFile;
|
||||
objectField.objectType = typeof(TextAsset);
|
||||
|
||||
var messagesField = new IMGUIContainer(() =>
|
||||
{
|
||||
foreach (var message in error.errorMessages)
|
||||
{
|
||||
EditorGUILayout.HelpBox(message, MessageType.Error);
|
||||
}
|
||||
});
|
||||
messagesField.style.marginLeft = 30;
|
||||
|
||||
// if an error isn't able to be linked to a yarn file specifically
|
||||
// such as an error in the library defining an invalid external function
|
||||
// we don't want to show an empty text asset
|
||||
if (error.yarnFile != null)
|
||||
{
|
||||
errorContainer.Add(objectField);
|
||||
}
|
||||
errorContainer.Add(messagesField);
|
||||
|
||||
errorsContainer.Add(errorContainer);
|
||||
}
|
||||
|
||||
errorsContainer.style.marginBottom = 15;
|
||||
|
||||
ui.Add(errorsContainer);
|
||||
}
|
||||
|
||||
sourceFileEntriesContainer.style.marginLeft = 8;
|
||||
|
||||
ui.Add(sourceFilesContainer);
|
||||
var sourceFilesHeader = new Label();
|
||||
sourceFilesHeader.text = "Source Yarn Scripts";
|
||||
sourceFilesHeader.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
sourceFilesContainer.Add(sourceFilesHeader);
|
||||
sourceFilesContainer.Add(sourceFileEntriesContainer);
|
||||
|
||||
foreach (var path in importData.sourceFilePatterns)
|
||||
{
|
||||
var locElement = CreateSourceFileEntryElement(path);
|
||||
sourceFileEntriesContainer.Add(locElement);
|
||||
sourceEntryFields.Add(locElement);
|
||||
}
|
||||
|
||||
var addSourceFileButton = new Button();
|
||||
addSourceFileButton.text = "Add";
|
||||
sourceFilesContainer.Add(addSourceFileButton);
|
||||
addSourceFileButton.style.marginLeft = 8;
|
||||
addSourceFileButton.clicked += () =>
|
||||
{
|
||||
var loc = CreateSourceFileEntryElement("**/*.yarn");
|
||||
sourceEntryFields.Add(loc);
|
||||
sourceFileEntriesContainer.Add(loc);
|
||||
SourceFilesAddedOrRemoved = true;
|
||||
};
|
||||
|
||||
var localisationHeader = new Label();
|
||||
|
||||
localisationHeader.text = "Localisation";
|
||||
localisationHeader.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
localisationHeader.style.marginTop = 8;
|
||||
|
||||
localisationControls.Add(localisationHeader);
|
||||
|
||||
var languagePopup = new LanguageField("Base Language");
|
||||
var generateStringsFileButton = new Button();
|
||||
var addStringTagsButton = new Button();
|
||||
var updateExistingStringsFilesButton = new Button();
|
||||
|
||||
baseLanguage = importData.baseLanguageName;
|
||||
|
||||
languagePopup.SetValueWithoutNotify(baseLanguage ?? "unknown");
|
||||
languagePopup.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
baseLanguage = evt.newValue;
|
||||
foreach (var loc in localizationEntryFields)
|
||||
{
|
||||
loc.ProjectBaseLanguage = baseLanguage;
|
||||
}
|
||||
BaseLanguageNameModified = true;
|
||||
});
|
||||
|
||||
localisationControls.Add(languagePopup);
|
||||
|
||||
#if USE_ADDRESSABLES
|
||||
yarnInternalControls.Add(useAddressableAssetsField);
|
||||
#endif
|
||||
|
||||
yarnInternalControls.Add(localisationFieldsContainer);
|
||||
|
||||
foreach (var localisation in importData.localizations)
|
||||
{
|
||||
var locElement = CreateLocalisationEntryElement(localisation, baseLanguage ?? "unknown");
|
||||
localisationFieldsContainer.Add(locElement);
|
||||
localizationEntryFields.Add(locElement);
|
||||
}
|
||||
|
||||
var addLocalisationButton = new Button();
|
||||
addLocalisationButton.text = "Add Localisation";
|
||||
addLocalisationButton.clicked += () =>
|
||||
{
|
||||
var loc = CreateLocalisationEntryElement(new ProjectImportData.LocalizationEntry()
|
||||
{
|
||||
languageID = importData.baseLanguageName ?? "unknown",
|
||||
}, baseLanguage ?? "unknown");
|
||||
localizationEntryFields.Add(loc);
|
||||
localisationFieldsContainer.Add(loc);
|
||||
LocalisationsAddedOrRemoved = true;
|
||||
|
||||
};
|
||||
yarnInternalControls.Add(addLocalisationButton);
|
||||
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
localisationControls.Add(useUnityLocalisationSystemField);
|
||||
|
||||
unityControls.Add(unityLocalisationTableCollectionField);
|
||||
|
||||
var emptyTableCollectionWarning = new IMGUIContainer(() =>
|
||||
{
|
||||
EditorGUILayout.HelpBox("A string table collection is required.", MessageType.Warning);
|
||||
});
|
||||
|
||||
unityControls.Add(emptyTableCollectionWarning);
|
||||
|
||||
void UpdateLocalizationVisibility()
|
||||
{
|
||||
SetElementVisible(unityControls, useUnityLocalisationSystemProperty?.boolValue ?? false);
|
||||
SetElementVisible(yarnInternalControls, !useUnityLocalisationSystemProperty?.boolValue ?? false);
|
||||
}
|
||||
|
||||
void UpdateUnityTableCollectionEmptyWarningVisibility()
|
||||
{
|
||||
SetElementVisible(emptyTableCollectionWarning, string.IsNullOrEmpty(unityLocalisationTableCollectionGUIDProperty?.stringValue));
|
||||
}
|
||||
|
||||
UpdateLocalizationVisibility();
|
||||
UpdateUnityTableCollectionEmptyWarningVisibility();
|
||||
|
||||
useUnityLocalisationSystemField.RegisterCallback<ChangeEvent<bool>>(evt =>
|
||||
{
|
||||
UpdateLocalizationVisibility();
|
||||
});
|
||||
|
||||
|
||||
unityLocalisationTableCollectionField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
// When the localisation table changes, get the GUID for it and
|
||||
// store it in the property.
|
||||
|
||||
if (unityLocalisationTableCollectionGUIDProperty == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(unityLocalisationTableCollectionGUIDProperty)} is null");
|
||||
}
|
||||
|
||||
if (evt.newValue != null && AssetDatabase.TryGetGUIDAndLocalFileIdentifier(evt.newValue, out string guid, out long _))
|
||||
{
|
||||
unityLocalisationTableCollectionGUIDProperty.stringValue = guid;
|
||||
unityLocalisationTableCollectionGUIDProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The object is null, or a GUID for it can't be found.
|
||||
unityLocalisationTableCollectionGUIDProperty.stringValue = string.Empty;
|
||||
unityLocalisationTableCollectionGUIDProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
// Flag that we've changed our importer's settings.
|
||||
StringTableModified = true;
|
||||
|
||||
UpdateUnityTableCollectionEmptyWarningVisibility();
|
||||
});
|
||||
#endif
|
||||
|
||||
var cantGenerateUnityStringTableMessage = new IMGUIContainer(() =>
|
||||
{
|
||||
EditorGUILayout.HelpBox($"All lines must have a line ID tag in order to create a string table. Click '{AddStringTagsButtonLabel}' to fix this problem.", MessageType.Warning);
|
||||
});
|
||||
|
||||
var unableToAddLineTagsDueToChangesWarningBox = new IMGUIContainer(() =>
|
||||
{
|
||||
EditorGUILayout.HelpBox("Unable to add line tags while the project has unsaved changes.", MessageType.Info);
|
||||
});
|
||||
|
||||
var useCustomTaggerValue = useCustomLineTaggerProperty?.boolValue ?? false;
|
||||
var currentTaggerClass = lineTaggerClassProperty?.stringValue ?? null;
|
||||
|
||||
var taggerChoice = new DropdownField();
|
||||
var allTaggers = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => typeof(ILineTagGenerator).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract);
|
||||
foreach (var tagger in allTaggers)
|
||||
{
|
||||
taggerChoice.choices.Add(tagger.FullName);
|
||||
if (tagger.FullName == currentTaggerClass)
|
||||
{
|
||||
taggerChoice.value = tagger.FullName;
|
||||
}
|
||||
}
|
||||
taggerChoice.RegisterValueChangedCallback(v =>
|
||||
{
|
||||
if (lineTaggerClassProperty != null)
|
||||
{
|
||||
lineTaggerClassProperty.stringValue = v.newValue;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
UpdateTaggingButtonsEnabled();
|
||||
}
|
||||
});
|
||||
|
||||
var useCustomTagger = new Toggle
|
||||
{
|
||||
label = "Use custom line tagging",
|
||||
value = useCustomTaggerValue
|
||||
};
|
||||
useCustomTagger.RegisterValueChangedCallback((change) =>
|
||||
{
|
||||
SetElementVisible(taggerChoice, change.newValue);
|
||||
|
||||
if (useCustomLineTaggerProperty != null)
|
||||
{
|
||||
useCustomLineTaggerProperty.boolValue = change.newValue;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
UpdateTaggingButtonsEnabled();
|
||||
}
|
||||
});
|
||||
|
||||
addStringTagsButton.text = AddStringTagsButtonLabel;
|
||||
addStringTagsButton.clicked += () =>
|
||||
{
|
||||
ILineTagGenerator? tagger = null;
|
||||
if (useCustomTagger.value)
|
||||
{
|
||||
if (taggerChoice.value != null)
|
||||
{
|
||||
if (lineTaggerClassProperty != null)
|
||||
{
|
||||
lineTaggerClassProperty.stringValue = taggerChoice.value;
|
||||
}
|
||||
if (useCustomLineTaggerProperty != null)
|
||||
{
|
||||
useCustomLineTaggerProperty.boolValue = true;
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var taggerType = allTaggers.SingleOrDefault(t => t.FullName == taggerChoice.value);
|
||||
if (taggerType != null)
|
||||
{
|
||||
tagger = Activator.CreateInstance(taggerType) as ILineTagGenerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
YarnProjectUtility.AddLineTagsToFilesInYarnProject(yarnProjectImporter, null, tagger);
|
||||
UpdateTaggingButtonsEnabled();
|
||||
};
|
||||
|
||||
generateStringsFileButton.text = GenerateStringsFileButtonLabel;
|
||||
|
||||
generateStringsFileButton.clicked += () => ExportStringsData(yarnProjectImporter);
|
||||
|
||||
updateExistingStringsFilesButton.text = UpdateExistingStringsFilesButtonLabel;
|
||||
updateExistingStringsFilesButton.clicked += () =>
|
||||
{
|
||||
YarnProjectUtility.UpdateLocalizationCSVs(yarnProjectImporter);
|
||||
};
|
||||
yarnInternalControls.Add(updateExistingStringsFilesButton);
|
||||
|
||||
// if it's already on we want it to show without having to toggle
|
||||
SetElementVisible(taggerChoice, useCustomTagger.value);
|
||||
|
||||
yarnInternalControls.Add(useCustomTagger);
|
||||
yarnInternalControls.Add(taggerChoice);
|
||||
|
||||
localisationControls.Add(yarnInternalControls);
|
||||
localisationControls.Add(unityControls);
|
||||
|
||||
ui.Add(localisationControls);
|
||||
|
||||
ui.Add(cantGenerateUnityStringTableMessage);
|
||||
|
||||
ui.Add(unableToAddLineTagsDueToChangesWarningBox);
|
||||
ui.Add(addStringTagsButton);
|
||||
ui.Add(generateStringsFileButton);
|
||||
|
||||
var generateVariablesSourceFileField = new PropertyField(generateVariablesSourceFileProperty);
|
||||
var variablesClassNameField = new PropertyField(variablesClassNameProperty);
|
||||
var variablesClassNamespaceField = new PropertyField(variablesClassNamespaceProperty);
|
||||
|
||||
generateVariablesSourceFileField.Bind(serializedObject);
|
||||
variablesClassNameField.Bind(serializedObject);
|
||||
variablesClassNamespaceField.Bind(serializedObject);
|
||||
|
||||
|
||||
// Find all loaded assemblies that are not YarnSpinner.dll. Find all
|
||||
// types that implement IVariableStorage, are not abstract, and are
|
||||
// not generated code. Get the full names of the result.
|
||||
var variableStorageClasses = AppDomain.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.Where(a => a != typeof(Yarn.Dialogue).Assembly)
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.Where(t => t.GetInterfaces().Any(i => i == typeof(IVariableStorage)))
|
||||
.Where(t => t.IsAbstract == false)
|
||||
.Where(t => !t.CustomAttributes.Any(a => a.AttributeType == typeof(System.CodeDom.Compiler.GeneratedCodeAttribute)))
|
||||
.Select(t => t.FullName)
|
||||
.ToList();
|
||||
|
||||
var variablesClassParentDropdownField = new DropdownField(
|
||||
"Variables Parent Class",
|
||||
variableStorageClasses,
|
||||
variablesClassParentProperty?.stringValue ?? string.Empty
|
||||
);
|
||||
|
||||
variablesClassParentDropdownField.RegisterValueChangedCallback(v =>
|
||||
{
|
||||
if (variablesClassParentProperty != null)
|
||||
{
|
||||
variablesClassParentProperty.stringValue = v.newValue;
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
});
|
||||
|
||||
void UpdateVariableSettingsVisibility()
|
||||
{
|
||||
foreach (var field in new VisualElement[] { variablesClassNameField, variablesClassNamespaceField, variablesClassParentDropdownField })
|
||||
{
|
||||
SetElementVisible(field, generateVariablesSourceFileProperty?.boolValue ?? false);
|
||||
}
|
||||
}
|
||||
UpdateVariableSettingsVisibility();
|
||||
generateVariablesSourceFileField.RegisterValueChangeCallback(e => UpdateVariableSettingsVisibility());
|
||||
|
||||
variableStorageSettingsContainer.Add(generateVariablesSourceFileField);
|
||||
variableStorageSettingsContainer.Add(variablesClassNameField);
|
||||
variableStorageSettingsContainer.Add(variablesClassNamespaceField);
|
||||
variableStorageSettingsContainer.Add(variablesClassParentDropdownField);
|
||||
|
||||
ui.Add(variableStorageSettingsContainer);
|
||||
|
||||
|
||||
ui.Add(new IMGUIContainer(ApplyRevertGUI));
|
||||
|
||||
UpdateTaggingButtonsEnabled();
|
||||
|
||||
return ui;
|
||||
|
||||
void UpdateTaggingButtonsEnabled()
|
||||
{
|
||||
bool isUnsaved = HasModified();
|
||||
addStringTagsButton.SetEnabled(yarnProjectImporter.CanGenerateStringsTable == false && importData.yarnFiles.Any() && !isUnsaved);
|
||||
generateStringsFileButton.SetEnabled(yarnProjectImporter.CanGenerateStringsTable && !isUnsaved);
|
||||
|
||||
SetElementVisible(unableToAddLineTagsDueToChangesWarningBox, isUnsaved);
|
||||
|
||||
bool isUnityLocalisationAvailable;
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
isUnityLocalisationAvailable = true;
|
||||
#else
|
||||
isUnityLocalisationAvailable = false;
|
||||
#endif
|
||||
|
||||
cantGenerateUnityStringTableMessage.style.display = (isUnityLocalisationAvailable && yarnProjectImporter.HasErrors == false && yarnProjectImporter.CanGenerateStringsTable == false) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalizationEntryElement CreateLocalisationEntryElement(ProjectImportData.LocalizationEntry localisation, string baseLanguage)
|
||||
{
|
||||
if (localizationUIAsset == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't create {nameof(LocalizationEntryElement)}: {nameof(localizationUIAsset)} is null");
|
||||
}
|
||||
|
||||
var locElement = new LocalizationEntryElement(localizationUIAsset, localisation, baseLanguage);
|
||||
locElement.OnDelete += () =>
|
||||
{
|
||||
locElement.RemoveFromHierarchy();
|
||||
localizationEntryFields.Remove(locElement);
|
||||
LocalisationsAddedOrRemoved = true;
|
||||
};
|
||||
return locElement;
|
||||
}
|
||||
|
||||
private SourceFileEntryElement CreateSourceFileEntryElement(string path)
|
||||
{
|
||||
if (sourceFileUIAsset == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't create {nameof(SourceFileEntryElement)}: {nameof(sourceFileUIAsset)} is null");
|
||||
}
|
||||
|
||||
if (!(this.target is YarnProjectImporter importer))
|
||||
{
|
||||
throw new InvalidOperationException($"Internal error: importer for {this.target} is not a {nameof(YarnProjectImporter)}!");
|
||||
}
|
||||
|
||||
var sourceElement = new SourceFileEntryElement(sourceFileUIAsset, path, importer);
|
||||
sourceElement.OnDelete += () =>
|
||||
{
|
||||
sourceElement.RemoveFromHierarchy();
|
||||
sourceEntryFields.Remove(sourceElement);
|
||||
SourceFilesAddedOrRemoved = true;
|
||||
};
|
||||
return sourceElement;
|
||||
}
|
||||
|
||||
|
||||
private void ExportStringsData(YarnProjectImporter yarnProjectImporter)
|
||||
{
|
||||
var currentPath = AssetDatabase.GetAssetPath(yarnProjectImporter);
|
||||
var currentFileName = Path.GetFileNameWithoutExtension(currentPath);
|
||||
var currentDirectory = Path.GetDirectoryName(currentPath);
|
||||
|
||||
var destinationPath = EditorUtility.SaveFilePanel("Export Strings CSV", currentDirectory, $"{currentFileName}.csv", "csv");
|
||||
|
||||
if (string.IsNullOrEmpty(destinationPath) == false)
|
||||
{
|
||||
// Generate the file on disk
|
||||
YarnProjectUtility.WriteStringsFile(destinationPath, yarnProjectImporter);
|
||||
|
||||
// Also generate the metadata file.
|
||||
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
||||
var destinationFileName = Path.GetFileNameWithoutExtension(destinationPath);
|
||||
|
||||
var metadataDestinationPath = Path.Combine(destinationDirectory, $"{destinationFileName}-metadata.csv");
|
||||
YarnProjectUtility.WriteMetadataFile(metadataDestinationPath, yarnProjectImporter);
|
||||
|
||||
// destinationPath may have been inside our Assets
|
||||
// directory, so refresh the asset database
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetElementVisible(VisualElement e, bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
e.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasModified()
|
||||
{
|
||||
return base.HasModified() || AnyModifications;
|
||||
}
|
||||
|
||||
private VisualElement CreateUpgradeUI(YarnProjectImporter importer)
|
||||
{
|
||||
var ui = new VisualElement();
|
||||
|
||||
var box = new VisualElement();
|
||||
box.AddToClassList("help-box");
|
||||
|
||||
Label header = new Label("This project needs to be upgraded.");
|
||||
header.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
box.Add(header);
|
||||
box.Add(new Label("After upgrading, you will need to update your localisations, and ensure that all of the Yarn scripts for this project are in the same folder as the project."));
|
||||
box.Add(new Label("Your Yarn scripts will not be modified."));
|
||||
|
||||
var learnMoreLink = new Label("Learn more...");
|
||||
learnMoreLink.RegisterCallback<MouseDownEvent>(evt =>
|
||||
{
|
||||
Application.OpenURL(ProjectUpgradeHelpURL);
|
||||
});
|
||||
learnMoreLink.AddToClassList("link");
|
||||
box.Add(learnMoreLink);
|
||||
|
||||
var upgradeButton = new Button(() =>
|
||||
{
|
||||
YarnProjectUtility.UpgradeYarnProject(importer);
|
||||
|
||||
// Reload the entire inspector - we will have changed the
|
||||
// project significantly
|
||||
ActiveEditorTracker.sharedTracker.ForceRebuild();
|
||||
});
|
||||
upgradeButton.text = "Upgrade Yarn Project";
|
||||
box.Add(upgradeButton);
|
||||
|
||||
ui.Add(box);
|
||||
|
||||
ui.Add(new IMGUIContainer(ApplyRevertGUI));
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
private VisualElement CreateErrorUI(string headerText, string[] labels, string linkLabel, string link)
|
||||
{
|
||||
var ui = new VisualElement();
|
||||
var box = new VisualElement();
|
||||
box.AddToClassList("help-box");
|
||||
|
||||
Label header = new Label(headerText);
|
||||
header.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||
box.Add(header);
|
||||
|
||||
foreach (var label in labels)
|
||||
{
|
||||
box.Add(new Label(label));
|
||||
}
|
||||
|
||||
var learnMoreLink = new Label(linkLabel);
|
||||
learnMoreLink.RegisterCallback<MouseDownEvent>(evt =>
|
||||
{
|
||||
Application.OpenURL(link);
|
||||
});
|
||||
learnMoreLink.AddToClassList("link");
|
||||
box.Add(learnMoreLink);
|
||||
|
||||
ui.Add(box);
|
||||
|
||||
ui.Add(new IMGUIContainer(ApplyRevertGUI));
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
private VisualElement CreateCriticalErrorUI()
|
||||
{
|
||||
string[] labels = {
|
||||
"This is likely due to a bug on our end, and not in your project.",
|
||||
"Try recreating the project and see if this resolves the issue."
|
||||
};
|
||||
|
||||
return CreateErrorUI("This project has failed to import due to an internal error.", labels, "If the issue persists, please open an issue.", CreateNewIssueURL);
|
||||
}
|
||||
|
||||
private VisualElement CreateUnknownErrorUI()
|
||||
{
|
||||
string[] labels = {
|
||||
"The type of this Yarn Project is unknown.",
|
||||
"Try recreating the project and see if this resolves the issue."
|
||||
};
|
||||
|
||||
return CreateErrorUI("This project has failed to import correctly.", labels, "If the issue persists, please open an issue.", CreateNewIssueURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a1a2642bf9259a4b95d13af4498fa9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- editorUI: {instanceID: 0}
|
||||
- localizationUIAsset: {fileID: 9197481963319205126, guid: de04e2bdef0b44420ace51d11acb9a26,
|
||||
type: 3}
|
||||
- sourceFileUIAsset: {fileID: 9197481963319205126, guid: 538a1dbae42414629a134a058c8848d9,
|
||||
type: 3}
|
||||
- yarnProjectStyleSheet: {fileID: 7433441132597879392, guid: cb55d9cdb86eb461d9bf7e96af6e9c1e,
|
||||
type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnProjectImporterEditor.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,238 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using UnityEngine.Networking;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
public class YarnSpinnerEditorWindow : EditorWindow
|
||||
{
|
||||
static UnityWebRequest? supportersRequest;
|
||||
static string supportersList = string.Empty;
|
||||
|
||||
[SerializeField]
|
||||
private VisualTreeAsset? m_VisualTreeAsset = default;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
internal static void TryShowingWindowOnLoad()
|
||||
{
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
// do a check to see if it is time to show
|
||||
if (ShouldShowAboutPage())
|
||||
{
|
||||
ShowAbout();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[MenuItem("Window/Yarn Spinner/About Yarn Spinner... %#y", false, 2000)]
|
||||
public static void ShowAbout()
|
||||
{
|
||||
YarnSpinnerEditorWindow window = GetWindow<YarnSpinnerEditorWindow>(true, "About Yarn Spinner", true);
|
||||
window.minSize = new Vector2(512, 768);
|
||||
window.maxSize = window.minSize;
|
||||
window.Show();
|
||||
}
|
||||
|
||||
public void CreateGUI()
|
||||
{
|
||||
// Each editor window contains a root VisualElement object
|
||||
VisualElement root = rootVisualElement;
|
||||
|
||||
if (m_VisualTreeAsset == null)
|
||||
{
|
||||
Debug.LogError("Unable to load the UXML file for the About Window");
|
||||
return;
|
||||
}
|
||||
|
||||
// Instantiate UXML
|
||||
VisualElement labelFromUXML = m_VisualTreeAsset.Instantiate();
|
||||
root.Add(labelFromUXML);
|
||||
|
||||
// ok so will need to get lots of different pieces
|
||||
// core version, compiler version, unity version
|
||||
var coreLabel = root.Q<Label>("coreVLabel");
|
||||
var compLabel = root.Q<Label>("compVLabel");
|
||||
var unityLabel = root.Q<Label>("unityVLabel");
|
||||
|
||||
coreLabel.text = $"Core: {GetInformationalVersionForType(typeof(Yarn.Dialogue))}";
|
||||
compLabel.text = $"Compiler: {GetInformationalVersionForType(typeof(Yarn.Compiler.Compiler))}";
|
||||
unityLabel.text = $"Unity: {GetInformationalVersionForType(typeof(Yarn.Unity.DialogueRunner))}";
|
||||
|
||||
// docs link and discord link
|
||||
var resourcesContainer = root.Q("resources");
|
||||
var resourcesButtonContainer = resourcesContainer.Q("buttons");
|
||||
var dissy = resourcesButtonContainer.Q<Button>("support");
|
||||
var docs = resourcesButtonContainer.Q<Button>("docs");
|
||||
dissy.clicked += () =>
|
||||
{
|
||||
Application.OpenURL("https://discord.com/invite/yarnspinner");
|
||||
};
|
||||
docs.clicked += () =>
|
||||
{
|
||||
Application.OpenURL("https://docs.yarnspinner.dev/yarn-spinner-for-unity/");
|
||||
};
|
||||
|
||||
var extrasContainer = root.Q("extras");
|
||||
var showcase = extrasContainer.Q<Button>("showcaseButton");
|
||||
var patreon = extrasContainer.Q<Button>("patreonButton");
|
||||
|
||||
showcase.clicked += () =>
|
||||
{
|
||||
Application.OpenURL("https://www.yarnspinner.dev/tell-us");
|
||||
};
|
||||
|
||||
patreon.clicked += () =>
|
||||
{
|
||||
Application.OpenURL("https://www.patreon.com/bePatron?u=11132340");
|
||||
};
|
||||
|
||||
// list of patreons
|
||||
var patronsList = extrasContainer.Q<ScrollView>("patreonList");
|
||||
FillScrollList(patronsList);
|
||||
|
||||
var review = extrasContainer.Q<Button>("reviewButton");
|
||||
var reviewLabel = extrasContainer.Q("reviewLabel");
|
||||
string reviewText;
|
||||
string reviewURL;
|
||||
|
||||
#pragma warning disable 162
|
||||
switch (Yarn.Unity.Editor.YarnPackageImporter.InstallationApproach)
|
||||
{
|
||||
case Yarn.Unity.Editor.YarnPackageImporter.InstallApproach.AssetStore:
|
||||
review.style.display = DisplayStyle.Flex;
|
||||
reviewLabel.style.display = DisplayStyle.Flex;
|
||||
reviewText = "Review on the Asset Store";
|
||||
reviewURL = "https://assetstore.unity.com/packages/tools/behavior-ai/yarn-spinner-for-unity-the-friendly-dialogue-and-narrative-tool-267061";
|
||||
break;
|
||||
case Yarn.Unity.Editor.YarnPackageImporter.InstallApproach.Itch:
|
||||
review.style.display = DisplayStyle.Flex;
|
||||
reviewLabel.style.display = DisplayStyle.Flex;
|
||||
reviewText = "Review at Itch";
|
||||
reviewURL = "https://yarnspinner.itch.io/yarn-spinner/rate";
|
||||
break;
|
||||
default:
|
||||
review.style.display = DisplayStyle.None;
|
||||
reviewLabel.style.display = DisplayStyle.None;
|
||||
return;
|
||||
}
|
||||
|
||||
review.text = reviewText;
|
||||
review.clicked += () =>
|
||||
{
|
||||
Application.OpenURL(reviewURL);
|
||||
};
|
||||
#pragma warning restore
|
||||
}
|
||||
|
||||
private void FillScrollList(ScrollView patronsList)
|
||||
{
|
||||
foreach (var child in patronsList.Children())
|
||||
{
|
||||
child.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(supportersList))
|
||||
{
|
||||
var label = new Label("Loading supporters...");
|
||||
patronsList.Add(label);
|
||||
RequestSupporterText();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sponsors = supportersList.Split('\n');
|
||||
foreach (var sponsor in sponsors)
|
||||
{
|
||||
var label = new Label(sponsor);
|
||||
label.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||
patronsList.Add(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetInformationalVersionForType(System.Type type)
|
||||
{
|
||||
var assembly = type.Assembly;
|
||||
|
||||
var informationalVersionAttributes = assembly.GetCustomAttributes(
|
||||
typeof(AssemblyInformationalVersionAttribute),
|
||||
false) as AssemblyInformationalVersionAttribute[];
|
||||
|
||||
var informationalVersionAttribute = informationalVersionAttributes.FirstOrDefault();
|
||||
|
||||
string version = informationalVersionAttribute?.InformationalVersion ?? "<unknown version>";
|
||||
return version;
|
||||
}
|
||||
|
||||
private static bool ShouldShowAboutPage()
|
||||
{
|
||||
// turns out that headless mode doesn't prevent windows being summoned
|
||||
if (Application.isBatchMode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var version = Assembly.GetAssembly(typeof(DialogueRunner)).GetName().Version;
|
||||
|
||||
var settings = YarnSpinnerProjectSettings.GetOrCreateSettings();
|
||||
var storedVersion = settings.Version;
|
||||
|
||||
if (storedVersion.major != version.Major || storedVersion.minor != version.Minor)
|
||||
{
|
||||
settings.Version = (version.Major, version.Minor);
|
||||
settings.WriteSettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void EditorUpdate()
|
||||
{
|
||||
if (supportersRequest == null)
|
||||
{
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
return;
|
||||
}
|
||||
if (!supportersRequest.isDone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// regardless of the success or failure of the process we want to unregister the editor update
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
|
||||
bool isError = supportersRequest.result != UnityWebRequest.Result.Success;
|
||||
|
||||
if (isError)
|
||||
{
|
||||
supportersList = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
supportersList = supportersRequest.downloadHandler.text;
|
||||
|
||||
var extras = rootVisualElement.Q<VisualElement>("extras");
|
||||
var list = extras.Q<ScrollView>("patreonList");
|
||||
FillScrollList(list);
|
||||
list.MarkDirtyRepaint();
|
||||
}
|
||||
}
|
||||
private void RequestSupporterText()
|
||||
{
|
||||
// Start requesting the supporters text.
|
||||
supportersRequest = UnityWebRequest.Get("https://yarnspinner.dev/supporters.txt");
|
||||
supportersRequest.SendWebRequest();
|
||||
|
||||
// Run EditorUpdate every editor frame so that we can handle
|
||||
// when the request ends.
|
||||
EditorApplication.update += EditorUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42c76a8c72ee34e9f8c76e906b54d346
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_VisualTreeAsset: {fileID: 9197481963319205126, guid: 1184c485a8e5249aeb9253ff925af9c7,
|
||||
type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerEditorWindow.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,5 @@
|
||||
.custom-label {
|
||||
font-size: 20px;
|
||||
-unity-font-style: bold;
|
||||
color: rgb(68, 138, 255);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4f2c0e54086641babbe5855064e2c88
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerEditorWindow.uss
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,27 @@
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<Style src="project://database/Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerEditorWindow.uss?fileID=7433441132597879392&guid=b4f2c0e54086641babbe5855064e2c88&type=3#YarnSpinnerEditorWindow" />
|
||||
<engine:VisualElement style="flex-grow: 0; background-image: url("project://database/Packages/dev.yarnspinner.unity/Editor/Editors/Icons/YarnSpinnerLogo.png?fileID=21300000&guid=528a6dd601766934abb8b1053bd798ef&type=3#YarnSpinnerLogo"); -unity-background-scale-mode: scale-to-fit; min-height: 128px;" />
|
||||
<engine:Label text="Yarn Spinner for Unity" style="-unity-text-align: upper-center; -unity-font-style: bold; font-size: 32px; margin-top: 0;" />
|
||||
<engine:Label text="Thank you for using Yarn Spinner! Have fun adding dialogue to your amazing game!" style="margin-bottom: 8px; margin-top: 0; margin-left: 4px; -unity-text-align: upper-center; white-space: normal;" />
|
||||
<engine:Label text="Core Version: aaaaaaaa" name="coreVLabel" selectable="true" focusable="true" style="margin-bottom: 4px; margin-left: 8px; white-space: normal; font-size: 10px;" />
|
||||
<engine:Label text="Compiler Version: aaaaaaaa" name="compVLabel" selectable="true" focusable="true" style="margin-bottom: 4px; margin-left: 8px; white-space: normal; font-size: 10px;" />
|
||||
<engine:Label text="Unity Version: aaaaaaaa" name="unityVLabel" selectable="true" focusable="true" style="margin-bottom: 4px; margin-left: 8px; white-space: normal; font-size: 10px;" />
|
||||
<engine:VisualElement name="resources" style="flex-grow: 0;">
|
||||
<engine:Label text="Resources" style="-unity-font-style: bold; margin-top: 6px; margin-left: 4px;" />
|
||||
<engine:Label text="Here are some useful resources." style="margin-left: 4px;" />
|
||||
<engine:VisualElement name="buttons" style="flex-grow: 0; flex-direction: row; margin-left: 4px; margin-right: 4px;">
|
||||
<engine:Button text="Documentation" name="docs" style="flex-grow: 1;" />
|
||||
<engine:Button text="Support" name="support" style="flex-grow: 1;" />
|
||||
</engine:VisualElement>
|
||||
</engine:VisualElement>
|
||||
<engine:VisualElement name="extras" style="flex-grow: 1;">
|
||||
<engine:Label text="Extras" style="-unity-font-style: bold; margin-top: 6px; margin-left: 4px;" />
|
||||
<engine:Label text="Would you like to be included in the Yarn Spinner showcase on our website? Submit info about your game!" style="margin-left: 4px; white-space: normal;" />
|
||||
<engine:Button text="Submit your game" name="showcaseButton" style="margin-bottom: 4px; margin-left: 8px; margin-right: 8px;" />
|
||||
<engine:Label text="If you are enjoying Yarn Spinner, please consider writing a review of Yarn Spinner. It only takes a moment and it hugely helps us. Thank you!" name="reviewLabel" style="white-space: normal; margin-top: 6px; margin-left: 4px;" />
|
||||
<engine:Button text="Review on the Asset Store" name="reviewButton" style="margin-bottom: 4px; margin-left: 8px; margin-right: 8px;" />
|
||||
<engine:Label text="Yarn Spinner is made possible thanks to our wonderful supporters on Patreon. If you would like to join the Patreon, this would be much appreciated!" style="white-space: normal; margin-top: 6px; margin-left: 4px;" />
|
||||
<engine:Button text="Support Us On Patreon" name="patreonButton" style="margin-right: 8px; margin-left: 8px;" />
|
||||
<engine:ScrollView horizontal-scroller-visibility="Hidden" name="patreonList" style="flex-grow: 1;" />
|
||||
</engine:VisualElement>
|
||||
</engine:UXML>
|
||||
@@ -0,0 +1,17 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1184c485a8e5249aeb9253ff925af9c7
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerEditorWindow.uxml
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
/// Basic data class of unity settings that impact Yarn Spinner.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this only supports disabling the automatic reimport of Yarn Projects when locale assets change, but other settings will eventually end up here.
|
||||
/// </remarks>
|
||||
class YarnSpinnerProjectSettings
|
||||
{
|
||||
public static string YarnSpinnerProjectSettingsPath => Path.Combine("ProjectSettings", "Packages", "dev.yarnspinner", "YarnSpinnerProjectSettings.json");
|
||||
public static string YarnSpinnerGeneratedYSLSPath => Path.Combine("ProjectSettings", "Packages", "dev.yarnspinner", "generated.ysls.json");
|
||||
|
||||
public static string YarnSpinnerAssemblyGeneratedYSLSPath(string assemblyName)
|
||||
{
|
||||
return Path.Combine("ProjectSettings", "Packages", "dev.yarnspinner", $"{assemblyName}-generated.ysls.json");
|
||||
}
|
||||
|
||||
public bool autoRefreshLocalisedAssets = true;
|
||||
public bool automaticallyLinkAttributedYarnCommandsAndFunctions = true;
|
||||
public bool generateYSLSFile = true;
|
||||
public bool enableDirectLinkToVSCode = false;
|
||||
public (int major, int minor) Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return (majorVersion, minorVersion);
|
||||
}
|
||||
set
|
||||
{
|
||||
majorVersion = value.major;
|
||||
minorVersion = value.minor;
|
||||
}
|
||||
}
|
||||
public bool sortLocalisationValuesInsideStringTable = false;
|
||||
|
||||
private int majorVersion = 0;
|
||||
private int minorVersion = 0;
|
||||
|
||||
private const string automaticallyLinkAttributedYarnCommandsAndFunctionsKey = "automaticallyLinkAttributedYarnCommandsAndFunctions";
|
||||
private const string autoRefreshLocalisedAssetsKey = "autoRefreshLocalisedAssets";
|
||||
private const string generateYSLSFileKey = "generateYSLSFile";
|
||||
private const string enableDirectLinkToVSCodeKey = "enableDirectLinkToVSCode";
|
||||
private const string majorVersionKey = "majorVersion";
|
||||
private const string minorVersionKey = "minorVersion";
|
||||
private const string sortLocalisationValuesInsideStringTableKey = "sortLocalisationValuesInsideStringTable";
|
||||
|
||||
internal static YarnSpinnerProjectSettings GetOrCreateSettings(string? path = null, Yarn.Unity.ILogger? iLogger = null)
|
||||
{
|
||||
var settingsPath = YarnSpinnerProjectSettingsPath;
|
||||
if (path != null)
|
||||
{
|
||||
settingsPath = Path.Combine(path, YarnSpinnerProjectSettingsPath);
|
||||
}
|
||||
var logger = ValidLogger(iLogger);
|
||||
|
||||
YarnSpinnerProjectSettings settings = new YarnSpinnerProjectSettings();
|
||||
if (File.Exists(settingsPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var settingsData = File.ReadAllText(settingsPath);
|
||||
settings = FromJson(settingsData, logger);
|
||||
|
||||
return settings;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
logger.WriteException(e, $"Failed to load Yarn Spinner project settings at {settingsPath}");
|
||||
}
|
||||
}
|
||||
|
||||
settings.autoRefreshLocalisedAssets = true;
|
||||
settings.automaticallyLinkAttributedYarnCommandsAndFunctions = true;
|
||||
settings.generateYSLSFile = true;
|
||||
settings.majorVersion = 0;
|
||||
settings.minorVersion = 0;
|
||||
settings.sortLocalisationValuesInsideStringTable = false;
|
||||
settings.WriteSettings(path, logger);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static YarnSpinnerProjectSettings FromJson(string jsonString, Yarn.Unity.ILogger? iLogger = null)
|
||||
{
|
||||
var logger = ValidLogger(iLogger);
|
||||
|
||||
YarnSpinnerProjectSettings settings = new YarnSpinnerProjectSettings();
|
||||
|
||||
try
|
||||
{
|
||||
var jsonDict = Json.Deserialize(jsonString) as Dictionary<string, object>;
|
||||
|
||||
if (jsonDict == null)
|
||||
{
|
||||
logger.WriteLine($"Failed to parse Yarn Spinner project settings JSON");
|
||||
return settings;
|
||||
}
|
||||
|
||||
T GetValueOrDefault<T>(string key, T defaultValue)
|
||||
{
|
||||
if (jsonDict.TryGetValue(key, out object result))
|
||||
{
|
||||
return (T)System.Convert.ChangeType(result, typeof(T));
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
bool automaticallyLinkAttributedYarnCommandsAndFunctions = GetValueOrDefault(automaticallyLinkAttributedYarnCommandsAndFunctionsKey, true);
|
||||
bool autoRefreshLocalisedAssets = GetValueOrDefault(autoRefreshLocalisedAssetsKey, true);
|
||||
bool generateYSLSFile = GetValueOrDefault(generateYSLSFileKey, true);
|
||||
bool enableDirectLinkToVSCode = GetValueOrDefault(enableDirectLinkToVSCodeKey, false);
|
||||
int major = GetValueOrDefault(majorVersionKey, 0);
|
||||
int minor = GetValueOrDefault(minorVersionKey, 0);
|
||||
bool sortLocalisationValuesInsideStringTable = GetValueOrDefault(sortLocalisationValuesInsideStringTableKey, false);
|
||||
|
||||
settings.automaticallyLinkAttributedYarnCommandsAndFunctions = automaticallyLinkAttributedYarnCommandsAndFunctions;
|
||||
settings.autoRefreshLocalisedAssets = autoRefreshLocalisedAssets;
|
||||
settings.generateYSLSFile = generateYSLSFile;
|
||||
settings.enableDirectLinkToVSCode = enableDirectLinkToVSCode;
|
||||
settings.majorVersion = major;
|
||||
settings.minorVersion = minor;
|
||||
settings.sortLocalisationValuesInsideStringTable = sortLocalisationValuesInsideStringTable;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
logger.WriteException(ex);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
internal void WriteSettings(string? path = null, Yarn.Unity.ILogger? iLogger = null)
|
||||
{
|
||||
var logger = ValidLogger(iLogger);
|
||||
|
||||
var settingsPath = YarnSpinnerProjectSettingsPath;
|
||||
if (path != null)
|
||||
{
|
||||
settingsPath = Path.Combine(path, settingsPath);
|
||||
}
|
||||
|
||||
var dictForm = new System.Collections.Generic.Dictionary<string, object>();
|
||||
dictForm[automaticallyLinkAttributedYarnCommandsAndFunctionsKey] = this.automaticallyLinkAttributedYarnCommandsAndFunctions;
|
||||
dictForm[autoRefreshLocalisedAssetsKey] = this.autoRefreshLocalisedAssets;
|
||||
dictForm[generateYSLSFileKey] = this.generateYSLSFile;
|
||||
dictForm[enableDirectLinkToVSCodeKey] = this.enableDirectLinkToVSCode;
|
||||
dictForm[sortLocalisationValuesInsideStringTableKey] = this.sortLocalisationValuesInsideStringTable;
|
||||
dictForm[majorVersionKey] = this.majorVersion;
|
||||
dictForm[minorVersionKey] = this.minorVersion;
|
||||
|
||||
var jsonValue = Json.Serialize(dictForm);
|
||||
|
||||
var folder = Path.GetDirectoryName(settingsPath);
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(settingsPath, jsonValue);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
logger.WriteException(e, $"Failed to save Yarn Spinner project settings to {settingsPath}");
|
||||
}
|
||||
}
|
||||
|
||||
// if the provided logger is valid just return it
|
||||
// otherwise return the default logger
|
||||
private static Yarn.Unity.ILogger ValidLogger(Yarn.Unity.ILogger? iLogger)
|
||||
{
|
||||
var logger = iLogger;
|
||||
if (logger == null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
logger = new UnityLogger();
|
||||
#else
|
||||
logger = new NullLogger();
|
||||
#endif
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b525354f60f7742e6b5292fdb2d6d887
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerProjectSettings.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#nullable enable
|
||||
|
||||
class YarnSpinnerProjectSettingsProvider : SettingsProvider
|
||||
{
|
||||
private YarnSpinnerProjectSettings? baseSettings;
|
||||
private YarnSpinnerProjectSettings? unsavedSettings;
|
||||
private int settingWidth = 320;
|
||||
|
||||
public YarnSpinnerProjectSettingsProvider(string path, SettingsScope scope = SettingsScope.Project) : base(path, scope) { }
|
||||
|
||||
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||
{
|
||||
baseSettings = YarnSpinnerProjectSettings.GetOrCreateSettings();
|
||||
unsavedSettings = YarnSpinnerProjectSettings.GetOrCreateSettings();
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (unsavedSettings == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Internal error: {nameof(unsavedSettings)} is not set", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (baseSettings == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Internal error: {nameof(baseSettings)} is not set", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField("Automatic Recompilation and Asset Association");
|
||||
using (var changeCheck = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var localisedAssetUpdate = unsavedSettings.autoRefreshLocalisedAssets;
|
||||
var linkingAttributedFuncs = unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions;
|
||||
var generateYSLS = unsavedSettings.generateYSLSFile;
|
||||
var enableDirectLinkToVSCode = unsavedSettings.enableDirectLinkToVSCode;
|
||||
var sortLocalisationValuesInsideStringTable = unsavedSettings.sortLocalisationValuesInsideStringTable;
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Update Localised Assets", GUILayout.Width(settingWidth), GUILayout.ExpandWidth(false));
|
||||
localisedAssetUpdate = EditorGUILayout.Toggle(unsavedSettings.autoRefreshLocalisedAssets, GUILayout.ExpandWidth(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Generate linkings for Functions and Commands", GUILayout.Width(settingWidth), GUILayout.ExpandWidth(false));
|
||||
linkingAttributedFuncs = EditorGUILayout.Toggle(unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions, GUILayout.ExpandWidth(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Generate YSLS file for attributed methods", GUILayout.Width(settingWidth), GUILayout.ExpandWidth(false));
|
||||
generateYSLS = EditorGUILayout.Toggle(unsavedSettings.generateYSLSFile, GUILayout.ExpandWidth(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
#if USE_UNITY_LOCALIZATION
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Keep Unity Localization tables sorted", GUILayout.Width(settingWidth), GUILayout.ExpandWidth(false));
|
||||
sortLocalisationValuesInsideStringTable = EditorGUILayout.Toggle(unsavedSettings.sortLocalisationValuesInsideStringTable, GUILayout.ExpandWidth(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
#endif
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Editor overrides");
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Enable direct connection to VS Code for Yarn Scripts", GUILayout.Width(settingWidth), GUILayout.ExpandWidth(false));
|
||||
enableDirectLinkToVSCode = EditorGUILayout.Toggle(unsavedSettings.enableDirectLinkToVSCode, GUILayout.ExpandWidth(false));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (changeCheck.changed)
|
||||
{
|
||||
unsavedSettings.autoRefreshLocalisedAssets = localisedAssetUpdate;
|
||||
unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions = linkingAttributedFuncs;
|
||||
unsavedSettings.generateYSLSFile = generateYSLS;
|
||||
unsavedSettings.enableDirectLinkToVSCode = enableDirectLinkToVSCode;
|
||||
unsavedSettings.sortLocalisationValuesInsideStringTable = sortLocalisationValuesInsideStringTable;
|
||||
}
|
||||
|
||||
bool disabledReimportButton = true;
|
||||
if
|
||||
(
|
||||
unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions != baseSettings.automaticallyLinkAttributedYarnCommandsAndFunctions ||
|
||||
unsavedSettings.autoRefreshLocalisedAssets != baseSettings.autoRefreshLocalisedAssets ||
|
||||
unsavedSettings.generateYSLSFile != baseSettings.generateYSLSFile ||
|
||||
unsavedSettings.enableDirectLinkToVSCode != baseSettings.enableDirectLinkToVSCode ||
|
||||
unsavedSettings.sortLocalisationValuesInsideStringTable != baseSettings.sortLocalisationValuesInsideStringTable
|
||||
)
|
||||
{
|
||||
disabledReimportButton = false;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
using (new EditorGUI.DisabledScope(disabledReimportButton))
|
||||
{
|
||||
if (GUILayout.Button("Apply Changes", GUILayout.Width(200)))
|
||||
{
|
||||
// we need to know which parts we will need to reimport
|
||||
// we check and change the setting first
|
||||
// because the settings are used in the reimports that are about to be run
|
||||
// and only then can we do the appropriate reimports
|
||||
bool needsCSharpRecompilation = false;
|
||||
bool needsYarnProjectReimport = false;
|
||||
|
||||
if (baseSettings.autoRefreshLocalisedAssets != unsavedSettings.autoRefreshLocalisedAssets)
|
||||
{
|
||||
needsYarnProjectReimport = true;
|
||||
}
|
||||
if (baseSettings.automaticallyLinkAttributedYarnCommandsAndFunctions != unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions)
|
||||
{
|
||||
needsCSharpRecompilation = true;
|
||||
}
|
||||
if (baseSettings.generateYSLSFile != unsavedSettings.generateYSLSFile)
|
||||
{
|
||||
needsCSharpRecompilation = true;
|
||||
}
|
||||
if (baseSettings.sortLocalisationValuesInsideStringTable != unsavedSettings.sortLocalisationValuesInsideStringTable)
|
||||
{
|
||||
needsYarnProjectReimport = true;
|
||||
}
|
||||
|
||||
// saving the changed settings out to disk
|
||||
baseSettings.autoRefreshLocalisedAssets = unsavedSettings.autoRefreshLocalisedAssets;
|
||||
baseSettings.automaticallyLinkAttributedYarnCommandsAndFunctions = unsavedSettings.automaticallyLinkAttributedYarnCommandsAndFunctions;
|
||||
baseSettings.generateYSLSFile = unsavedSettings.generateYSLSFile;
|
||||
baseSettings.enableDirectLinkToVSCode = unsavedSettings.enableDirectLinkToVSCode;
|
||||
baseSettings.sortLocalisationValuesInsideStringTable = unsavedSettings.sortLocalisationValuesInsideStringTable;
|
||||
baseSettings.WriteSettings();
|
||||
|
||||
// now we can reimport
|
||||
if (needsCSharpRecompilation)
|
||||
{
|
||||
// need to do a full build because if they have DISABLED this then we want to turf the already linked code
|
||||
// this is BIG but I can't see any other way around this
|
||||
// I am assuming people aren't doing this so often as to be a huge headache
|
||||
CompilationPipeline.RequestScriptCompilation(RequestScriptCompilationOptions.CleanBuildCache);
|
||||
}
|
||||
if (needsYarnProjectReimport)
|
||||
{
|
||||
// here we just reimport the yarn projects
|
||||
var yarnProjects = AssetDatabase.FindAssets($"t:{nameof(YarnProject)}");
|
||||
foreach (var guid in yarnProjects)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
AssetDatabase.ImportAsset(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Register the SettingsProvider
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateYarnSpinnerProjectSettingsProvider()
|
||||
{
|
||||
var provider = new YarnSpinnerProjectSettingsProvider("Project/Yarn Spinner", SettingsScope.Project);
|
||||
|
||||
var keywords = new List<string>() { "yarn", "spinner", "localisation", "codegen", "attribute" };
|
||||
provider.keywords = keywords;
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ba3b32b8f5dd4ee0abbb05c8eef314a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnSpinnerProjectSettingsProvider.cs
|
||||
uploadId: 968678
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
#if !USE_TMP
|
||||
using UnityEditor;
|
||||
|
||||
namespace Yarn.Unity.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// When TextMeshPro (com.unity.textmeshpro) or UGUI 2.0.0+ (com.unity.ugui) are not present in the project, TMP is not supported.<br/>
|
||||
/// This editor will draw a help box for the classes that require TMP to function.
|
||||
/// </summary>
|
||||
public abstract class YarnTextMeshProFallbackEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
#if UNITY_2023_2_OR_NEWER
|
||||
EditorGUILayout.HelpBox("This component requires uGUI 2.0.0 or above (com.unity.ugui) be installed in the Package Manager.", MessageType.Warning);
|
||||
#else
|
||||
EditorGUILayout.HelpBox("This component requires TextMeshPro (com.unity.textmeshpro) be installed in the Package Manager.", MessageType.Warning);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(LineView))]
|
||||
public sealed class LineViewEditorFallback : YarnTextMeshProFallbackEditor { }
|
||||
|
||||
[CustomEditor(typeof(OptionsListView))]
|
||||
public sealed class OptionsListViewEditorFallback : YarnTextMeshProFallbackEditor { }
|
||||
|
||||
[CustomEditor(typeof(CharacterColorView))]
|
||||
public sealed class CharacterColorViewEditorFallback : YarnTextMeshProFallbackEditor { }
|
||||
|
||||
[CustomEditor(typeof(OptionView))]
|
||||
public sealed class OptionViewEditorFallback : YarnTextMeshProFallbackEditor { }
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20204a7ba9004a3db629284f50991ae6
|
||||
timeCreated: 1684292521
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 267061
|
||||
packageName: Yarn Spinner+ for Unity, the friendly dialogue and narrative tool
|
||||
packageVersion: 3.2.8
|
||||
assetPath: Packages/dev.yarnspinner.unity/Editor/Editors/YarnTextMeshProFallbackEditor.cs
|
||||
uploadId: 968678
|
||||