Files
CC-Framework.BriskGameServer/Assets/BriskSdk/Runtime/Core/Brisk.cs

330 lines
9.9 KiB
C#
Raw Normal View History

2026-04-10 22:04:51 +08:00
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
/// <summary>
/// Brisk SDK 的静态总入口。
/// 初始化完成后,开发者可以通过 <c>Brisk.Auth</c>、<c>Brisk.Leaderboard</c> 等模块直接访问能力。
/// </summary>
2026-04-10 22:04:51 +08:00
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();
}
/// <summary>
/// SDK 初始化完成后触发。
/// </summary>
2026-04-10 22:04:51 +08:00
public static event Action OnInitialized;
/// <summary>
/// 登录成功并保存会话后触发。
/// </summary>
2026-04-10 22:04:51 +08:00
public static event Action OnLoggedIn;
/// <summary>
/// 主动登出并清理本地会话后触发。
/// </summary>
2026-04-10 22:04:51 +08:00
public static event Action OnLoggedOut;
/// <summary>
/// 发生维护、封禁、强更等严重阻断错误时触发。
/// </summary>
2026-04-10 22:04:51 +08:00
public static event Action<BriskBlockingException> OnBlockingError;
/// <summary>
/// 登录态失效并清空本地会话时触发。
/// </summary>
2026-04-10 22:04:51 +08:00
public static event Action<BriskAuthExpiredException> OnAuthExpired;
/// <summary>
/// 认证模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskAuthModule Auth { get; }
/// <summary>
/// 玩家模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskPlayerModule Player { get; }
/// <summary>
/// 动态配置模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskConfigModule Config { get; }
/// <summary>
/// 公告模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskAnnouncementsModule Announcements { get; }
/// <summary>
/// 排行榜模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskLeaderboardModule Leaderboard { get; }
/// <summary>
/// 云存档模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskArchiveModule Archive { get; }
/// <summary>
/// 玩家空间模块入口。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskSpaceModule Space { get; }
/// <summary>
/// 当前 SDK 是否已完成初始化。
/// </summary>
2026-04-10 22:04:51 +08:00
public static bool IsInitialized => s_context != null;
/// <summary>
/// 当前是否存在可用登录态。
/// </summary>
2026-04-10 22:04:51 +08:00
public static bool IsLoggedIn => s_context != null && s_context.Session.HasAccessToken;
/// <summary>
/// 当前访问令牌。
/// </summary>
2026-04-10 22:04:51 +08:00
public static string AccessToken => s_context != null ? s_context.Session.AccessToken : null;
/// <summary>
/// 当前玩家 ID。
/// </summary>
2026-04-10 22:04:51 +08:00
public static string PlayerId => s_context != null ? s_context.Session.PlayerId : null;
/// <summary>
/// 当前登录身份摘要。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskIdentity Identity => s_context != null ? s_context.Session.Identity : null;
/// <summary>
/// 当前初始化选项。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskOptions Options => s_context != null ? s_context.Options : null;
/// <summary>
/// 初始化阶段获取到的 bootstrap 结果。
/// </summary>
2026-04-10 22:04:51 +08:00
public static BriskBootstrapResult Bootstrap => s_context != null ? s_context.Bootstrap : null;
/// <summary>
/// 初始化 SDK并执行 bootstrap 与本地会话恢复。
/// </summary>
/// <param name="options">初始化选项。</param>
2026-04-10 22:04:51 +08:00
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;
}
}
/// <summary>
/// 关闭 SDK 并清空当前上下文。
/// </summary>
2026-04-10 22:04:51 +08:00
public static void Shutdown()
{
s_context = null;
}
/// <summary>
/// 设置严重错误的展示器。
/// </summary>
/// <param name="presenter">自定义错误展示器;传入 null 时恢复默认展示器。</param>
2026-04-10 22:04:51 +08:00
public static void SetErrorPresenter(IBriskErrorPresenter presenter)
{
GetRequiredContext().ErrorPresenter = presenter ?? BriskDefaultErrorPresenter.Instance;
}
/// <summary>
/// 设置阻断错误确认后的退出回调。
/// </summary>
/// <param name="exitHandler">项目方自定义退出逻辑。</param>
2026-04-10 22:04:51 +08:00
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)
{
2026-05-13 19:05:00 +08:00
NotifyAuthExpired(exception, true);
}
internal static void NotifyAuthExpired(BriskAuthExpiredException exception, bool showDefaultPresenter)
{
if (showDefaultPresenter)
{
s_context?.ErrorPresenter?.ShowAuthExpired(exception);
}
2026-04-10 22:04:51 +08:00
OnAuthExpired?.Invoke(exception);
}
private static async Task BootstrapAsync(BriskContext context)
{
var query = new Dictionary<string, string>
{
{ "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;
}
2026-05-13 19:05:00 +08:00
if (storedSession.ExpiresAt.HasValue && storedSession.ExpiresAt.Value <= DateTimeOffset.UtcNow)
{
await HandleExpiredStartupSessionAsync(
context,
storedSession,
new BriskAuthExpiredException("Stored session expired before initialization."));
return;
}
2026-04-10 22:04:51 +08:00
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)
{
2026-05-13 19:05:00 +08:00
await HandleExpiredStartupSessionAsync(context, storedSession, exception);
2026-04-10 22:04:51 +08:00
}
catch (BriskBlockingException exception)
{
NotifyBlockingError(exception);
throw;
}
}
2026-05-13 19:05:00 +08:00
private static async Task HandleExpiredStartupSessionAsync(BriskContext context, BriskStoredSession storedSession, BriskAuthExpiredException exception)
{
context.Session.Clear();
await context.TokenStore.ClearAsync();
NotifyAuthExpired(exception, false);
if (!context.Options.AutoReloginOnInitialize || !HasStoredLoginIdentity(storedSession))
{
return;
}
try
{
await Auth.LoginWithUserIdAsync(storedSession.LoginProvider, storedSession.LoginUserId);
}
catch (BriskBlockingException)
{
throw;
}
catch
{
// 初始化期静默重登失败时,交给业务层后续第三方登录流程重新调用 Brisk.Auth。
}
}
private static bool HasStoredLoginIdentity(BriskStoredSession storedSession)
{
return storedSession != null
&& !string.IsNullOrWhiteSpace(storedSession.LoginProvider)
&& !string.IsNullOrWhiteSpace(storedSession.LoginUserId);
}
2026-04-10 22:04:51 +08:00
}