using System; using System.Collections.Generic; using System.Threading.Tasks; /// /// Brisk SDK 的静态总入口。 /// 初始化完成后,开发者可以通过 Brisk.AuthBrisk.Leaderboard 等模块直接访问能力。 /// public static class Brisk { private static BriskContext s_context; static Brisk() { Auth = new BriskAuthModule(); Player = new BriskPlayerModule(); Config = new BriskConfigModule(); Announcements = new BriskAnnouncementsModule(); Leaderboard = new BriskLeaderboardModule(); Archive = new BriskArchiveModule(); Space = new BriskSpaceModule(); } /// /// SDK 初始化完成后触发。 /// public static event Action OnInitialized; /// /// 登录成功并保存会话后触发。 /// public static event Action OnLoggedIn; /// /// 主动登出并清理本地会话后触发。 /// public static event Action OnLoggedOut; /// /// 发生维护、封禁、强更等严重阻断错误时触发。 /// public static event Action OnBlockingError; /// /// 登录态失效并清空本地会话时触发。 /// public static event Action OnAuthExpired; /// /// 认证模块入口。 /// public static BriskAuthModule Auth { get; } /// /// 玩家模块入口。 /// public static BriskPlayerModule Player { get; } /// /// 动态配置模块入口。 /// public static BriskConfigModule Config { get; } /// /// 公告模块入口。 /// public static BriskAnnouncementsModule Announcements { get; } /// /// 排行榜模块入口。 /// public static BriskLeaderboardModule Leaderboard { get; } /// /// 云存档模块入口。 /// public static BriskArchiveModule Archive { get; } /// /// 玩家空间模块入口。 /// public static BriskSpaceModule Space { get; } /// /// 当前 SDK 是否已完成初始化。 /// public static bool IsInitialized => s_context != null; /// /// 当前是否存在可用登录态。 /// public static bool IsLoggedIn => s_context != null && s_context.Session.HasAccessToken; /// /// 当前访问令牌。 /// public static string AccessToken => s_context != null ? s_context.Session.AccessToken : null; /// /// 当前玩家 ID。 /// public static string PlayerId => s_context != null ? s_context.Session.PlayerId : null; /// /// 当前登录身份摘要。 /// public static BriskIdentity Identity => s_context != null ? s_context.Session.Identity : null; /// /// 当前初始化选项。 /// public static BriskOptions Options => s_context != null ? s_context.Options : null; /// /// 初始化阶段获取到的 bootstrap 结果。 /// public static BriskBootstrapResult Bootstrap => s_context != null ? s_context.Bootstrap : null; /// /// 初始化 SDK,并执行 bootstrap 与本地会话恢复。 /// /// 初始化选项。 public static async Task InitializeAsync(BriskOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } options.Validate(); var context = new BriskContext(options); s_context = context; try { await BootstrapAsync(context); await RestoreSessionAsync(context); OnInitialized?.Invoke(); } catch { if (context.Bootstrap == null) { s_context = null; } throw; } } /// /// 关闭 SDK 并清空当前上下文。 /// public static void Shutdown() { s_context = null; } /// /// 设置严重错误的展示器。 /// /// 自定义错误展示器;传入 null 时恢复默认展示器。 public static void SetErrorPresenter(IBriskErrorPresenter presenter) { GetRequiredContext().ErrorPresenter = presenter ?? BriskDefaultErrorPresenter.Instance; } /// /// 设置阻断错误确认后的退出回调。 /// /// 项目方自定义退出逻辑。 public static void SetExitHandler(Action exitHandler) { GetRequiredContext().ExitHandler = exitHandler; } internal static BriskContext GetRequiredContext() { if (s_context == null) { throw new BriskNotInitializedException(); } return s_context; } internal static void NotifyLoggedIn() { OnLoggedIn?.Invoke(); } internal static void NotifyLoggedOut() { OnLoggedOut?.Invoke(); } internal static void NotifyBlockingError(BriskBlockingException exception) { s_context?.ErrorPresenter?.ShowBlockingError(exception); OnBlockingError?.Invoke(exception); } internal static void NotifyAuthExpired(BriskAuthExpiredException exception) { s_context?.ErrorPresenter?.ShowAuthExpired(exception); OnAuthExpired?.Invoke(exception); } private static async Task BootstrapAsync(BriskContext context) { var query = new Dictionary { { "game_key", context.Options.GameKey }, { "client_version", context.Options.ClientVersion }, { "device_id", context.Options.DeviceId } }; var bootstrapData = await context.HttpClient.GetDataAsync("/client/bootstrap", query, false); var bootstrap = BriskModelMapper.ToBootstrapResult(bootstrapData); context.Bootstrap = bootstrap; if (bootstrap.MaintenanceMode) { var message = string.IsNullOrWhiteSpace(bootstrap.MaintenanceMessage) ? "Server is under maintenance." : bootstrap.MaintenanceMessage; var exception = new BriskMaintenanceException(message); NotifyBlockingError(exception); throw exception; } if (BriskVersionComparer.IsLessThan(context.Options.ClientVersion, bootstrap.MinClientVersion)) { var exception = new BriskClientUpdateRequiredException("Client version is lower than the minimum supported version."); NotifyBlockingError(exception); throw exception; } } private static async Task RestoreSessionAsync(BriskContext context) { var storedSession = await context.TokenStore.LoadAsync(); if (storedSession == null || string.IsNullOrWhiteSpace(storedSession.AccessToken)) { return; } context.Session.Update( storedSession.AccessToken, storedSession.ExpiresAt, storedSession.PlayerId, storedSession.ProjectAccountId, storedSession.LoginProvider, storedSession.LoginUserId); if (!context.Options.ValidateSessionOnInitialize) { return; } try { var meData = await context.HttpClient.GetDataAsync("/player/me", null, true); var me = BriskModelMapper.ToPlayerMe(meData); context.Session.Update( storedSession.AccessToken, storedSession.ExpiresAt, me.PlayerId, me.ProjectAccountId, me.LoginProvider, me.LoginUserId); } catch (BriskAuthExpiredException exception) { context.Session.Clear(); await context.TokenStore.ClearAsync(); NotifyAuthExpired(exception); } catch (BriskBlockingException exception) { NotifyBlockingError(exception); throw; } } }