Compare commits
2 Commits
4814840b2c
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de679f5dd1 | ||
|
|
1e9616d06d |
45
Plugin.cs
45
Plugin.cs
@@ -14,11 +14,19 @@ public class CNText : BaseUnityPlugin
|
||||
{
|
||||
static ConfigEntry<bool> needReplaceTextComp;
|
||||
static ConfigEntry<int> customTextFontSize;
|
||||
static ConfigEntry<bool> removeUnsupportedTags;
|
||||
static ConfigEntry<bool> closeUnclosedTags;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
needReplaceTextComp = Config.Bind<bool>("OnlinePlayerUI", "NeedReplaceTextComp", true, "是否显示替换的头顶玩家名称文本组件");
|
||||
customTextFontSize = Config.Bind<int>("OnlinePlayerUI", "CustomTextFontSize", 38, "替换后头顶玩家名称字号");
|
||||
Harmony.CreateAndPatchAll(typeof(OnlinePlayerUIUpdatePatch));
|
||||
removeUnsupportedTags = Config.Bind<bool>("OnlinePlayerUI", "RemoveUnsupportedTags", true, "是否移除不支持的标签");
|
||||
closeUnclosedTags = Config.Bind<bool>("OnlinePlayerUI", "CloseUnclosedTags", true, "是否自动闭合未闭合的标签");
|
||||
if (needReplaceTextComp.Value)
|
||||
{
|
||||
Harmony.CreateAndPatchAll(typeof(OnlinePlayerUIUpdatePatch));
|
||||
}
|
||||
}
|
||||
static Font LoadCustomFont()
|
||||
{
|
||||
@@ -44,27 +52,6 @@ public class CNText : BaseUnityPlugin
|
||||
return font;
|
||||
}
|
||||
|
||||
static public string ReformatName(string name)
|
||||
{
|
||||
name = name.Replace("<#", "</Color><Color=#");
|
||||
if (name.StartsWith("</Color>"))
|
||||
{
|
||||
name = name.Substring(8);
|
||||
}
|
||||
if (name.LastIndexOf("</Color>") < name.LastIndexOf("<Color=#"))
|
||||
{
|
||||
name += "</Color>";
|
||||
}
|
||||
if (name.IndexOf("</Color>") < name.LastIndexOf("<Color=#"))
|
||||
{
|
||||
name = name.Substring(0, name.IndexOf("</Color>")) + name.Substring(name.IndexOf("</Color>") + 8);
|
||||
}
|
||||
if (name.LastIndexOf("</I>") < name.LastIndexOf("<I>") || name.LastIndexOf("</i>") < name.LastIndexOf("<i>"))
|
||||
{
|
||||
name += "</i>";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
[HarmonyPatch(typeof(OnlinePlayerUI), "Update")]
|
||||
class OnlinePlayerUIUpdatePatch
|
||||
{
|
||||
@@ -100,17 +87,9 @@ public class CNText : BaseUnityPlugin
|
||||
customText.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
customText.color = tmpPlayerText.color;
|
||||
customText.text = ReformatName(tmpPlayerText.text);
|
||||
if (needReplaceTextComp.Value)
|
||||
{
|
||||
tmpPlayerText.enabled = false;
|
||||
customText.enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPlayerText.enabled = true;
|
||||
customText.enabled = false;
|
||||
}
|
||||
customText.text = TMPToFontTextConverter.Convert(tmpPlayerText.text, removeUnsupportedTags.Value, closeUnclosedTags.Value);
|
||||
tmpPlayerText.enabled = false;
|
||||
customText.enabled = true;
|
||||
customText.supportRichText = true;
|
||||
}
|
||||
}
|
||||
|
||||
153
TMPToFontTextConverter.cs
Normal file
153
TMPToFontTextConverter.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class TMPToFontTextConverter
|
||||
{
|
||||
private static readonly Dictionary<string, string> ColorNameToHex = new Dictionary<string, string>()
|
||||
{
|
||||
{"white", "#FFFFFF"}, {"black", "#000000"},
|
||||
{"red", "#FF0000"}, {"green", "#00FF00"},
|
||||
{"blue", "#0000FF"}, {"yellow", "#FFFF00"},
|
||||
{"cyan", "#00FFFF"}, {"magenta", "#FF00FF"},
|
||||
{"gray", "#808080"}, {"grey", "#808080"}
|
||||
};
|
||||
|
||||
public static string Convert(string input, bool removeUnsupportedTags = true, bool closeUnclosedTags = true)
|
||||
{
|
||||
var output = PreprocessColorTags(input);
|
||||
output = ProcessColorTags(output);
|
||||
output = RemoveUnsupportedTags(output, removeUnsupportedTags);
|
||||
return closeUnclosedTags ? CloseUnclosedTags(output) : output;
|
||||
}
|
||||
|
||||
private static string PreprocessColorTags(string input)
|
||||
{
|
||||
// 转换简写颜色标签格式(带#和不带#)
|
||||
return Regex.Replace(input, @"<(#?[0-9a-fA-F]{3,8})>", match =>
|
||||
{
|
||||
string hex = match.Groups[1].Value;
|
||||
return $"<color={(hex.StartsWith("#") ? hex : "#" + hex)}>";
|
||||
});
|
||||
}
|
||||
|
||||
private static string ProcessColorTags(string input)
|
||||
{
|
||||
// 匹配所有颜色标签进行标准化处理
|
||||
return Regex.Replace(input, @"<color=(.*?)>", match =>
|
||||
{
|
||||
string colorValue = match.Groups[1].Value.Trim();
|
||||
|
||||
// 处理颜色名称
|
||||
if (ColorNameToHex.TryGetValue(colorValue.ToLower(), out var hex))
|
||||
return $"<color={hex}>";
|
||||
|
||||
// 处理十六进制格式
|
||||
if (colorValue.StartsWith("#"))
|
||||
{
|
||||
string cleanHex = colorValue.Replace("#", "");
|
||||
return FormatHexColor(cleanHex);
|
||||
}
|
||||
|
||||
// 处理RGBA格式
|
||||
if (colorValue.StartsWith("rgba"))
|
||||
return ConvertRGBA(colorValue);
|
||||
|
||||
return $"<color={colorValue}>"; // 保留原始格式
|
||||
}, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
private static string FormatHexColor(string hex)
|
||||
{
|
||||
hex = hex.ToUpper();
|
||||
switch (hex.Length)
|
||||
{
|
||||
case 3: // #RGB → RRGGBB
|
||||
return $"<color=#{new string(hex[0], 2)}{new string(hex[1], 2)}{new string(hex[2], 2)}>";
|
||||
case 6: // RRGGBB → RRGGBBFF
|
||||
return $"<color=#{hex}FF>";
|
||||
case 8: // RRGGBBAA → 保持原样
|
||||
return $"<color=#{hex}>";
|
||||
default: // 无效格式保持原样
|
||||
return $"<color=#{hex}>";
|
||||
}
|
||||
}
|
||||
|
||||
private static string RemoveUnsupportedTags(string input, bool removeUnsupported)
|
||||
{
|
||||
if (!removeUnsupported) return input;
|
||||
|
||||
// 删除不支持的标签及其内容(保留内容)
|
||||
string[] unsupportedTags = { "font", "s", "u", "align" };
|
||||
foreach (var tag in unsupportedTags)
|
||||
{
|
||||
input = Regex.Replace(input, $@"<{tag}=.*?>", "", RegexOptions.IgnoreCase);
|
||||
input = Regex.Replace(input, $@"<\/{tag}>", "", RegexOptions.IgnoreCase);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
private static string CloseUnclosedTags(string input)
|
||||
{
|
||||
Stack<string> tagStack = new Stack<string>();
|
||||
StringBuilder output = new StringBuilder();
|
||||
int index = 0;
|
||||
|
||||
while (index < input.Length)
|
||||
{
|
||||
if (input[index] == '<')
|
||||
{
|
||||
int tagEnd = input.IndexOf('>', index);
|
||||
if (tagEnd == -1) break;
|
||||
|
||||
string fullTag = input.Substring(index, tagEnd - index + 1);
|
||||
bool isClosing = fullTag.StartsWith("</");
|
||||
string tagType = Regex.Match(fullTag, @"</?(\w+)").Groups[1].Value.ToLower();
|
||||
|
||||
output.Append(fullTag);
|
||||
|
||||
// 处理标签栈
|
||||
if (!isClosing && !tagType.EndsWith("/"))
|
||||
{
|
||||
tagStack.Push(tagType); // 记录基础标签类型
|
||||
}
|
||||
else if (isClosing)
|
||||
{
|
||||
// 正确匹配最近打开的标签
|
||||
if (tagStack.Count > 0 && tagStack.Peek() == tagType)
|
||||
tagStack.Pop();
|
||||
}
|
||||
|
||||
index = tagEnd + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Append(input[index++]);
|
||||
}
|
||||
}
|
||||
|
||||
// 补全剩余标签(保持打开顺序)
|
||||
while (tagStack.Count > 0)
|
||||
{
|
||||
string tag = tagStack.Pop();
|
||||
output.Append($"</{tag}>");
|
||||
}
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
private static string ConvertRGBA(string rgba)
|
||||
{
|
||||
var matches = Regex.Matches(rgba, @"\d+\.?\d*");
|
||||
if (matches.Count < 3) return "#FFFFFFFF";
|
||||
|
||||
StringBuilder hex = new StringBuilder("#");
|
||||
for (int i = 0; i < 3; i++)
|
||||
hex.Append((int.Parse(matches[i].Value) * 255).ToString("X2"));
|
||||
|
||||
hex.Append(matches.Count > 3 ?
|
||||
((int)(float.Parse(matches[3].Value) * 255)).ToString("X2") : "FF");
|
||||
|
||||
return $"<color={hex}>";
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,16 @@
|
||||
└─StreamingAssets
|
||||
```
|
||||
|
||||
**其中 `StreamingAssets`为新增的目录**
|
||||
**其中 `StreamingAssets`为新增的目录**
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.2
|
||||
|
||||
fix:
|
||||
|
||||
- 标签解析,重构了标签转换器
|
||||
|
||||
### v1.0.1
|
||||
|
||||
fix:
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net35</TargetFramework>
|
||||
<AssemblyName>stick.plugins.cntext</AssemblyName>
|
||||
<Product>cntext</Product>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.0.2</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>
|
||||
@@ -22,15 +22,16 @@
|
||||
<PackageReference Include="Mono.Cecil" Version="0.10.4" />
|
||||
<PackageReference Include="UnityEngine.Modules" Version="5.6.3.16509117" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2"
|
||||
PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>lib/Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>lib/Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -39,16 +40,16 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="UnityEngine.UI">
|
||||
<HintPath>lib/UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="TextMeshPro">
|
||||
<HintPath>lib/TextMeshPro-1.0.55.56.0b9.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user