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