// Copyright (c) 2024 Augie R. Maddox, Guavaman Enterprises. All rights reserved. #pragma warning disable 0649 namespace Rewired.Glyphs { using Rewired; using Interfaces; using System; using System.Collections.Generic; /// /// Manages glyphs. /// public class GlyphProvider : UnityEngine.MonoBehaviour, IGlyphProvider { [UnityEngine.SerializeField] [UnityEngine.Tooltip("Determines if glyphs should be fetched immediately in bulk when available. If false, glyphs will be fetched when queried.")] private bool _prefetch; [UnityEngine.SerializeField] [UnityEngine.Tooltip("A list of glyph set collections. At least one collection must be assigned.")] private List _glyphSetCollections; [NonSerialized] private readonly Dictionary _glyphs = new Dictionary(); [NonSerialized] private bool _initialized; /// /// Determines if glyphs should be fetched immediately in bulk when available. /// If false, glyphs will be fetched when queried. /// public bool prefetch { get { return _prefetch; } set { _prefetch = value; if (isActiveAndEnabled && ReInput.isReady && ReInput.glyphs.glyphProvider == (IGlyphProvider)this) { ReInput.glyphs.prefetch = value; } } } /// /// The list of glyph set collections. /// You should not make changes to the list directly, but instead set the list. /// Otherwise, the changes will not be reflected in Rewired for glyphs that /// have already been cached. If you do modify the list directly, call after making changes. /// When setting the array, will be called automatically. /// public List glyphSetCollections { get { return _glyphSetCollections; } set { _glyphSetCollections = value; Reload(); } } /// /// The cached glyphs. /// protected Dictionary glyphs { get { return _glyphs; } } protected virtual void OnEnable() { if (!_initialized) Initialize(); // only init if needed to avoid reloading everything if re-enabled TrySetGlyphProvider(); } protected virtual void OnDisable() { if (ReInput.isReady && ReInput.glyphs.glyphProvider == (IGlyphProvider)this) { ReInput.glyphs.glyphProvider = null; } ReInput.InitializedEvent -= TrySetGlyphProvider; } protected virtual void Update() { #if UNITY_EDITOR HandleInspectorValueChanges(); #endif } /// /// Sets this as the Glyph Provider in Rewired. /// protected virtual void TrySetGlyphProvider() { // Workaround to handle OnEnable script execution order bugs in various versions of Unity. // When recompiling in the editor in Play mode, OnEnable can be called on this script // before it is called on Rewired, so Rewired is not initialized by the time this runs. // This also has the side benefit of allowing the user to instantiate this object // before Rewired for whatever reason, and it will set itself as the provider // when Rewired initalizes. // This will also set the glyph provider again after calling ReInput.Reset or changing // some configuration setting that causes Rewired to reset. ReInput.InitializedEvent -= TrySetGlyphProvider; ReInput.InitializedEvent += TrySetGlyphProvider; if (!ReInput.isReady) return; if (!Utils.UnityTools.IsNullOrDestroyed(ReInput.glyphs.glyphProvider)) { UnityEngine.Debug.LogWarning("Rewired: A glyph provider is already set. Only one glyph provider can exist at a time."); return; } ReInput.glyphs.glyphProvider = this; ReInput.glyphs.prefetch = _prefetch; } /// /// Called when initialized. /// Will be initialized on enable and when localized strings are set. /// /// True if initialized, false if initialization failed. protected virtual bool Initialize() { _initialized = false; if (_glyphSetCollections == null) return false; // Create a dictionary of all glyhps in all collections _glyphs.Clear(); const char keyPathSeparator = '/'; System.Text.StringBuilder sb = new System.Text.StringBuilder(); string key; GlyphSetCollection collection; GlyphSet.EntryBase entry; int baseKeysCount; int entryCount; int i, j, k; for (i = 0; i < _glyphSetCollections.Count; i++) { collection = _glyphSetCollections[i]; if (collection == null) continue; foreach(var set in collection.IterateSetsRecursively()) { if (set == null) continue; if (set.baseKeys != null) { baseKeysCount = set.baseKeys.Length; for (j = 0; j < baseKeysCount; j++) { if (string.IsNullOrEmpty(set.baseKeys[j])) continue; entryCount = set.glyphCount; for (k = 0; k < entryCount; k++) { entry = set.GetEntry(k); if (entry == null) continue; if (string.IsNullOrEmpty(entry.key)) continue; if (entry.GetValue() == null) continue; // Concatenate base key and glyph key sb.Append(set.baseKeys[j]); sb.Append(keyPathSeparator); sb.Append(entry.key); key = sb.ToString(); sb.Length = 0; if (_glyphs.ContainsKey(key)) { UnityEngine.Debug.LogError("Rewired: Duplicate glyph key found: " + key); continue; } _glyphs.Add(key, entry.GetValue()); } } } } } _initialized = true; return true; } /// /// Clears glyph cache so all glyhps are reloaded. /// Subclasses should call this after making changes to the glyph collection. /// public void Reload() { Initialize(); if (isActiveAndEnabled && ReInput.isReady && ReInput.glyphs.glyphProvider == (IGlyphProvider)this) { ReInput.glyphs.Reload(); } } /// /// Try to get the glyph for the specified key. /// /// The key. /// The localized string. /// True if the glyph was found, false if not. bool IGlyphProvider.TryGetGlyph(string key, out object result) { if (!_initialized) { result = null; return false; } return _glyphs.TryGetValue(key, out result); } #if UNITY_EDITOR [NonSerialized] private Action _inspectorActions; private Rewired.Utils.Classes.Data.InspectorValue_inspector_prefetch = new Rewired.Utils.Classes.Data.InspectorValue(); private Rewired.Utils.Classes.Data.InspectorListValue _inspector_glyphSetCollections = new Rewired.Utils.Classes.Data.InspectorListValue(); protected virtual void OnValidate() { _inspectorActions = null; // prevent buffering of actions in edit mode CheckInspectorValues(ref _inspectorActions); } protected virtual void CheckInspectorValues(ref Action actions) { if(_inspector_prefetch.SetIfChanged(_prefetch)) { actions += () => prefetch = _prefetch; } if (_inspector_glyphSetCollections.SetIfChanged(_glyphSetCollections)) { actions += () => glyphSetCollections = _glyphSetCollections; } } protected virtual void HandleInspectorValueChanges() { Action actions = _inspectorActions; _inspectorActions = null; if (actions != null) actions(); } #endif } }