/* Yarn Spinner is licensed to you under the terms found in the file LICENSE.md. */ using System.Collections; using System.Collections.Generic; using System.Text; using UnityEngine; using Yarn.Markup; using Yarn.Unity; #nullable enable /// /// An attribute marker processor that uses a to /// apply TextMeshPro styling tags to a line. /// /// This marker processor registers itself as a handler for markers /// whose name is equal to the name of a style in the given palette. For /// example, if the palette defines a style named "happy", this marker processor /// will process tags in a Yarn line named [happy] by inserting the /// appropriate TextMeshProp style tags defined for the "happy" style. public sealed class PaletteMarkerProcessor : Yarn.Unity.ReplacementMarkupHandler { /// /// The to use when applying styles. /// [Tooltip("The MarkupPalette to use when applying styles.")] public MarkupPalette? palette; /// /// The line provider to register this markup processor with. /// [Tooltip("The LineProviderBehaviour to register this markup processor with.")] public LineProviderBehaviour? lineProvider; /// /// /// Processes a replacement marker by applying the style from the given /// palette. /// /// The marker to process. /// A StringBuilder to build the styled text in. /// An optional list of child attributes to /// apply, but this is ignored for TextMeshPro styles. /// The locale code to use when formatting the style. /// A list of markup diagnostics if there are any errors, otherwise an empty list. public override ReplacementMarkerResult ProcessReplacementMarker(MarkupAttribute marker, StringBuilder childBuilder, List childAttributes, string localeCode) { if (palette == null) { var error = new List() { new LineParser.MarkupDiagnostic($"can't apply palette for marker {marker.Name}, because a palette was not set") }; return new ReplacementMarkerResult(error, 0); } if (palette.PaletteForMarker(marker.Name, out var format)) { var childrenLength = childBuilder.Length; childBuilder.Insert(0, format.Start); childBuilder.Append(format.End); // finally we need to know if we have to offset the markers // most of the time we won't have to do anything if (format.MarkerOffset != 0) { // we now need to move any children attributes down by however many characters were added to the front // this is only the case if visible glyphs were added // as in for example adding to the front doesn't add any visible glyphs so won't need to offset anything // and because markers are all 0-offset relative to parents for (int i = 0; i < childAttributes.Count; i++) { childAttributes[i] = childAttributes[i].Shift(format.MarkerOffset); } } // finally we need to calculate the number of invisible characters we added // which is the difference between the new and original string lengths - the total number of visible characters inserted // we don't care WHERE those visible characters were added, just that they were // we can't just use the marker offset because that only worries about visible elements added at the front of the string // most of the time this is just gonna be 0 anyways and you don't have to think about it return new ReplacementMarkerResult(childBuilder.Length - childrenLength - format.TotalVisibleCharacterCount); } var diagnostics = new List() { new LineParser.MarkupDiagnostic($"was unable to find a matching sprite for {marker.Name}") }; return new ReplacementMarkerResult(diagnostics, 0); } /// /// Called by Unity when this script is enabled to register itself with . /// private void Start() { if (palette == null) { return; } if (palette.BasicMarkers.Count == 0) { return; } if (lineProvider == null) { var runner = DialogueRunner.FindRunner(this); if (runner == null) { Debug.LogWarning("Was unable to find a dialogue runner, unable to register the markup palettes."); return; } lineProvider = (LineProviderBehaviour)runner.LineProvider; } foreach (var marker in palette.BasicMarkers) { lineProvider.RegisterMarkerProcessor(marker.Marker, this); } foreach (var marker in palette.CustomMarkers) { lineProvider.RegisterMarkerProcessor(marker.Marker, this); } } }