同步
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
[Serializable]
|
||||
public class LineMetadata
|
||||
{
|
||||
[Serializable]
|
||||
class StringDictionary : SerializableDictionary<string, string> { }
|
||||
|
||||
[SerializeField]
|
||||
private StringDictionary _lineMetadata = new StringDictionary();
|
||||
|
||||
internal LineMetadata(IEnumerable<LineMetadataTableEntry> lineMetadataTableEntries)
|
||||
{
|
||||
AddMetadata(lineMetadataTableEntries);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds any metadata if they are defined for each line. The metadata is
|
||||
/// internally stored as a single string with each piece of metadata
|
||||
/// separated by a single whitespace.
|
||||
/// </summary>
|
||||
/// <param name="lineMetadataTableEntries">IEnumerable with metadata
|
||||
/// entries.</param>
|
||||
internal void AddMetadata(IEnumerable<LineMetadataTableEntry> lineMetadataTableEntries)
|
||||
{
|
||||
foreach (var entry in lineMetadataTableEntries)
|
||||
{
|
||||
if (entry.Metadata.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_lineMetadata.Add(entry.ID, String.Join(" ", entry.Metadata));
|
||||
}
|
||||
}
|
||||
|
||||
public LineMetadata() { }
|
||||
|
||||
public void AddMetadata(string lineID, IEnumerable<string> metadata)
|
||||
{
|
||||
_lineMetadata.Add(lineID, string.Join(" ", metadata));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the line IDs that contain metadata.
|
||||
/// </summary>
|
||||
/// <returns>The line IDs.</returns>
|
||||
public IEnumerable<string> GetLineIDs()
|
||||
{
|
||||
// The object returned doesn't allow modifications and is kept in
|
||||
// sync with `_lineMetadata`.
|
||||
return _lineMetadata.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns metadata for a given line ID, if any is defined.
|
||||
/// </summary>
|
||||
/// <param name="lineID">The line ID.</param>
|
||||
/// <returns>An array of each piece of metadata if defined, otherwise
|
||||
/// returns null.</returns>
|
||||
public string[]? GetMetadata(string lineID)
|
||||
{
|
||||
if (_lineMetadata.TryGetValue(lineID, out var result))
|
||||
{
|
||||
return result.Split(' ');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string? GetShadowLineSource(string lineID)
|
||||
{
|
||||
if (_lineMetadata.TryGetValue(lineID, out var metadataString) == false)
|
||||
{
|
||||
// The line has no metadata, so it is not a shadow line.
|
||||
return null;
|
||||
}
|
||||
|
||||
var metadata = metadataString.Split(' ');
|
||||
|
||||
foreach (var metadataEntry in metadata)
|
||||
{
|
||||
if (metadataEntry.StartsWith("shadow:"))
|
||||
{
|
||||
// This is a shadow line. Return the line ID that it's
|
||||
// shadowing.
|
||||
return "line:" + metadataEntry.Substring("shadow:".Length);
|
||||
}
|
||||
}
|
||||
|
||||
// The line had metadata, but it wasn't a shadow line.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcb7ff0ed8491e845a63b50f1c5f7130
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using CsvHelper;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
/// <summary>
|
||||
/// Struct holding information about a line and its associated metadata.
|
||||
/// Only used internally as an intermediary before persisting information
|
||||
/// in either a `YarnProject` or a CSV file.
|
||||
/// </summary>
|
||||
internal struct LineMetadataTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The line ID for this line.
|
||||
/// </summary>
|
||||
public string ID;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the Yarn script in which this line was originally
|
||||
/// found.
|
||||
/// </summary>
|
||||
public string File;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the node in which this line was originally found.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This node can be found in the file indicated by <see
|
||||
/// cref="File"/>.
|
||||
/// </remarks>
|
||||
public string Node;
|
||||
|
||||
/// <summary>
|
||||
/// The line number in the file indicated by <see cref="File"/> at
|
||||
/// which the original version of this line can be found.
|
||||
/// </summary>
|
||||
public string LineNumber;
|
||||
|
||||
/// <summary>
|
||||
/// Additional metadata included in this line.
|
||||
/// </summary>
|
||||
public string[] Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LineMetadataTableEntry"/>
|
||||
/// struct, copying values from an existing instance.
|
||||
/// </summary>
|
||||
/// <param name="s">The instance to copy values from.</param>
|
||||
public LineMetadataTableEntry(LineMetadataTableEntry s)
|
||||
{
|
||||
ID = s.ID;
|
||||
File = s.File;
|
||||
Node = s.Node;
|
||||
LineNumber = s.LineNumber;
|
||||
Metadata = s.Metadata;
|
||||
}
|
||||
|
||||
private static CsvHelper.Configuration.Configuration? CsvConfiguration;
|
||||
|
||||
private static CsvHelper.Configuration.Configuration GetConfiguration()
|
||||
{
|
||||
if (CsvConfiguration == null)
|
||||
{
|
||||
CsvConfiguration = new CsvHelper.Configuration.Configuration(System.Globalization.CultureInfo.InvariantCulture)
|
||||
{
|
||||
MemberTypes = CsvHelper.Configuration.MemberTypes.Fields,
|
||||
};
|
||||
}
|
||||
return CsvConfiguration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads comma-separated value data from <paramref name="sourceText"/>,
|
||||
/// and produces a collection of <see cref="LineMetadataTableEntry"/> structs.
|
||||
/// </summary>
|
||||
/// <param name="sourceText">A string containing CSV-formatted
|
||||
/// data.</param>
|
||||
/// <returns>The parsed collection of <see cref="LineMetadataTableEntry"/>
|
||||
/// structs.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when an error occurs when
|
||||
/// parsing the string.</exception>
|
||||
internal static IEnumerable<LineMetadataTableEntry> ParseFromCSV(string sourceText)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stringReader = new System.IO.StringReader(sourceText))
|
||||
using (var csv = new CsvReader(stringReader, GetConfiguration()))
|
||||
{
|
||||
/*
|
||||
Do the below instead of GetRecords<T> due to
|
||||
incompatibility with IL2CPP See more:
|
||||
https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues/36#issuecomment-691489913
|
||||
*/
|
||||
var records = new List<LineMetadataTableEntry>();
|
||||
csv.Read();
|
||||
csv.ReadHeader();
|
||||
while (csv.Read())
|
||||
{
|
||||
// Fetch values; if they can't be found, they'll be
|
||||
// defaults.
|
||||
csv.TryGetField<string>("id", out var id);
|
||||
csv.TryGetField<string>("file", out var file);
|
||||
csv.TryGetField<string>("node", out var node);
|
||||
csv.TryGetField<string>("lineNumber", out var lineNumber);
|
||||
csv.TryGetField<string>("metadata", out var metadata);
|
||||
|
||||
var record = new LineMetadataTableEntry
|
||||
{
|
||||
ID = id ?? string.Empty,
|
||||
File = file ?? string.Empty,
|
||||
Node = node ?? string.Empty,
|
||||
LineNumber = lineNumber ?? string.Empty,
|
||||
Metadata = metadata?.Split(' ') ?? new string[] { },
|
||||
};
|
||||
|
||||
records.Add(record);
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
}
|
||||
catch (CsvHelperException e)
|
||||
{
|
||||
throw new System.ArgumentException($"Error reading CSV file: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CSV-formatted string containing data from <paramref
|
||||
/// name="entries"/>.
|
||||
/// </summary>
|
||||
/// <param name="entries">The <see cref="LineMetadataTableEntry"/> values to
|
||||
/// generate the spreadsheet from.</param>
|
||||
/// <returns>A string containing CSV-formatted data.</returns>
|
||||
public static string CreateCSV(IEnumerable<LineMetadataTableEntry> entries)
|
||||
{
|
||||
using (var textWriter = new System.IO.StringWriter())
|
||||
{
|
||||
// Use the invariant culture when writing the CSV
|
||||
var csv = new CsvWriter(
|
||||
textWriter, // write into this stream
|
||||
GetConfiguration() // use this configuration
|
||||
);
|
||||
|
||||
var fieldNames = new[] {
|
||||
"id",
|
||||
"file",
|
||||
"node",
|
||||
"lineNumber",
|
||||
"metadata",
|
||||
};
|
||||
|
||||
foreach (var field in fieldNames)
|
||||
{
|
||||
csv.WriteField(field);
|
||||
}
|
||||
csv.NextRecord();
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var values = new[] {
|
||||
entry.ID,
|
||||
entry.File,
|
||||
entry.Node,
|
||||
entry.LineNumber,
|
||||
string.Join(" ", entry.Metadata),
|
||||
};
|
||||
foreach (var value in values)
|
||||
{
|
||||
csv.WriteField(value);
|
||||
}
|
||||
csv.NextRecord();
|
||||
}
|
||||
|
||||
return textWriter.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"LineMetadataTableEntry: id={ID} file={File} node={Node} line={LineNumber} metadata={string.Join(" ", Metadata)}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is LineMetadataTableEntry entry &&
|
||||
ID == entry.ID &&
|
||||
File == entry.File &&
|
||||
Node == entry.Node &&
|
||||
LineNumber == entry.LineNumber &&
|
||||
Enumerable.SequenceEqual(Metadata, entry.Metadata);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var result =
|
||||
ID.GetHashCode() ^
|
||||
File.GetHashCode() ^
|
||||
Node.GetHashCode() ^
|
||||
LineNumber.GetHashCode();
|
||||
|
||||
foreach (var piece in Metadata)
|
||||
{
|
||||
result ^= piece.GetHashCode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eacced505fcfb6f41808a8add9f10aec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using CsvHelper;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
public struct StringTableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The language that the line is written in.
|
||||
/// </summary>
|
||||
public string Language;
|
||||
|
||||
/// <summary>
|
||||
/// The line ID for this line. This value will be the same across all
|
||||
/// localizations.
|
||||
/// </summary>
|
||||
public string ID;
|
||||
|
||||
/// <summary>
|
||||
/// The text of this line, in the language specified by <see
|
||||
/// cref="Language"/>.
|
||||
/// </summary>
|
||||
public string? Text;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the Yarn script in which this line was originally found.
|
||||
/// </summary>
|
||||
public string File;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the node in which this line was originally found.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This node can be found in the file indicated by <see cref="File"/>.
|
||||
/// </remarks>
|
||||
public string Node;
|
||||
|
||||
/// <summary>
|
||||
/// The line number in the file indicated by <see cref="File"/> at which
|
||||
/// the original version of this line can be found.
|
||||
/// </summary>
|
||||
public string LineNumber;
|
||||
|
||||
/// <summary>
|
||||
/// A string used as part of a mechanism for checking if translated
|
||||
/// versions of this string are out of date.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This field contains the first 8 characters of the SHA-256 hash of
|
||||
/// the line's text as it appeared in the base localization CSV file.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When a new StringTableEntry is created in a localized CSV file for a
|
||||
/// .yarn file, the Lock value is copied over from the base CSV file,
|
||||
/// and used for the translated entry.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Because the base localization CSV is regenerated every time the
|
||||
/// .yarn file is imported, the base localization Lock value will change
|
||||
/// if a line's text changes. This means that if the base lock and
|
||||
/// translated lock differ, the translated line is out of date, and
|
||||
/// needs to be updated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public string Lock;
|
||||
|
||||
/// <summary>
|
||||
/// A comment used to describe this line to translators.
|
||||
/// </summary>
|
||||
public string Comment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StringTableEntry"/>
|
||||
/// struct, copying values from an existing instance.
|
||||
/// </summary>
|
||||
/// <param name="s">The instance to copy values from.</param>
|
||||
public StringTableEntry(StringTableEntry s)
|
||||
{
|
||||
ID = s.ID;
|
||||
Text = s.Text;
|
||||
File = s.File;
|
||||
Node = s.Node;
|
||||
LineNumber = s.LineNumber;
|
||||
Lock = s.Lock;
|
||||
Comment = s.Comment;
|
||||
Language = s.Language;
|
||||
}
|
||||
|
||||
private static CsvHelper.Configuration.Configuration? CsvConfiguration;
|
||||
|
||||
private static CsvHelper.Configuration.Configuration GetConfiguration()
|
||||
{
|
||||
if (CsvConfiguration == null)
|
||||
{
|
||||
CsvConfiguration = new CsvHelper.Configuration.Configuration(System.Globalization.CultureInfo.InvariantCulture)
|
||||
{
|
||||
MemberTypes = CsvHelper.Configuration.MemberTypes.Fields,
|
||||
};
|
||||
}
|
||||
return CsvConfiguration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads comma-separated value data from <paramref name="sourceText"/>,
|
||||
/// and produces a collection of <see cref="StringTableEntry"/> structs.
|
||||
/// </summary>
|
||||
/// <param name="sourceText">A string containing CSV-formatted
|
||||
/// data.</param>
|
||||
/// <returns>The parsed collection of <see cref="StringTableEntry"/>
|
||||
/// structs.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when an error occurs when
|
||||
/// parsing the string.</exception>
|
||||
public static IEnumerable<StringTableEntry> ParseFromCSV(string sourceText)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stringReader = new System.IO.StringReader(sourceText))
|
||||
using (var csv = new CsvReader(stringReader, GetConfiguration()))
|
||||
{
|
||||
/*
|
||||
Do the below instead of GetRecords<T> due to incompatibility
|
||||
with IL2CPP See more:
|
||||
https://github.com/YarnSpinnerTool/YarnSpinner-Unity/issues/36#issuecomment-691489913
|
||||
*/
|
||||
var records = new List<StringTableEntry>();
|
||||
csv.Read();
|
||||
csv.ReadHeader();
|
||||
while (csv.Read())
|
||||
{
|
||||
// Fetch values; if they can't be found, they'll be
|
||||
// defaults.
|
||||
csv.TryGetField<string>("language", out var language);
|
||||
csv.TryGetField<string>("lock", out var lockString);
|
||||
csv.TryGetField<string>("comment", out var comment);
|
||||
csv.TryGetField<string>("id", out var id);
|
||||
csv.TryGetField<string>("text", out var text);
|
||||
csv.TryGetField<string>("file", out var file);
|
||||
csv.TryGetField<string>("node", out var node);
|
||||
csv.TryGetField<string>("lineNumber", out var lineNumber);
|
||||
|
||||
var record = new StringTableEntry
|
||||
{
|
||||
Language = language ?? string.Empty,
|
||||
ID = id ?? string.Empty,
|
||||
Text = text ?? string.Empty,
|
||||
File = file ?? string.Empty,
|
||||
Node = node ?? string.Empty,
|
||||
LineNumber = lineNumber ?? string.Empty,
|
||||
Lock = lockString ?? string.Empty,
|
||||
Comment = comment ?? string.Empty,
|
||||
};
|
||||
|
||||
records.Add(record);
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
}
|
||||
catch (CsvHelperException e)
|
||||
{
|
||||
throw new System.ArgumentException($"Error reading CSV file: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CSV-formatted string containing data from <paramref
|
||||
/// name="entries"/>.
|
||||
/// </summary>
|
||||
/// <param name="entries">The <see cref="StringTableEntry"/> values to
|
||||
/// generate the spreadsheet from.</param>
|
||||
/// <returns>A string containing CSV-formatted data.</returns>
|
||||
public static string CreateCSV(IEnumerable<StringTableEntry> entries)
|
||||
{
|
||||
using (var textWriter = new System.IO.StringWriter())
|
||||
{
|
||||
// Generate the localised .csv file
|
||||
|
||||
// Use the invariant culture when writing the CSV
|
||||
var csv = new CsvHelper.CsvWriter(
|
||||
textWriter, // write into this stream
|
||||
GetConfiguration() // use this configuration
|
||||
);
|
||||
|
||||
var fieldNames = new[] {
|
||||
"language",
|
||||
"id",
|
||||
"text",
|
||||
"file",
|
||||
"node",
|
||||
"lineNumber",
|
||||
"lock",
|
||||
"comment",
|
||||
};
|
||||
|
||||
foreach (var field in fieldNames)
|
||||
{
|
||||
csv.WriteField(field);
|
||||
}
|
||||
csv.NextRecord();
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var values = new[] {
|
||||
entry.Language,
|
||||
entry.ID,
|
||||
entry.Text,
|
||||
entry.File,
|
||||
entry.Node,
|
||||
entry.LineNumber,
|
||||
entry.Lock,
|
||||
entry.Comment,
|
||||
};
|
||||
foreach (var value in values)
|
||||
{
|
||||
csv.WriteField(value);
|
||||
}
|
||||
csv.NextRecord();
|
||||
}
|
||||
|
||||
return textWriter.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"StringTableEntry: lang={Language} id={ID} text=\"{Text}\" file={File} node={Node} line={LineNumber} lock={Lock} comment={Comment}";
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is StringTableEntry entry &&
|
||||
Language == entry.Language &&
|
||||
ID == entry.ID &&
|
||||
Text == entry.Text &&
|
||||
File == entry.File &&
|
||||
Node == entry.Node &&
|
||||
LineNumber == entry.LineNumber &&
|
||||
Lock == entry.Lock &&
|
||||
Comment == entry.Comment;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return
|
||||
Language.GetHashCode() ^
|
||||
ID.GetHashCode() ^
|
||||
(Text?.GetHashCode() ?? 1) ^
|
||||
File.GetHashCode() ^
|
||||
Node.GetHashCode() ^
|
||||
LineNumber.GetHashCode() ^
|
||||
Lock.GetHashCode() ^
|
||||
Comment.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4a614ed0869649379fe8285d2a97759
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Yarn Spinner is licensed to you under the terms found in the file LICENSE.md.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Yarn.Unity
|
||||
{
|
||||
[HelpURL("https://docs.yarnspinner.dev/using-yarnspinner-with-unity/importing-yarn-files/yarn-projects")]
|
||||
public sealed class YarnProject : ScriptableObject
|
||||
{
|
||||
[HideInInspector]
|
||||
public byte[]? compiledYarnProgram;
|
||||
|
||||
[HideInInspector]
|
||||
[NotNull]
|
||||
#pragma warning disable CS8618
|
||||
public Localization baseLocalization;
|
||||
#pragma warning restore CS8618
|
||||
|
||||
[SerializeField]
|
||||
[HideInInspector]
|
||||
public SerializableDictionary<string, Localization> localizations = new SerializableDictionary<string, Localization>();
|
||||
|
||||
public LineMetadata? lineMetadata;
|
||||
|
||||
[HideInInspector]
|
||||
public LocalizationType localizationType;
|
||||
|
||||
/// <summary>
|
||||
/// The cached result of deserializing <see
|
||||
/// cref="compiledYarnProgram"/>.
|
||||
/// </summary>
|
||||
private Program? cachedProgram = null;
|
||||
|
||||
/// <summary>
|
||||
/// The names of all nodes contained within the <see cref="Program"/>.
|
||||
/// </summary>
|
||||
public string[] NodeNames
|
||||
{
|
||||
get
|
||||
{
|
||||
return Program.Nodes.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct ShadowTableEntry
|
||||
{
|
||||
public string sourceLineID;
|
||||
public string[] shadowMetadata;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class ShadowTableDictionary : SerializableDictionary<string, ShadowTableEntry> { }
|
||||
|
||||
/// <summary>
|
||||
/// The cached result of reading the default values from the <see
|
||||
/// cref="Program"/>.
|
||||
/// </summary>
|
||||
private Dictionary<string, System.IConvertible>? initialValues;
|
||||
|
||||
/// <summary>
|
||||
/// The default values of all declared or inferred variables in the <see
|
||||
/// cref="Program"/>. Organised by their name as written in the yarn
|
||||
/// files.
|
||||
/// </summary>
|
||||
public Dictionary<string, System.IConvertible> InitialValues
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initialValues != null)
|
||||
{
|
||||
return initialValues;
|
||||
}
|
||||
|
||||
initialValues = new Dictionary<string, System.IConvertible>();
|
||||
|
||||
foreach (var pair in Program.InitialValues)
|
||||
{
|
||||
var value = pair.Value;
|
||||
switch (value.ValueCase)
|
||||
{
|
||||
case Yarn.Operand.ValueOneofCase.StringValue:
|
||||
{
|
||||
initialValues[pair.Key] = value.StringValue;
|
||||
break;
|
||||
}
|
||||
case Yarn.Operand.ValueOneofCase.BoolValue:
|
||||
{
|
||||
initialValues[pair.Key] = value.BoolValue;
|
||||
break;
|
||||
}
|
||||
case Yarn.Operand.ValueOneofCase.FloatValue:
|
||||
{
|
||||
initialValues[pair.Key] = value.FloatValue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Debug.LogWarning($"{pair.Key} is of an invalid type: {value.ValueCase}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return initialValues;
|
||||
}
|
||||
}
|
||||
|
||||
// ok assumption is that this can be lazy loaded and then kept around as
|
||||
// not every node has headers you care about but some will and be read A
|
||||
// LOT so we will fill a dict on request and just keep it around is
|
||||
// somewhat unnecessary as people can get this out themselves if they
|
||||
// want but I think peeps will wanna use headers like a dictionary so we
|
||||
// will do the transformation for you
|
||||
private Dictionary<string, Dictionary<string, List<string>>> nodeHeaders = new Dictionary<string, Dictionary<string, List<string>>>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the headers for the requested node.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The first time this is called, the values are extracted from <see
|
||||
/// cref="Program"/> and cached inside <see cref="nodeHeaders"/>. Future
|
||||
/// calls will then return the cached values.
|
||||
/// </remarks>
|
||||
[System.Obsolete("Use " + nameof(Dialogue) + "." + nameof(Dialogue.GetHeaders), true)]
|
||||
public Dictionary<string, List<string>> GetHeaders(string nodeName)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Localization given a locale code.
|
||||
/// </summary>
|
||||
/// <param name="localeCode">The locale code to find a <see
|
||||
/// cref="Localization"/> for.</param>
|
||||
/// <returns>The Localization if one is found for the locale <paramref
|
||||
/// name="localeCode"/>; <see cref="baseLocalization"/>
|
||||
/// otherwise.</returns>
|
||||
public Localization GetLocalization(string localeCode)
|
||||
{
|
||||
// If localeCode is null, we use the base localization.
|
||||
if (localeCode == null)
|
||||
{
|
||||
return baseLocalization;
|
||||
}
|
||||
|
||||
if (localizations.TryGetValue(localeCode, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// We didn't find a localization. Fall back to the Base
|
||||
// localization.
|
||||
return baseLocalization;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all line and option IDs within the requested nodes
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is intended to be used either to precache multiple nodes worth
|
||||
/// of lines or for debugging
|
||||
/// </remarks>
|
||||
/// <param name="nodes">the names of all nodes whos line IDs you
|
||||
/// covet</param>
|
||||
/// <returns>The ids of all lines and options in the requested <paramref
|
||||
/// name="nodes"/> </returns>
|
||||
public IEnumerable<string> GetLineIDsForNodes(IEnumerable<string> nodes)
|
||||
{
|
||||
var ids = new List<string>();
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
var lines = Program.LineIDsForNode(node);
|
||||
if (lines != null)
|
||||
{
|
||||
ids.AddRange(lines);
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Yarn Program stored in this project.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The first time this is called, the program stored in <see
|
||||
/// cref="compiledYarnProgram"/> is deserialized and cached. Future
|
||||
/// calls to this method will return the cached value.
|
||||
/// </remarks>
|
||||
public Program Program
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedProgram == null)
|
||||
{
|
||||
cachedProgram = Program.Parser.ParseFrom(compiledYarnProgram);
|
||||
}
|
||||
return cachedProgram;
|
||||
}
|
||||
}
|
||||
private void Awake()
|
||||
{
|
||||
// We have to invalidate the cache on Awake. Note that this cannot
|
||||
// be done through the importer (e.g., with a setter method that
|
||||
// sets compiledYarnProgram and invalidates cachedProgram) because
|
||||
// the YarnProject the importer accesses is NOT the same object as
|
||||
// the one currently loaded in the editor. (You can tell by
|
||||
// comparing their HashCodes) If there are other sources that can
|
||||
// change the value of compiledYarnProgram aside from the importer
|
||||
// in runtime, maybe we can add such a method, but until then, this
|
||||
// is sufficient.
|
||||
cachedProgram = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum LocalizationType
|
||||
{
|
||||
YarnInternal,
|
||||
Unity,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca200c7010639400ab741813a61274b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: f6a533d9225cd40ea9ded31d4f686e3b, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user