Files

304 lines
11 KiB
C#
Raw Permalink Normal View History

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<string, string> 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<string>());
return result.Replace("§§", "§");
}
private static string ProcessElement(JsonObject element, List<string> currentFormat)
{
var text = "";
var formats = new List<string>(currentFormat);
// 处理格式
if (element.ContainsKey("bold") && element["bold"].ToObject<bool>()) 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<string>(formats));
return text;
}
/// <summary>
/// Minecraft 文本格式化代码,用于显示不同颜色的文本
/// </summary>
/// <param name="text">要格式化的文本</param>
/// <param name="lab">控件</param>
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<TimerRun>();
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();
}
};
}
}
}
}