294 lines
9.6 KiB
C#
294 lines
9.6 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Text;
|
||
using UnityEngine;
|
||
#if UNITY_EDITOR
|
||
using UnityEditor;
|
||
#endif
|
||
|
||
[Serializable]
|
||
public class UI_FunctionHoverEntry
|
||
{
|
||
public string path;
|
||
[TextArea(2, 6)]
|
||
public string text;
|
||
public string iconPath;
|
||
public Sprite icon;
|
||
}
|
||
|
||
[CreateAssetMenu(menuName = "UI/Function Hover Config", fileName = "UI_FunctionHoverConfig")]
|
||
public class UI_FunctionHoverConfig : ScriptableObject
|
||
{
|
||
public List<UI_FunctionHoverEntry> entries = new List<UI_FunctionHoverEntry>();
|
||
|
||
#if UNITY_EDITOR
|
||
[ContextMenu("Import From 素材/指向")]
|
||
private void ImportFromDefaultFile()
|
||
{
|
||
ImportFromFile("素材/指向");
|
||
}
|
||
|
||
[ContextMenu("Import From UI_FunctionHoverConfig.json")]
|
||
private void ImportFromDefaultJson()
|
||
{
|
||
ImportFromJsonFile("Assets/Resources/UI_FunctionHoverConfig.json");
|
||
}
|
||
|
||
public void ImportFromFile(string relativePath)
|
||
{
|
||
if (string.IsNullOrEmpty(relativePath)) return;
|
||
string fullPath = Path.Combine(Application.dataPath, "..", relativePath);
|
||
if (!File.Exists(fullPath))
|
||
{
|
||
Debug.LogWarning("UI_FunctionHoverConfig: file not found: " + fullPath);
|
||
return;
|
||
}
|
||
|
||
string content = File.ReadAllText(fullPath, Encoding.UTF8);
|
||
var parsed = ParseConfig(content);
|
||
if (parsed.Count > 0)
|
||
{
|
||
entries = parsed;
|
||
EditorUtility.SetDirty(this);
|
||
AssetDatabase.SaveAssets();
|
||
}
|
||
}
|
||
|
||
public void ImportFromJsonFile(string relativePath)
|
||
{
|
||
if (string.IsNullOrEmpty(relativePath)) return;
|
||
string fullPath = Path.Combine(Application.dataPath, "..", relativePath);
|
||
if (!File.Exists(fullPath))
|
||
{
|
||
Debug.LogWarning("UI_FunctionHoverConfig: json not found: " + fullPath);
|
||
return;
|
||
}
|
||
|
||
string content = File.ReadAllText(fullPath, Encoding.UTF8);
|
||
var parsed = ParseJson(content);
|
||
if (parsed.Count > 0)
|
||
{
|
||
entries = parsed;
|
||
EditorUtility.SetDirty(this);
|
||
AssetDatabase.SaveAssets();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
private static List<UI_FunctionHoverEntry> ParseConfig(string content)
|
||
{
|
||
var result = new List<UI_FunctionHoverEntry>();
|
||
if (string.IsNullOrEmpty(content)) return result;
|
||
|
||
var blocks = content.Split(new[] { "\r\n\r\n", "\n\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||
foreach (var block in blocks)
|
||
{
|
||
string pathLine = null;
|
||
string textLine = null;
|
||
string iconLine = null;
|
||
var lines = block.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||
foreach (var line in lines)
|
||
{
|
||
if (line.StartsWith("路径")) pathLine = line;
|
||
else if (line.StartsWith("文本")) textLine = line;
|
||
else if (line.StartsWith("显示icon")) iconLine = line;
|
||
}
|
||
|
||
if (pathLine == null || textLine == null) continue;
|
||
|
||
string pathsRaw = GetValueAfterColon(pathLine);
|
||
string text = GetValueAfterColon(textLine);
|
||
string iconPath = iconLine != null ? GetValueAfterColon(iconLine) : null;
|
||
|
||
var paths = SplitPaths(pathsRaw);
|
||
var icon = LoadIcon(iconPath);
|
||
foreach (var p in paths)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(p)) continue;
|
||
result.Add(new UI_FunctionHoverEntry
|
||
{
|
||
path = p.Trim(),
|
||
text = text,
|
||
iconPath = iconPath,
|
||
icon = icon
|
||
});
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
[Serializable]
|
||
private class JsonRoot
|
||
{
|
||
public List<JsonEntry> entries;
|
||
}
|
||
|
||
[Serializable]
|
||
private class JsonEntry
|
||
{
|
||
public List<string> paths;
|
||
public string text;
|
||
public string icon;
|
||
}
|
||
|
||
private static List<UI_FunctionHoverEntry> ParseJson(string content)
|
||
{
|
||
var result = new List<UI_FunctionHoverEntry>();
|
||
if (string.IsNullOrEmpty(content)) return result;
|
||
|
||
JsonRoot root = null;
|
||
try
|
||
{
|
||
root = JsonUtility.FromJson<JsonRoot>(content);
|
||
}
|
||
catch
|
||
{
|
||
root = null;
|
||
}
|
||
|
||
if (root == null || root.entries == null) return result;
|
||
|
||
for (int i = 0; i < root.entries.Count; i++)
|
||
{
|
||
var entry = root.entries[i];
|
||
if (entry == null || entry.paths == null) continue;
|
||
Sprite icon = LoadIcon(entry.icon);
|
||
for (int p = 0; p < entry.paths.Count; p++)
|
||
{
|
||
var path = entry.paths[p];
|
||
if (string.IsNullOrWhiteSpace(path)) continue;
|
||
result.Add(new UI_FunctionHoverEntry
|
||
{
|
||
path = path.Trim(),
|
||
text = entry.text,
|
||
iconPath = entry.icon,
|
||
icon = icon
|
||
});
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private static string GetValueAfterColon(string line)
|
||
{
|
||
int idx = line.IndexOf(':');
|
||
if (idx < 0) idx = line.IndexOf(':');
|
||
if (idx < 0) return line.Trim();
|
||
return line.Substring(idx + 1).Trim();
|
||
}
|
||
|
||
private static string[] SplitPaths(string raw)
|
||
{
|
||
if (string.IsNullOrEmpty(raw)) return Array.Empty<string>();
|
||
string tmp = raw.Replace("和", "|")
|
||
.Replace("、", "|")
|
||
.Replace(",", "|")
|
||
.Replace(",", "|")
|
||
.Replace(";", "|")
|
||
.Replace(";", "|");
|
||
return tmp.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||
}
|
||
|
||
private static Sprite LoadIcon(string iconPath)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(iconPath)) return null;
|
||
string path = NormalizeAssetPath(iconPath);
|
||
if (!path.StartsWith("Assets", StringComparison.OrdinalIgnoreCase))
|
||
path = "Assets/" + path;
|
||
|
||
#if UNITY_EDITOR
|
||
Sprite direct = TryLoadByPath(path);
|
||
if (direct != null) return direct;
|
||
|
||
string name = Path.GetFileName(path);
|
||
string folder = Path.GetDirectoryName(path);
|
||
List<string> searchFolders = new List<string>();
|
||
if (!string.IsNullOrEmpty(folder) && Directory.Exists(Path.Combine(Application.dataPath, "..", folder)))
|
||
searchFolders.Add(folder);
|
||
|
||
string uiUiFolder = "Assets/artworks/UI_UI";
|
||
if (Directory.Exists(Path.Combine(Application.dataPath, "..", uiUiFolder)))
|
||
searchFolders.Add(uiUiFolder);
|
||
|
||
string artworksFolder = "Assets/artworks";
|
||
if (Directory.Exists(Path.Combine(Application.dataPath, "..", artworksFolder)))
|
||
searchFolders.Add(artworksFolder);
|
||
|
||
string[] folders = searchFolders.Count > 0 ? searchFolders.ToArray() : null;
|
||
var guids = AssetDatabase.FindAssets(name + " t:Sprite", folders);
|
||
if (guids.Length == 0)
|
||
guids = AssetDatabase.FindAssets(name + " t:Texture2D", folders);
|
||
if (guids.Length > 0)
|
||
{
|
||
string best = PickBestAssetPath(guids, name, folder);
|
||
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(best);
|
||
if (sprite != null) return sprite;
|
||
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(best);
|
||
if (tex != null)
|
||
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
|
||
}
|
||
#endif
|
||
return null;
|
||
}
|
||
|
||
private static string NormalizeAssetPath(string raw)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(raw)) return string.Empty;
|
||
string path = raw.Replace('>', '/').Replace('\\', '/').Trim();
|
||
path = path.Replace("Ul_Ul", "UI_UI");
|
||
path = path.Replace("(", " (").Replace(")", ")");
|
||
path = path.Replace(" ", " ").Trim();
|
||
return path;
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
private static Sprite TryLoadByPath(string path)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(path)) return null;
|
||
string[] candidates = path.IndexOf('.') >= 0
|
||
? new[] { path }
|
||
: new[]
|
||
{
|
||
path + ".png",
|
||
path + ".jpg",
|
||
path + ".jpeg"
|
||
};
|
||
|
||
for (int i = 0; i < candidates.Length; i++)
|
||
{
|
||
string p = candidates[i];
|
||
var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(p);
|
||
if (sprite != null) return sprite;
|
||
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(p);
|
||
if (tex != null)
|
||
return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f));
|
||
}
|
||
return null;
|
||
}
|
||
|
||
private static string PickBestAssetPath(string[] guids, string name, string preferredFolder)
|
||
{
|
||
if (guids == null || guids.Length == 0) return null;
|
||
string best = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||
if (guids.Length == 1) return best;
|
||
|
||
string preferredLower = (preferredFolder ?? string.Empty).Replace('\\', '/').ToLowerInvariant();
|
||
string uiUiFolder = "assets/artworks/ui_ui";
|
||
for (int i = 0; i < guids.Length; i++)
|
||
{
|
||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||
if (string.IsNullOrEmpty(path)) continue;
|
||
string lower = path.ToLowerInvariant();
|
||
if (!string.IsNullOrEmpty(preferredLower) && lower.Contains(preferredLower))
|
||
return path;
|
||
if (lower.Contains(uiUiFolder))
|
||
best = path;
|
||
}
|
||
return best;
|
||
}
|
||
#endif
|
||
}
|