CI / Go Backend (push) Canceled after 0s
初始化 monorepo: Go后端(7微服务) + Unity客户端(9模块) + 启动器 HTML5原型: Three.js 3D体素世界, Perlin噪声地形, 原版材质, 22种方块 Minecraft创造模式背包: 双栏布局, 拖拽移动物品, 方向性元件引脚 AI助搭策划文档 + 客户端/服务端骨架 + Docker Compose + CI
304 lines
11 KiB
C#
304 lines
11 KiB
C#
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();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
} |