159 lines
5.8 KiB
C#
159 lines
5.8 KiB
C#
using System;
|
||
using System.Collections;
|
||
using Ichni.Diagnostics;
|
||
using UnityEngine;
|
||
using UnityEngine.Localization.Settings;
|
||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||
|
||
namespace Ichni
|
||
{
|
||
/// <summary>
|
||
/// Unity Localization 的统一启动入口。
|
||
/// <para>
|
||
/// 本类只包装 Unity 官方提供的 <see cref="LocalizationSettings.InitializationOperation"/>,
|
||
/// 不自行初始化 Addressables、不查询 Locale Label,也不复制 Localization Package 的内部加载流程。
|
||
/// 因此 Settings、Yarn 与其它本地化消费者始终等待同一个由 Unity 管理的初始化操作。
|
||
/// </para>
|
||
/// </summary>
|
||
public static class LocalizationBootstrap
|
||
{
|
||
public enum InitializationState
|
||
{
|
||
NotStarted,
|
||
Initializing,
|
||
Ready,
|
||
Failed
|
||
}
|
||
|
||
private static AsyncOperationHandle<LocalizationSettings> _initializationOperation;
|
||
|
||
public static InitializationState State { get; private set; } = InitializationState.NotStarted;
|
||
public static bool IsReady => State == InitializationState.Ready;
|
||
public static bool HasFailed => State == InitializationState.Failed;
|
||
public static string FailureReason { get; private set; }
|
||
|
||
/// <summary>
|
||
/// Unity Localization 官方初始化 Handle。
|
||
/// 获取该属性会以幂等方式启动初始化,但不会同步阻塞主线程。
|
||
/// </summary>
|
||
public static AsyncOperationHandle<LocalizationSettings> InitializationOperation
|
||
{
|
||
get
|
||
{
|
||
BeginInitialization();
|
||
return _initializationOperation;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在关闭 Domain Reload 的 Editor 配置下,清理上一次 Play Mode 留下的项目侧状态。
|
||
/// Localization Package 会自行重建其内部 Handle,本类不持有也不释放 Package 的资源。
|
||
/// </summary>
|
||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||
private static void ResetState()
|
||
{
|
||
_initializationOperation = default;
|
||
State = InitializationState.NotStarted;
|
||
FailureReason = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按 Unity 官方流程获取唯一的 Localization 初始化操作。
|
||
/// 可以由多个系统重复调用;已经启动后不会创建第二条加载链。
|
||
/// </summary>
|
||
public static void BeginInitialization()
|
||
{
|
||
if (State != InitializationState.NotStarted)
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 不设置 InitializeSynchronously,也不直接访问 SelectedLocale。
|
||
// InitializationOperation 会异步完成 Locale 选择及所有配置为 Preload 的数据库初始化。
|
||
_initializationOperation = LocalizationSettings.InitializationOperation;
|
||
State = InitializationState.Initializing;
|
||
Log("开始等待 Unity Localization 官方 InitializationOperation。");
|
||
RefreshState();
|
||
}
|
||
catch (Exception exception)
|
||
{
|
||
Fail("无法创建 Unity Localization 初始化操作。", exception);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新初始化结果。供 YarnTask 等不能直接 yield AsyncOperationHandle 的异步流程调用。
|
||
/// </summary>
|
||
public static void RefreshState()
|
||
{
|
||
if (State != InitializationState.Initializing)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!_initializationOperation.IsValid())
|
||
{
|
||
Fail("Unity Localization 返回了无效的 InitializationOperation Handle。");
|
||
return;
|
||
}
|
||
|
||
if (!_initializationOperation.IsDone)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (_initializationOperation.Status != AsyncOperationStatus.Succeeded)
|
||
{
|
||
Fail("Unity Localization 初始化失败。", _initializationOperation.OperationException);
|
||
return;
|
||
}
|
||
|
||
LocaleReady();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 供 MonoBehaviour 协程等待 Unity Localization 初始化。
|
||
/// 此处直接 yield 官方 Handle,不使用轮询超时或自建 Addressables 状态机。
|
||
/// </summary>
|
||
public static IEnumerator WaitForInitialization()
|
||
{
|
||
BeginInitialization();
|
||
|
||
if (State == InitializationState.Initializing)
|
||
{
|
||
yield return _initializationOperation;
|
||
RefreshState();
|
||
}
|
||
}
|
||
|
||
private static void LocaleReady()
|
||
{
|
||
State = InitializationState.Ready;
|
||
FailureReason = null;
|
||
|
||
// SelectedLocale 只有在完整 InitializationOperation 成功后才允许同步读取。
|
||
string localeCode = LocalizationSettings.SelectedLocale != null
|
||
? LocalizationSettings.SelectedLocale.Identifier.Code
|
||
: "<null>";
|
||
Log($"Unity Localization 初始化完成。SelectedLocale={localeCode}");
|
||
}
|
||
|
||
private static void Fail(string message, Exception exception = null)
|
||
{
|
||
FailureReason = exception == null ? message : $"{message} Exception={exception}";
|
||
State = InitializationState.Failed;
|
||
|
||
Debug.LogError($"[LocalizationBootstrap] {FailureReason}");
|
||
BuildHangTracer.Log("LOCALIZATION_BOOTSTRAP", $"[Failed] {FailureReason}");
|
||
}
|
||
|
||
private static void Log(string message)
|
||
{
|
||
Debug.Log($"[LocalizationBootstrap] {message}");
|
||
BuildHangTracer.Log("LOCALIZATION_BOOTSTRAP", message);
|
||
}
|
||
}
|
||
}
|