feat: add world chat UI

This commit is contained in:
ud18010
2026-07-28 11:54:07 +08:00
parent 09c89aadf0
commit 48aed26725
28 changed files with 5308 additions and 99 deletions
@@ -0,0 +1,157 @@
using System.IO;
using NUnit.Framework;
using TMPro;
using UnityEditor;
using UnityEngine;
using XGame.EditorTools;
public sealed class JsonUIPrefabBuilderInputFieldTests
{
private const string JsonPath = "../Temp/UIGenTests/UI_TMPInputTest.json";
private const string PrefabPath = "Assets/Temp/UIGenTests/UI_TMPInputTest.prefab";
[TearDown]
public void TearDown()
{
AssetDatabase.DeleteAsset(PrefabPath);
AssetDatabase.DeleteAsset("Assets/Temp/UIGenTests");
string fullJsonPath = Path.GetFullPath(Path.Combine(Application.dataPath, JsonPath));
if (File.Exists(fullJsonPath))
{
File.Delete(fullJsonPath);
}
}
[Test]
public void BuildFromJsonFile_CreatesAndBindsTmpInputField()
{
string fullJsonPath = WriteJson();
string outputPath = JsonUIPrefabBuilder.BuildFromJsonFile(fullJsonPath);
Assert.That(outputPath, Is.EqualTo(PrefabPath));
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(PrefabPath);
Assert.That(prefab, Is.Not.Null);
Transform inputTransform = prefab.transform.Find("InputHitArea");
Assert.That(inputTransform, Is.Not.Null);
TMP_InputField input = inputTransform.GetComponent<TMP_InputField>();
Assert.That(input, Is.Not.Null);
Assert.That(inputTransform.gameObject.layer, Is.EqualTo(LayerMask.NameToLayer("UI")));
Assert.That(input.textComponent, Is.Not.Null);
Assert.That(input.textComponent.name, Is.EqualTo("Txt_InputValue"));
Assert.That(input.placeholder, Is.Not.Null);
Assert.That(input.placeholder.name, Is.EqualTo("Txt_InputPlaceholder"));
Assert.That(input.characterLimit, Is.EqualTo(140));
Assert.That(input.lineType, Is.EqualTo(TMP_InputField.LineType.SingleLine));
}
private static string WriteJson()
{
string fullJsonPath = Path.GetFullPath(Path.Combine(Application.dataPath, JsonPath));
Directory.CreateDirectory(Path.GetDirectoryName(fullJsonPath));
File.WriteAllText(fullJsonPath, @"{
""schemaVersion"": 1,
""prefabName"": ""UI_TMPInputTest"",
""prefabPath"": ""Assets/Temp/UIGenTests/UI_TMPInputTest.prefab"",
""description"": ""TMP input field test."",
""canvas"": {
""canvasScaler"": {
""referenceResolution"": [2048, 1024],
""matchWidthOrHeight"": 0.5
}
},
""assets"": {
""sprites"": {}
},
""nodes"": [
{
""name"": ""UI_TMPInputTest"",
""parent"": null,
""active"": true,
""rect"": {
""anchorMin"": [0, 0],
""anchorMax"": [1, 1],
""offsetMin"": [0, 0],
""offsetMax"": [0, 0]
},
""components"": []
},
{
""name"": ""InputHitArea"",
""parent"": ""UI_TMPInputTest"",
""active"": true,
""rect"": {
""anchorMin"": [0.5, 0.5],
""anchorMax"": [0.5, 0.5],
""pivot"": [0.5, 0.5],
""anchoredPosition"": [0, 0],
""sizeDelta"": [520, 80]
},
""components"": [
{
""type"": ""Image"",
""imageType"": ""Sliced"",
""raycastTarget"": true,
""color"": ""#FFFFFFFF""
},
{
""type"": ""TMP_InputField"",
""textComponent"": ""Txt_InputValue"",
""placeholderComponent"": ""Txt_InputPlaceholder"",
""placeholder"": ""输入内容..."",
""characterLimit"": 140,
""lineType"": ""SingleLine"",
""contentType"": ""Standard""
}
]
},
{
""name"": ""Txt_InputPlaceholder"",
""parent"": ""InputHitArea"",
""active"": true,
""rect"": {
""anchorMin"": [0, 0],
""anchorMax"": [1, 1],
""offsetMin"": [24, 0],
""offsetMax"": [-24, 0]
},
""components"": [
{
""type"": ""TextMeshProUGUI"",
""text"": ""输入内容..."",
""fontSize"": 28,
""alignment"": ""Left"",
""color"": ""#7A8DA1FF"",
""raycastTarget"": false
}
]
},
{
""name"": ""Txt_InputValue"",
""parent"": ""InputHitArea"",
""active"": true,
""rect"": {
""anchorMin"": [0, 0],
""anchorMax"": [1, 1],
""offsetMin"": [24, 0],
""offsetMax"": [-24, 0]
},
""components"": [
{
""type"": ""TextMeshProUGUI"",
""text"": """",
""fontSize"": 28,
""alignment"": ""Left"",
""color"": ""#23384CFF"",
""raycastTarget"": false
}
]
}
],
""bindings"": [],
""events"": []
}");
return fullJsonPath;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 203834191d3c4f7c8b175a00e72186c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
using NUnit.Framework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XGame;
public sealed class UIManagerAttachTests
{
[TearDown]
public void TearDown()
{
DestroyIfExists("ZeroSizedCanvas");
DestroyIfExists("UIRoot");
EventSystem eventSystem = Object.FindObjectOfType<EventSystem>();
if (eventSystem != null)
{
Object.DestroyImmediate(eventSystem.gameObject);
}
}
[Test]
public void AttachTo_StretchesZeroSizedCanvasRootAndAppliesUiLayer()
{
GameObject ui = new GameObject("ZeroSizedCanvas", typeof(RectTransform), typeof(Canvas));
GameObject child = new GameObject("Child", typeof(RectTransform), typeof(Image));
child.transform.SetParent(ui.transform, false);
RectTransform rt = ui.GetComponent<RectTransform>();
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.zero;
rt.sizeDelta = Vector2.zero;
UIManager.AttachTo(UILayer.Normal, ui);
int uiLayer = LayerMask.NameToLayer("UI");
Assert.That(rt.anchorMin, Is.EqualTo(Vector2.zero));
Assert.That(rt.anchorMax, Is.EqualTo(Vector2.one));
Assert.That(rt.offsetMin, Is.EqualTo(Vector2.zero));
Assert.That(rt.offsetMax, Is.EqualTo(Vector2.zero));
Assert.That(ui.layer, Is.EqualTo(uiLayer));
Assert.That(child.layer, Is.EqualTo(uiLayer));
}
private static void DestroyIfExists(string name)
{
GameObject go = GameObject.Find(name);
if (go != null)
{
Object.DestroyImmediate(go);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 793775c4067b48ffad9e0ca52d8e92db
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,7 +1,11 @@
{
"name": "XWorld.Link.EditModeTests",
"rootNamespace": "",
"references": ["XWorld.Link"],
"references": [
"XWorld.Link",
"Unity.TextMeshPro",
"GUID:119d45324677fde49923efc4ea54b313"
],
"includePlatforms": ["Editor"],
"excludePlatforms": [],
"allowUnsafeCode": false,
@@ -0,0 +1,35 @@
using System.Reflection;
using NUnit.Framework;
using UnityEditor;
public sealed class XWorldJsonPrefabAutoConvertTests
{
private const string JsonPrefKey = "XWorld.UI.AutoConvertJsonOnFocus";
private const string HtmlPrefKey = "XWorld.UI.AutoConvertHtmlOnFocus";
[TearDown]
public void TearDown()
{
EditorPrefs.DeleteKey(JsonPrefKey);
EditorPrefs.DeleteKey(HtmlPrefKey);
}
[Test]
public void JsonAutoConvertDefaultsToEnabledIndependentlyOfHtmlPreference()
{
EditorPrefs.DeleteKey(JsonPrefKey);
EditorPrefs.SetBool(HtmlPrefKey, false);
Assert.That(ReadJsonAutoConvertEnabled(), Is.True);
}
private static bool ReadJsonAutoConvertEnabled()
{
MethodInfo method = typeof(XWorldUtil).GetMethod(
"IsAutoConvertJsonOnFocusEnabled",
BindingFlags.Static | BindingFlags.NonPublic);
Assert.That(method, Is.Not.Null);
return (bool)method.Invoke(null, null);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 802e633c1f3d4d38be7f72851fed177f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: