Files
2026-07-09 21:33:33 +02:00

103 lines
4.1 KiB
C#

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<IMarker> _markers =
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => typeof(IMarker).IsAssignableFrom(type) && type.IsClass)
.Select(Activator.CreateInstance)
.Cast<IMarker>()
.ToList();
private static List<IMarkerGroup> _groupMarkers =
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.Where(type => typeof(IMarkerGroup).IsAssignableFrom(type) && type.IsClass)
.Select(Activator.CreateInstance)
.Cast<IMarkerGroup>()
.ToList();
#if UNITY_EDITOR
[ShowInInspector, Searchable, ListDrawerSettings(IsReadOnly = true)]
private static List<MarkerDummyString> _allMarkers = new List<string>()
.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<Object> _sources = new();
// Parsed
private bool _isParsed;
private string _stringFormat;
private List<Func<string>> _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<string> 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<string> 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<object>());
}
public static implicit operator string(DynamicText dynamicText) => dynamicText.Get();
}
}