Files
unity/Assets/Editor/LocalizationBuilder.cs
RCiBot eb819c6688 feat: improve map lighting and expand the playable training range
Add real-time lighting and shadows, training courses and targets, and animated salvage crates. Include bilingual assets and curated verification results.
2026-11-12 18:03:04 +08:00

112 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.TextCore.Text;
using UnityEngine.UIElements;
namespace Ironspore.Editor
{
public static class LocalizationBuilder
{
public const string CatalogPath = "Assets/Game/Localization/LocalizationCatalog.asset";
const string FontPath = "Assets/ThirdParty/Adobe/NotoSansSC/NotoSansSC-VF.ttf";
const string FontAssetPath = "Assets/Game/UI/Fonts/GameFont.asset";
[MenuItem("Ironspore/Configure Localization")]
public static string Configure()
{
if (EditorApplication.isPlaying)
throw new InvalidOperationException("Stop play mode before configuring localization.");
Directory.CreateDirectory("Assets/Game/UI/Fonts");
AssetDatabase.Refresh();
var importer = AssetImporter.GetAtPath(FontPath) as TrueTypeFontImporter;
if (!importer)
throw new FileNotFoundException("Archived OFL font has not imported.", FontPath);
importer.fontTextureCase = FontTextureCase.Dynamic;
importer.fontSize = 40;
importer.includeFontData = true;
importer.SaveAndReimport();
var font = AssetDatabase.LoadAssetAtPath<Font>(FontPath);
var catalog = AssetDatabase.LoadAssetAtPath<LocalizationCatalog>(CatalogPath);
if (!catalog)
{
catalog = ScriptableObject.CreateInstance<LocalizationCatalog>();
AssetDatabase.CreateAsset(catalog, CatalogPath);
}
catalog.locales = new[]
{
new GameLocale { code = "zh-Hans", nativeName = "简体中文", table = AssetDatabase.LoadAssetAtPath<UnityEngine.TextAsset>("Assets/Game/Localization/Tables/zh-Hans.json") },
new GameLocale { code = "en", nativeName = "English", table = AssetDatabase.LoadAssetAtPath<UnityEngine.TextAsset>("Assets/Game/Localization/Tables/en.json") }
};
var uiFont = AssetDatabase.LoadAssetAtPath<FontAsset>(FontAssetPath);
if (!uiFont)
{
uiFont = FontAsset.CreateFontAsset(font, 64, 7, GlyphRenderMode.SDFAA, 2048, 2048, AtlasPopulationMode.Dynamic, true);
uiFont.name = "GameFont";
AssetDatabase.CreateAsset(uiFont, FontAssetPath);
uiFont.material.name = "GameFont Material";
AssetDatabase.AddObjectToAsset(uiFont.material, uiFont);
}
uiFont.isMultiAtlasTexturesEnabled = true;
var fontSettings = new SerializedObject(uiFont);
fontSettings.FindProperty("m_ClearDynamicDataOnBuild").boolValue = false;
fontSettings.ApplyModifiedPropertiesWithoutUndo();
var characters = new HashSet<char>(Enumerable.Range(32, 95).Select(x => (char)x));
foreach (var locale in catalog.locales)
{
foreach (char c in locale.nativeName)
characters.Add(c);
foreach (var entry in GameLocalization.ReadTable(locale.table))
foreach (char c in entry.Value)
if (!char.IsControl(c))
characters.Add(c);
}
string absent;
uiFont.TryAddCharacters(new string(characters.OrderBy(x => x).ToArray()), out absent);
if (!string.IsNullOrEmpty(absent))
throw new InvalidOperationException("Font is missing required glyphs: " + absent);
foreach (var atlas in uiFont.atlasTextures)
{
if (!atlas || AssetDatabase.Contains(atlas))
continue;
atlas.name = "GameFont Atlas";
AssetDatabase.AddObjectToAsset(atlas, uiFont);
}
EditorUtility.SetDirty(uiFont);
catalog.worldFont = font;
catalog.uiFont = uiFont;
EditorUtility.SetDirty(catalog);
var textSettings = AssetDatabase.LoadAssetAtPath<PanelTextSettings>("Assets/Game/UI/Fonts/GameTextSettings.asset");
if (!textSettings)
{
textSettings = ScriptableObject.CreateInstance<PanelTextSettings>();
AssetDatabase.CreateAsset(textSettings, "Assets/Game/UI/Fonts/GameTextSettings.asset");
}
textSettings.fallbackFontAssets = new List<FontAsset> { uiFont };
textSettings.clearDynamicDataOnBuild = false;
EditorUtility.SetDirty(textSettings);
var panel = AssetDatabase.LoadAssetAtPath<PanelSettings>("Assets/Game/UI/GamePanelSettings.asset");
panel.textSettings = textSettings;
EditorUtility.SetDirty(panel);
string previousScene = EditorSceneManager.GetActiveScene().path;
foreach (string name in new[] { "Bootstrap", "MechTestRange", "WarzonePrototype" })
{
var scene = EditorSceneManager.OpenScene("Assets/Scenes/" + name + ".unity");
var session = UnityEngine.Object.FindAnyObjectByType<GameSession>();
session.localization = catalog;
EditorUtility.SetDirty(session);
EditorSceneManager.MarkSceneDirty(scene);
EditorSceneManager.SaveScene(scene);
}
AssetDatabase.SaveAssets();
EditorSceneManager.OpenScene(string.IsNullOrEmpty(previousScene) ? "Assets/Scenes/Bootstrap.unity" : previousScene);
return "Configured two locales, " + characters.Count + " glyphs, UI Toolkit and TextMesh fonts, and all three scenes.";
}
}
}