using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Sirenix.OdinInspector; using UnityEngine; using Object = UnityEngine.Object; namespace VOID.Generic.DynamicValue { [Serializable] public class DynamicText { // STATIC - Cached markers private static List _markers = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => typeof(IMarker).IsAssignableFrom(type) && type.IsClass) .Select(Activator.CreateInstance) .Cast() .ToList(); private static List _groupMarkers = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => typeof(IMarkerGroup).IsAssignableFrom(type) && type.IsClass) .Select(Activator.CreateInstance) .Cast() .ToList(); #if UNITY_EDITOR [ShowInInspector, Searchable, ListDrawerSettings(IsReadOnly = true)] private static List _allMarkers = new List() .Union(_markers.Select(m => m.Marker())) .Union(_groupMarkers.SelectMany(mg => mg.Markers().Select(m => $"{mg.Group()}.{m}"))) .Select(str => new MarkerDummyString(str)) .ToList(); #endif // User defined formula or text with markers [SerializeField, TextArea(1,20)] private string _dynamicValue; public string dynamicValue => _dynamicValue; // TODO: Sources are needed to work, but so far will be given only via script private List _sources = new(); // Parsed private bool _isParsed; private string _stringFormat; private List> _valueGetters; public void AddSource(Object obj) => _sources.Add(obj); private void Parse() { _isParsed = true; _valueGetters = Regex.Matches(_dynamicValue, "{(.*?)}") .Select(match => match.Value) .Select(stringMarker => { stringMarker = stringMarker.Trim('{', '}'); var dotIndex = stringMarker.LastIndexOf('.'); var groupName = string.Join(string.Empty, stringMarker.Take(dotIndex)); var markerName = string.Join(string.Empty, stringMarker.Skip(dotIndex+1)); return TryParseMarker(markerName) ?? TryParseMarkerGroup(groupName, markerName) ?? (() => $"{{{stringMarker}}}"); }) .ToList(); var matchIndex = 0; _stringFormat = Regex.Replace(_dynamicValue, "{(.*?)}", _ => $"{{{matchIndex++}}}"); } private Func TryParseMarker(string markerName) { var marker = _markers.FirstOrDefault(m => m.Marker().Equals(markerName)); if (marker == null) return null; var source = _sources.FirstOrDefault(source => marker.SourceType().IsInstanceOfType(source)); if (source == null) return null; return marker.Getter(source); } private Func TryParseMarkerGroup(string groupName, string markerName) { var markerGroup = _groupMarkers.FirstOrDefault(mg => mg.Group().Equals(groupName) && mg.Markers().Contains(markerName)); if (markerGroup == null) return null; var source = _sources.FirstOrDefault(source => markerGroup.SourceType().IsInstanceOfType(source)); if (source == null) return null; return markerGroup.Getter(source, markerName); } public string Get() { #if UNITY_EDITOR _isParsed = false; #endif if (!_isParsed) Parse(); return string.Format(_stringFormat, _valueGetters.Select(getter => getter.Invoke()).ToArray()); } public static implicit operator string(DynamicText dynamicText) => dynamicText.Get(); } }