using System; using System.Collections.Generic; using AibisDream.Framework; using TMPro; using UnityEditor; using UnityEditor.AddressableAssets; using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets.Settings.GroupSchemas; using UnityEngine; namespace AibisDream.EditorTools { public static class TypographyFirstRoundBuilder { private const string GroupName = "Shared_Typography"; private const string ProfileFolder = "Assets/GameContent/Common/Typography/Profiles"; private const string WenQuanYiPath = "Assets/Font/Assets/WenQuanYi Bitmap Song 14px SDF.asset"; private const string ChillBitmapPath = "Assets/Font/Assets/ChillBitmap_16px SDF.asset"; private const string ArkPixelPath = "Assets/Font/TTF/ark-pixel-16px-proportional-latin SDF.asset"; [MenuItem("Tools/AIBIS Dream/Typography/Rebuild First Round Assets")] public static void BuildFirstRoundAssets() { EnsureFolder(ProfileFolder); TMP_FontAsset wenQuanYi = LoadRequiredFont(WenQuanYiPath); TMP_FontAsset chillBitmap = LoadRequiredFont(ChillBitmapPath); TMP_FontAsset arkPixel = LoadRequiredFont(ArkPixelPath); AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; if (settings == null) throw new InvalidOperationException("AddressableAssetSettings 不存在。"); AddressableAssetGroup group = GetOrCreateGroup(settings); CreateOrUpdateProfile( settings, group, TypographyProfileKind.ZhHans, wenQuanYi, new[] { chillBitmap }); CreateOrUpdateProfile( settings, group, TypographyProfileKind.Japanese, chillBitmap, new[] { wenQuanYi }); CreateOrUpdateProfile( settings, group, TypographyProfileKind.Latin, arkPixel, new[] { chillBitmap }); CreateOrUpdateProfile( settings, group, TypographyProfileKind.Russian, arkPixel, new[] { chillBitmap }); TerminalTypographyMigration.MigrateTerminalPrefabs(); EditorUtility.SetDirty(settings); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log("[TypographyFirstRoundBuilder] Profile、Addressables 和首轮试点绑定已更新。"); } public static void BuildFromCommandLine() { try { BuildFirstRoundAssets(); } catch (Exception exception) { Debug.LogException(exception); throw; } } private static TMP_FontAsset LoadRequiredFont(string path) { TMP_FontAsset font = AssetDatabase.LoadAssetAtPath(path); if (font == null) throw new InvalidOperationException($"找不到字体资产:{path}"); return font; } private static AddressableAssetGroup GetOrCreateGroup(AddressableAssetSettings settings) { AddressableAssetGroup group = settings.FindGroup(GroupName); if (group == null) { group = settings.CreateGroup( GroupName, false, false, true, null, typeof(BundledAssetGroupSchema), typeof(ContentUpdateGroupSchema)); } BundledAssetGroupSchema bundled = group.GetSchema(); if (bundled != null) { bundled.IncludeInBuild = true; bundled.BundleMode = BundledAssetGroupSchema.BundlePackingMode.PackTogether; EditorUtility.SetDirty(bundled); } ContentUpdateGroupSchema update = group.GetSchema(); if (update != null) { update.StaticContent = false; EditorUtility.SetDirty(update); } return group; } private static void CreateOrUpdateProfile( AddressableAssetSettings settings, AddressableAssetGroup group, TypographyProfileKind kind, TMP_FontAsset font, IReadOnlyCollection fallbacks) { string path = $"{ProfileFolder}/{kind}.asset"; TypographyProfile profile = AssetDatabase.LoadAssetAtPath(path); if (profile == null) { profile = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(profile, path); } var styles = new List(); foreach (TypographyRole role in Enum.GetValues(typeof(TypographyRole))) { styles.Add(new TypographyStyle( role, font, fallbackFonts: fallbacks, fontSizeMultiplier: 1f)); } profile.Configure(kind, styles); EditorUtility.SetDirty(profile); string guid = AssetDatabase.AssetPathToGUID(path); AddressableAssetEntry entry = settings.CreateOrMoveEntry(guid, group, false, false); entry.address = $"Typography/Profile/{kind}"; entry.SetLabel("Typography", true, true, false); } private static void EnsureFolder(string path) { string[] segments = path.Split('/'); string current = segments[0]; for (int i = 1; i < segments.Length; i++) { string next = $"{current}/{segments[i]}"; if (!AssetDatabase.IsValidFolder(next)) AssetDatabase.CreateFolder(current, segments[i]); current = next; } } } }