using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; using System.Windows.Threading; using PCL.Core.UI.Controls; using PCL.Core.Utils; using PCL.Core.App.Localization; namespace PCL; internal static class ModStyle { // Partly generated by claude-sonnet-4-20250514 public class TimerRun : Run, IDisposable { // 定时器事件 public delegate void TimerTickDelegate(TimerRun sender); // 定义依赖属性 public static readonly DependencyProperty UpdateIntervalProperty = DependencyProperty.Register(nameof(UpdateInterval), typeof(TimeSpan), typeof(TimerRun), new PropertyMetadata(TimeSpan.FromSeconds(1d))); private object _isDisposed = false; private DispatcherTimer _timer; public TimerRun(TimeSpan interval = default, bool autoStart = false) { _timer = new DispatcherTimer(); _timer.Tick += _TimerTick; UpdateInterval = interval == default ? TimeSpan.FromSeconds(1d) : interval; AutoStart = autoStart; Loaded += OnLoaded; Unloaded += OnUnloaded; } private object _isTimerRunning => _timer is not null && _timer.IsEnabled; // UpdateInterval 属性 public TimeSpan UpdateInterval { get => (TimeSpan)GetValue(UpdateIntervalProperty); set { if (value > TimeSpan.Zero) SetValue(UpdateIntervalProperty, value); } } public bool AutoStart { get; set; } public void Dispose() { if ((bool)_isDisposed) return; _isDisposed = true; // 资源释放 _timer.Tick -= _TimerTick; _timer?.Stop(); _timer = null; } // 属性变化处理 protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (ReferenceEquals(e.Property, UpdateIntervalProperty) && _timer is not null) _timer.Interval = UpdateInterval; } public event TimerTickDelegate? TimerTick; private void _TimerTick(object sender, EventArgs e) { TimerTick?.Invoke(this); } private void OnLoaded(object sender, RoutedEventArgs e) { if (AutoStart) StartTimer(); } private void OnUnloaded(object sender, RoutedEventArgs e) { StopTimer(); } public void StartTimer() { if (Dispatcher is null) { ModBase.Log( "[TimerRun] Dispatcher is null, unable to run", ModBase.LogLevel.Critical, userSummary: Lang.Text("Minecraft.Launch.Error.DispatcherUnavailable")); return; } if (!(bool)_isTimerRunning) _timer?.Start(); } public void StopTimer() { if ((bool)_isTimerRunning) _timer?.Stop(); } } public class MinecraftFormatter { private static readonly Dictionary colorMap = new() { { "black", "0" }, { "dark_blue", "1" }, { "dark_green", "2" }, { "dark_aqua", "3" }, { "dark_red", "4" }, { "dark_purple", "5" }, { "gold", "6" }, { "gray", "7" }, { "dark_gray", "8" }, { "blue", "9" }, { "green", "a" }, { "aqua", "b" }, { "red", "c" }, { "light_purple", "d" }, { "yellow", "e" }, { "white", "f" } }; private static readonly Random random = new(); private static readonly string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_+-=[]{}|;:,.<>?/~"; public static string ConvertToMinecraftFormat(JsonObject data) { var result = ""; foreach (var item in data["extra"].AsArray()) result += ProcessElement((JsonObject)item, new List()); return result.Replace("§§", "§"); } private static string ProcessElement(JsonObject element, List currentFormat) { var text = ""; var formats = new List(currentFormat); // 处理格式 if (element.ContainsKey("bold") && element["bold"].ToObject()) formats.Add("l"); if (element.ContainsKey("color")) { var color = element["color"].ToString(); var colorCode = "f"; if (colorMap.ContainsKey(color)) colorCode = colorMap[color]; formats.Insert(0, colorCode); // 颜色代码在前 } // 应用格式 if (formats.Count > 0) text += "§" + string.Join("§", formats); // 添加文本内容 if (element.ContainsKey("text")) text += element["text"].ToString(); // 处理子元素 if (element.ContainsKey("extra")) foreach (var child in element["extra"].AsArray()) text += ProcessElement((JsonObject)child, new List(formats)); return text; } /// /// Minecraft 文本格式化代码,用于显示不同颜色的文本 /// /// 要格式化的文本 /// 控件 public static void SetColorfulTextLab(string text, TextBlock lab, bool isDarkMode = true) { if (lab is null) { ModBase.Log("[Style] SetColorfulTextLab: lab is null"); return; } lab.Inlines.Clear(); var hasItalicProperty = false; // 斜体 var hasDeleteLineProperty = false; // 删除线 var hasStrickThroughProperty = false; // 下划线 var hasBlodProperty = false; // 粗体 var isRandomText = false; // 随机文本模式 var color = isDarkMode ? "#FFFFFF" : "#888888"; var isColorCode = false; var curRun = new TimerRun(); lab.Inlines.Add(curRun); // 用于存储需要随机化的文本段 var randomTextRuns = new List(); foreach (var c in text) { if (c.ToString() == "§") // 下一字符是格式化代码 { isColorCode = true; continue; } if (isColorCode) { var prevColor = color; if (!MotdRenderer.TryGetColorFromCode(c.ToString(), isDarkMode, out color)) { color = prevColor; // out 会将 color 置为 null,统一恢复为之前的颜色 switch (c) { // 格式化代码 case 'k': case 'K': // 随机字符 { isRandomText = true; // 开始新的Run用于随机文本 if (!string.IsNullOrEmpty(curRun.Text)) { curRun = new TimerRun(); lab.Inlines.Add(curRun); } curRun.AutoStart = true; randomTextRuns.Add(curRun); break; } case 'l': // 粗体 { hasBlodProperty = true; break; } case 'o': // 斜体 { hasItalicProperty = true; break; } case 'n': // 下划线 { hasStrickThroughProperty = true; break; } case 'm': // 删除线 { hasDeleteLineProperty = true; break; } case 'r': // 重置 { color = isDarkMode ? "#FFFFFF" : "#888888"; hasBlodProperty = false; hasItalicProperty = false; hasStrickThroughProperty = false; hasDeleteLineProperty = false; isRandomText = false; break; } } } if (!string.IsNullOrEmpty(curRun.Text) && c.ToString() != "k" && c.ToString() != "K") // 遇到格式代码但是有文本,重开一个Run { curRun = new TimerRun(); lab.Inlines.Add(curRun); } curRun.Foreground = new SolidColorBrush(new ModBase.MyColor(color)); curRun.FontWeight = hasBlodProperty ? FontWeights.Bold : FontWeights.Normal; curRun.FontStyle = hasItalicProperty ? FontStyles.Italic : FontStyles.Normal; curRun.TextDecorations = hasStrickThroughProperty ? TextDecorations.Strikethrough : null; curRun.TextDecorations = hasDeleteLineProperty ? TextDecorations.Underline : null; } else if (isRandomText) { // 随机模式下,添加随机字符 curRun.Text += randomChars[random.Next(randomChars.Length)].ToString(); } else { curRun.Text += c.ToString(); } if (isColorCode) isColorCode = false; } // 设置定时器来更新随机文本 if (randomTextRuns.Count > 0) foreach (var run in randomTextRuns) { run.UpdateInterval = TimeSpan.FromMilliseconds(20d); run.TimerTick += sender => { if (!string.IsNullOrEmpty(sender.Text)) { var sb = new StringBuilder(); for (int i = 0, loopTo = sender.Text.Length - 1; i <= loopTo; i++) sb.Append(randomChars[random.Next(randomChars.Length)]); sender.Text = sb.ToString(); } }; } } } }