Files
CC-Framework.BriskGameServer/PackageSource/com.foldcc.cc-framework.BriskGameServer/Samples~/QuickStart/BriskQuickStartSample.cs

923 lines
30 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
public sealed class BriskQuickStartSample : MonoBehaviour
{
[Header("Init")]
public string BaseUrl = "https://brisk.lightyears.ltd";
public string GameKey = "demo-game";
public string ClientVersion = "1.0.0";
public string DeviceId = "editor-device";
public bool ValidateSessionOnInitialize = true;
[Header("Login")]
public string LoginProvider = "tap";
public string LoginUserId = "tap_user_10001";
public string LoginCode = string.Empty;
public string Nickname = "Unity Sample User";
public string AvatarUrl = string.Empty;
[Header("Leaderboard")]
public string RankKey = "season-score";
public string SubmitScoreValue = "128";
public string LeaderboardLimit = "10";
public string AroundMeRange = "5";
public string SeasonId = string.Empty;
public string SeasonHistoryLimit = "20";
[Header("Archive")]
public string ArchiveSlotNo = "1";
public string ArchiveBaseVersion = string.Empty;
[TextArea(3, 6)]
public string ArchiveContent = "{\n \"save\": 1,\n \"coins\": 128,\n \"hero\": \"mage\"\n}";
[Header("Announcements")]
public string AnnouncementId = string.Empty;
[Header("Space")]
public string SpacePlayerId = string.Empty;
public string SpaceLoginProvider = "tap";
public string SpaceLoginUserId = "tap_user_10001";
[TextArea(3, 6)]
public string SpacePayloadText = "{\n \"mood\": \"ready\",\n \"title\": \"hello brisk\"\n}";
[Header("Demo")]
public bool AutoRunOnStart;
private readonly List<string> _eventLogs = new List<string>();
private Vector2 _pageScroll;
private Vector2 _resultScroll;
private Vector2 _logScroll;
private bool _isBusy;
private string _busyAction = string.Empty;
private string _statusText = "Ready.";
private string _resultText = "No request yet.";
private string _lastErrorText = string.Empty;
private IReadOnlyList<BriskAnnouncementItem> _announcementCache = Array.Empty<BriskAnnouncementItem>();
private IReadOnlyList<BriskRankSeasonInfo> _seasonHistoryCache = Array.Empty<BriskRankSeasonInfo>();
private void OnEnable()
{
Brisk.OnInitialized += HandleInitialized;
Brisk.OnLoggedIn += HandleLoggedIn;
Brisk.OnLoggedOut += HandleLoggedOut;
Brisk.OnAuthExpired += HandleAuthExpired;
Brisk.OnBlockingError += HandleBlockingError;
}
private void OnDisable()
{
Brisk.OnInitialized -= HandleInitialized;
Brisk.OnLoggedIn -= HandleLoggedIn;
Brisk.OnLoggedOut -= HandleLoggedOut;
Brisk.OnAuthExpired -= HandleAuthExpired;
Brisk.OnBlockingError -= HandleBlockingError;
}
private void Start()
{
if (AutoRunOnStart)
{
RunAction("Auto Smoke Run", RunSmokeFlowAsync);
}
}
[ContextMenu("Run Brisk Sample")]
public void RunFromContextMenu()
{
RunAction("Context Smoke Run", RunSmokeFlowAsync);
}
private void OnGUI()
{
var area = new Rect(12f, 12f, Screen.width - 24f, Screen.height - 24f);
GUILayout.BeginArea(area, GUI.skin.box);
_pageScroll = GUILayout.BeginScrollView(_pageScroll);
DrawHeader();
DrawStatusPanel();
DrawInitSection();
DrawLoginSection();
DrawPlayerAndConfigSection();
DrawAnnouncementsSection();
DrawLeaderboardSection();
DrawArchiveSection();
DrawSpaceSection();
DrawOutputSection();
GUILayout.EndScrollView();
GUILayout.EndArea();
}
private void DrawHeader()
{
GUILayout.Label("Brisk IMGUI Sample", GUI.skin.box);
GUILayout.Label("This sample is designed for full SDK flow testing inside a single scene.", GUI.skin.label);
}
private void DrawStatusPanel()
{
BeginSection("Runtime Status");
DrawReadOnlyRow("Initialized", Brisk.IsInitialized ? "Yes" : "No");
DrawReadOnlyRow("Logged In", Brisk.IsLoggedIn ? "Yes" : "No");
DrawReadOnlyRow("PlayerId", Brisk.PlayerId);
DrawReadOnlyRow("Identity", Brisk.Identity == null ? string.Empty : Brisk.Identity.LoginProvider + " / " + Brisk.Identity.LoginUserId);
DrawReadOnlyRow("Current Action", _isBusy ? _busyAction : "Idle");
DrawReadOnlyRow("Status", _statusText);
GUILayout.BeginHorizontal();
DrawButton("Run Smoke Flow", RunSmokeFlowAsync);
DrawButton("Show Bootstrap Cache", () =>
{
SetResult("Bootstrap Cache", Brisk.Bootstrap);
return Task.CompletedTask;
}, Brisk.IsInitialized);
DrawButton("Shutdown SDK", () =>
{
Brisk.Shutdown();
Log("SDK shutdown.");
_statusText = "SDK shutdown.";
return Task.CompletedTask;
});
DrawButton("Clear Output", () =>
{
_resultText = "Output cleared.";
_lastErrorText = string.Empty;
_eventLogs.Clear();
_statusText = "Output cleared.";
return Task.CompletedTask;
});
GUILayout.EndHorizontal();
EndSection();
}
private void DrawInitSection()
{
BeginSection("Initialize");
BaseUrl = DrawEditableRow("Base Url", BaseUrl);
GameKey = DrawEditableRow("Game Key", GameKey);
ClientVersion = DrawEditableRow("Client Version", ClientVersion);
DeviceId = DrawEditableRow("Device Id", DeviceId);
ValidateSessionOnInitialize = DrawToggleRow("Validate Session On Init", ValidateSessionOnInitialize);
GUILayout.BeginHorizontal();
DrawButton("Initialize", InitializeAsync);
DrawButton("Reinitialize", ReinitializeAsync);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawLoginSection()
{
BeginSection("Login");
LoginProvider = DrawEditableRow("Login Provider", LoginProvider);
LoginUserId = DrawEditableRow("Login User Id", LoginUserId);
LoginCode = DrawEditableRow("Login Code", LoginCode);
Nickname = DrawEditableRow("Nickname", Nickname);
AvatarUrl = DrawEditableRow("Avatar Url", AvatarUrl);
GUILayout.BeginHorizontal();
DrawButton("Login By UserId", LoginWithUserIdAsync, Brisk.IsInitialized);
DrawButton("Login By Code", LoginWithCodeAsync, Brisk.IsInitialized);
DrawButton("Logout", LogoutAsync, Brisk.IsInitialized);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawPlayerAndConfigSection()
{
BeginSection("Player And Config");
GUILayout.BeginHorizontal();
DrawButton("Get Me", GetMeAsync, Brisk.IsLoggedIn);
DrawButton("Get Config Current", GetConfigAsync, Brisk.IsInitialized);
DrawButton("Apply Current Identity To Space", () =>
{
ApplyCurrentIdentityToSpace();
SetResult("Space Lookup Identity", new Dictionary<string, object>
{
{ "space_player_id", SpacePlayerId },
{ "space_login_provider", SpaceLoginProvider },
{ "space_login_user_id", SpaceLoginUserId }
});
return Task.CompletedTask;
}, Brisk.IsInitialized);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawAnnouncementsSection()
{
BeginSection("Announcements");
AnnouncementId = DrawEditableRow("Announcement Id", AnnouncementId);
GUILayout.BeginHorizontal();
DrawButton("Get Announcement List", GetAnnouncementsAsync, Brisk.IsLoggedIn);
DrawButton("Mark Read", MarkAnnouncementAsync, Brisk.IsLoggedIn);
DrawButton("Mark First Cached", MarkFirstCachedAnnouncementAsync, Brisk.IsLoggedIn && _announcementCache.Count > 0);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawLeaderboardSection()
{
BeginSection("Leaderboard");
RankKey = DrawEditableRow("Rank Key", RankKey);
SubmitScoreValue = DrawEditableRow("Submit Score", SubmitScoreValue);
LeaderboardLimit = DrawEditableRow("Top Limit", LeaderboardLimit);
AroundMeRange = DrawEditableRow("Around Range", AroundMeRange);
SeasonId = DrawEditableRow("Season Id", SeasonId);
SeasonHistoryLimit = DrawEditableRow("History Limit", SeasonHistoryLimit);
GUILayout.BeginHorizontal();
DrawButton("Get Top", GetTopAsync, Brisk.IsLoggedIn);
DrawButton("Get My Rank", GetMyRankAsync, Brisk.IsLoggedIn);
DrawButton("Get Around Me", GetAroundMeAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
DrawButton("Submit Score", SubmitScoreAsync, Brisk.IsLoggedIn);
DrawButton("Get Current Season", GetCurrentSeasonAsync, Brisk.IsLoggedIn);
DrawButton("Get Season History", GetSeasonHistoryAsync, Brisk.IsLoggedIn);
DrawButton("Get Season Detail", GetSeasonDetailAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawArchiveSection()
{
BeginSection("Archive");
ArchiveSlotNo = DrawEditableRow("Slot No", ArchiveSlotNo);
ArchiveBaseVersion = DrawEditableRow("Base Version", ArchiveBaseVersion);
ArchiveContent = DrawTextAreaRow("Archive Content", ArchiveContent, 90f);
GUILayout.BeginHorizontal();
DrawButton("Get Slots", GetArchiveSlotsAsync, Brisk.IsLoggedIn);
DrawButton("Get Meta", GetArchiveMetaAsync, Brisk.IsLoggedIn);
DrawButton("Upload Text", UploadArchiveAsync, Brisk.IsLoggedIn);
DrawButton("Download", DownloadArchiveAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawSpaceSection()
{
BeginSection("Space");
SpacePlayerId = DrawEditableRow("Space Player Id", SpacePlayerId);
SpaceLoginProvider = DrawEditableRow("Space Login Provider", SpaceLoginProvider);
SpaceLoginUserId = DrawEditableRow("Space Login User Id", SpaceLoginUserId);
SpacePayloadText = DrawTextAreaRow("Space Payload Text", SpacePayloadText, 90f);
GUILayout.BeginHorizontal();
DrawButton("Get By PlayerId", GetSpaceByPlayerIdAsync, Brisk.IsLoggedIn);
DrawButton("Get By Login", GetSpaceByLoginAsync, Brisk.IsLoggedIn);
DrawButton("Get Stats By PlayerId", GetSpaceStatsByPlayerIdAsync, Brisk.IsLoggedIn);
DrawButton("Get Stats By Login", GetSpaceStatsByLoginAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
DrawButton("Like PlayerId", LikeByPlayerIdAsync, Brisk.IsLoggedIn);
DrawButton("Unlike PlayerId", UnlikeByPlayerIdAsync, Brisk.IsLoggedIn);
DrawButton("Like Login", LikeByLoginAsync, Brisk.IsLoggedIn);
DrawButton("Unlike Login", UnlikeByLoginAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
DrawButton("Update My Space", UpdateMySpaceAsync, Brisk.IsLoggedIn);
DrawButton("Get My Visits", GetMyVisitsAsync, Brisk.IsLoggedIn);
GUILayout.EndHorizontal();
EndSection();
}
private void DrawOutputSection()
{
BeginSection("Output");
GUILayout.Label("Latest Result", GUI.skin.label);
_resultScroll = GUILayout.BeginScrollView(_resultScroll, GUILayout.Height(240f));
GUILayout.TextArea(_resultText, GUILayout.ExpandHeight(true));
GUILayout.EndScrollView();
GUILayout.Space(8f);
GUILayout.Label("Latest Error", GUI.skin.label);
GUILayout.TextArea(string.IsNullOrWhiteSpace(_lastErrorText) ? "No error." : _lastErrorText, GUILayout.Height(90f));
GUILayout.Space(8f);
GUILayout.Label("Event Log", GUI.skin.label);
_logScroll = GUILayout.BeginScrollView(_logScroll, GUILayout.Height(220f));
GUILayout.TextArea(_eventLogs.Count == 0 ? "No events yet." : string.Join("\n", _eventLogs.ToArray()), GUILayout.ExpandHeight(true));
GUILayout.EndScrollView();
EndSection();
}
private async Task InitializeAsync()
{
await Brisk.InitializeAsync(new BriskOptions
{
BaseUrl = BaseUrl,
GameKey = GameKey,
ClientVersion = ClientVersion,
DeviceId = DeviceId,
ValidateSessionOnInitialize = ValidateSessionOnInitialize,
ExitHandler = HandleExitRequested
});
SetResult("Initialize Result", Brisk.Bootstrap);
}
private async Task ReinitializeAsync()
{
if (Brisk.IsInitialized)
{
Brisk.Shutdown();
Log("SDK shutdown before reinitialize.");
}
await InitializeAsync();
}
private async Task LoginWithUserIdAsync()
{
var result = await Brisk.Auth.LoginWithUserIdAsync(LoginProvider, LoginUserId, CreateProfile());
ApplyIdentity(result.PlayerId, result.LoginProvider, result.LoginUserId);
SetResult("Login By UserId Result", result);
}
private async Task LoginWithCodeAsync()
{
var result = await Brisk.Auth.LoginWithCodeAsync(LoginProvider, LoginCode, CreateProfile());
ApplyIdentity(result.PlayerId, result.LoginProvider, result.LoginUserId);
SetResult("Login By Code Result", result);
}
private async Task LogoutAsync()
{
await Brisk.Auth.LogoutAsync();
SetResult("Logout Result", new Dictionary<string, object>
{
{ "logged_in", Brisk.IsLoggedIn },
{ "player_id", Brisk.PlayerId }
});
}
private async Task GetMeAsync()
{
var me = await Brisk.Player.GetMeAsync();
ApplyIdentity(me.PlayerId, me.LoginProvider, me.LoginUserId);
SetResult("Player Me", me);
}
private async Task GetConfigAsync()
{
var config = await Brisk.Config.GetCurrentAsync();
SetResult("Config Current", config);
}
private async Task GetAnnouncementsAsync()
{
_announcementCache = await Brisk.Announcements.GetListAsync();
if (_announcementCache.Count > 0 && string.IsNullOrWhiteSpace(AnnouncementId))
{
AnnouncementId = _announcementCache[0].Id.ToString();
}
SetResult("Announcements", _announcementCache);
}
private async Task MarkAnnouncementAsync()
{
var id = ParseRequiredLong(AnnouncementId, nameof(AnnouncementId));
await Brisk.Announcements.MarkReadAsync(id);
SetResult("Announcement Marked Read", new Dictionary<string, object> { { "announcement_id", id } });
}
private async Task MarkFirstCachedAnnouncementAsync()
{
if (_announcementCache.Count == 0)
{
throw new InvalidOperationException("Announcement cache is empty. Run Get Announcement List first.");
}
var id = _announcementCache[0].Id;
AnnouncementId = id.ToString();
await Brisk.Announcements.MarkReadAsync(id);
SetResult("First Cached Announcement Marked Read", _announcementCache[0]);
}
private async Task GetTopAsync()
{
var result = await Brisk.Leaderboard.GetTopAsync(RankKey, ParseOptionalInt(LeaderboardLimit, 10));
SetResult("Leaderboard Top", result);
}
private async Task GetMyRankAsync()
{
var result = await Brisk.Leaderboard.GetMeAsync(RankKey);
SetResult("Leaderboard My Rank", result);
}
private async Task GetAroundMeAsync()
{
var result = await Brisk.Leaderboard.GetAroundMeAsync(RankKey, ParseOptionalInt(AroundMeRange, 5));
SetResult("Leaderboard Around Me", result);
}
private async Task SubmitScoreAsync()
{
var score = ParseRequiredLong(SubmitScoreValue, nameof(SubmitScoreValue));
await Brisk.Leaderboard.SubmitScoreAsync(RankKey, score);
SetResult("Score Submitted", new Dictionary<string, object>
{
{ "rank_key", RankKey },
{ "score", score }
});
}
private async Task GetCurrentSeasonAsync()
{
var result = await Brisk.Leaderboard.GetCurrentSeasonAsync(RankKey);
SeasonId = result == null ? SeasonId : result.SeasonId;
SetResult("Current Season", result);
}
private async Task GetSeasonHistoryAsync()
{
_seasonHistoryCache = await Brisk.Leaderboard.GetSeasonHistoryAsync(RankKey, ParseOptionalInt(SeasonHistoryLimit, 20));
if (_seasonHistoryCache.Count > 0 && string.IsNullOrWhiteSpace(SeasonId))
{
SeasonId = _seasonHistoryCache[0].SeasonId;
}
SetResult("Season History", _seasonHistoryCache);
}
private async Task GetSeasonDetailAsync()
{
var result = await Brisk.Leaderboard.GetSeasonHistoryDetailAsync(RankKey, SeasonId, ParseOptionalInt(SeasonHistoryLimit, 20));
SetResult("Season Detail", result);
}
private async Task GetArchiveSlotsAsync()
{
var result = await Brisk.Archive.GetSlotsAsync();
SetResult("Archive Slots", result);
}
private async Task GetArchiveMetaAsync()
{
var result = await Brisk.Archive.GetMetaAsync(ParseRequiredInt(ArchiveSlotNo, nameof(ArchiveSlotNo)));
ArchiveBaseVersion = result == null ? ArchiveBaseVersion : result.Version.ToString();
SetResult("Archive Meta", result);
}
private async Task UploadArchiveAsync()
{
var slotNo = ParseRequiredInt(ArchiveSlotNo, nameof(ArchiveSlotNo));
var baseVersion = ParseNullableInt(ArchiveBaseVersion);
var bytes = Encoding.UTF8.GetBytes(ArchiveContent ?? string.Empty);
var result = await Brisk.Archive.UploadAsync(slotNo, bytes, baseVersion);
ArchiveBaseVersion = result == null ? ArchiveBaseVersion : result.Version.ToString();
SetResult("Archive Upload", result);
}
private async Task DownloadArchiveAsync()
{
var result = await Brisk.Archive.DownloadAsync(ParseRequiredInt(ArchiveSlotNo, nameof(ArchiveSlotNo)));
ArchiveBaseVersion = result == null ? ArchiveBaseVersion : result.Version.ToString();
var output = new Dictionary<string, object>
{
{ "version", result.Version },
{ "checksum", result.Checksum },
{ "byte_length", result.Bytes == null ? 0 : result.Bytes.Length },
{ "text_preview", result.Bytes == null ? string.Empty : Encoding.UTF8.GetString(result.Bytes) }
};
SetResult("Archive Download", output);
}
private async Task GetSpaceByPlayerIdAsync()
{
var result = await Brisk.Space.GetByPlayerIdAsync(SpacePlayerId);
SetResult("Space By PlayerId", result);
}
private async Task GetSpaceByLoginAsync()
{
var result = await Brisk.Space.GetByLoginIdentityAsync(SpaceLoginProvider, SpaceLoginUserId);
SetResult("Space By Login", result);
}
private async Task GetSpaceStatsByPlayerIdAsync()
{
var result = await Brisk.Space.GetStatsByPlayerIdAsync(SpacePlayerId);
SetResult("Space Stats By PlayerId", result);
}
private async Task GetSpaceStatsByLoginAsync()
{
var result = await Brisk.Space.GetStatsByLoginIdentityAsync(SpaceLoginProvider, SpaceLoginUserId);
SetResult("Space Stats By Login", result);
}
private async Task LikeByPlayerIdAsync()
{
await Brisk.Space.LikeByPlayerIdAsync(SpacePlayerId);
SetResult("Like By PlayerId", new Dictionary<string, object> { { "player_id", SpacePlayerId } });
}
private async Task UnlikeByPlayerIdAsync()
{
await Brisk.Space.UnlikeByPlayerIdAsync(SpacePlayerId);
SetResult("Unlike By PlayerId", new Dictionary<string, object> { { "player_id", SpacePlayerId } });
}
private async Task LikeByLoginAsync()
{
await Brisk.Space.LikeByLoginIdentityAsync(SpaceLoginProvider, SpaceLoginUserId);
SetResult("Like By Login", new Dictionary<string, object>
{
{ "login_provider", SpaceLoginProvider },
{ "login_user_id", SpaceLoginUserId }
});
}
private async Task UnlikeByLoginAsync()
{
await Brisk.Space.UnlikeByLoginIdentityAsync(SpaceLoginProvider, SpaceLoginUserId);
SetResult("Unlike By Login", new Dictionary<string, object>
{
{ "login_provider", SpaceLoginProvider },
{ "login_user_id", SpaceLoginUserId }
});
}
private async Task UpdateMySpaceAsync()
{
var payload = new Dictionary<string, object>
{
{ "sample_text", SpacePayloadText },
{ "updated_at", DateTimeOffset.UtcNow.ToString("O") },
{ "player_id", Brisk.PlayerId },
{ "rank_key", RankKey }
};
await Brisk.Space.UpdateMyAsync(payload);
SetResult("Update My Space", payload);
}
private async Task GetMyVisitsAsync()
{
var result = await Brisk.Space.GetMyVisitsAsync();
SetResult("My Space Visits", result);
}
private async Task RunSmokeFlowAsync()
{
await InitializeAsync();
if (!Brisk.IsLoggedIn)
{
await LoginWithUserIdAsync();
}
await GetMeAsync();
await GetConfigAsync();
await GetTopAsync();
await GetAnnouncementsAsync();
await GetArchiveSlotsAsync();
await GetMyVisitsAsync();
}
private void DrawButton(string label, Func<Task> action, bool enabled = true)
{
var previous = GUI.enabled;
GUI.enabled = previous && !_isBusy && enabled;
if (GUILayout.Button(label, GUILayout.Height(30f)))
{
RunAction(label, action);
}
GUI.enabled = previous;
}
private void RunAction(string actionName, Func<Task> action)
{
if (_isBusy)
{
return;
}
RunActionAsync(actionName, action);
}
private async void RunActionAsync(string actionName, Func<Task> action)
{
_isBusy = true;
_busyAction = actionName;
_statusText = "Running: " + actionName;
_lastErrorText = string.Empty;
Log("Start: " + actionName);
try
{
await action();
_statusText = "Success: " + actionName;
Log("Success: " + actionName);
}
catch (Exception exception)
{
_statusText = "Failed: " + actionName;
_lastErrorText = FormatException(exception);
Log("Failed: " + actionName + " | " + exception.GetType().Name + " | " + exception.Message);
Debug.LogException(exception, this);
}
finally
{
_busyAction = string.Empty;
_isBusy = false;
}
}
private void SetResult(string title, object value)
{
_resultText = title + "\n" + new string('=', title.Length) + "\n" + FormatValue(value);
}
private void ApplyIdentity(string playerId, string loginProvider, string loginUserId)
{
if (!string.IsNullOrWhiteSpace(playerId))
{
SpacePlayerId = playerId;
}
if (!string.IsNullOrWhiteSpace(loginProvider))
{
SpaceLoginProvider = loginProvider;
LoginProvider = loginProvider;
}
if (!string.IsNullOrWhiteSpace(loginUserId))
{
SpaceLoginUserId = loginUserId;
LoginUserId = loginUserId;
}
}
private void ApplyCurrentIdentityToSpace()
{
if (Brisk.Identity != null)
{
ApplyIdentity(Brisk.Identity.PlayerId, Brisk.Identity.LoginProvider, Brisk.Identity.LoginUserId);
return;
}
if (Brisk.IsInitialized)
{
ApplyIdentity(Brisk.PlayerId, LoginProvider, LoginUserId);
}
}
private BriskProfile CreateProfile()
{
return new BriskProfile
{
Nickname = Nickname,
AvatarUrl = AvatarUrl
};
}
private void HandleInitialized()
{
Log("Event: OnInitialized");
}
private void HandleLoggedIn()
{
Log("Event: OnLoggedIn");
ApplyCurrentIdentityToSpace();
}
private void HandleLoggedOut()
{
Log("Event: OnLoggedOut");
}
private void HandleAuthExpired(BriskAuthExpiredException exception)
{
Log("Event: OnAuthExpired | " + exception.Message);
}
private void HandleBlockingError(BriskBlockingException exception)
{
Log("Event: OnBlockingError | " + exception.Message);
}
private void HandleExitRequested()
{
Log("Exit requested by Brisk blocking flow.");
}
private void Log(string message)
{
var line = "[" + DateTime.Now.ToString("HH:mm:ss") + "] " + message;
_eventLogs.Add(line);
if (_eventLogs.Count > 120)
{
_eventLogs.RemoveAt(0);
}
_logScroll.y = float.MaxValue;
}
private static int ParseRequiredInt(string value, string fieldName)
{
if (!int.TryParse(value, out var result))
{
throw new InvalidOperationException(fieldName + " must be a valid integer.");
}
return result;
}
private static long ParseRequiredLong(string value, string fieldName)
{
if (!long.TryParse(value, out var result))
{
throw new InvalidOperationException(fieldName + " must be a valid integer.");
}
return result;
}
private static int ParseOptionalInt(string value, int fallback)
{
return int.TryParse(value, out var result) ? result : fallback;
}
private static int? ParseNullableInt(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
return int.TryParse(value, out var result) ? result : (int?)null;
}
private static string FormatException(Exception exception)
{
if (exception == null)
{
return "Unknown error.";
}
var builder = new StringBuilder();
var current = exception;
while (current != null)
{
builder.AppendLine(current.GetType().Name + ": " + current.Message);
current = current.InnerException;
}
return builder.ToString().TrimEnd();
}
private static string FormatValue(object value)
{
var builder = new StringBuilder();
AppendValue(builder, value, 0, 0);
return builder.ToString().TrimEnd();
}
private static void AppendValue(StringBuilder builder, object value, int indent, int depth)
{
if (depth > 5)
{
builder.AppendLine(Indent(indent) + "...");
return;
}
if (value == null)
{
builder.AppendLine(Indent(indent) + "null");
return;
}
if (value is string stringValue)
{
builder.AppendLine(Indent(indent) + stringValue);
return;
}
if (value is byte[] bytes)
{
builder.AppendLine(Indent(indent) + "byte[" + bytes.Length + "]");
return;
}
var type = value.GetType();
if (type.IsPrimitive || value is decimal)
{
builder.AppendLine(Indent(indent) + value);
return;
}
if (value is IDictionary dictionary)
{
foreach (DictionaryEntry entry in dictionary)
{
builder.AppendLine(Indent(indent) + entry.Key + ":");
AppendValue(builder, entry.Value, indent + 2, depth + 1);
}
return;
}
if (value is IEnumerable enumerable)
{
var index = 0;
foreach (var item in enumerable)
{
builder.AppendLine(Indent(indent) + "[" + index + "]");
AppendValue(builder, item, indent + 2, depth + 1);
index++;
}
if (index == 0)
{
builder.AppendLine(Indent(indent) + "(empty)");
}
return;
}
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
if (fields.Length == 0)
{
builder.AppendLine(Indent(indent) + value);
return;
}
foreach (var field in fields)
{
builder.AppendLine(Indent(indent) + field.Name + ":");
AppendValue(builder, field.GetValue(value), indent + 2, depth + 1);
}
}
private static string Indent(int indent)
{
return new string(' ', indent);
}
private static void BeginSection(string title)
{
GUILayout.Space(10f);
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.Label(title, GUI.skin.label);
GUILayout.Space(4f);
}
private static void EndSection()
{
GUILayout.EndVertical();
}
private static string DrawEditableRow(string label, string value)
{
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(180f));
var next = GUILayout.TextField(value ?? string.Empty);
GUILayout.EndHorizontal();
return next;
}
private static string DrawTextAreaRow(string label, string value, float height)
{
GUILayout.Label(label, GUILayout.Width(180f));
return GUILayout.TextArea(value ?? string.Empty, GUILayout.Height(height));
}
private static bool DrawToggleRow(string label, bool value)
{
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(180f));
var next = GUILayout.Toggle(value, value ? "Enabled" : "Disabled");
GUILayout.EndHorizontal();
return next;
}
private static void DrawReadOnlyRow(string label, string value)
{
GUILayout.BeginHorizontal();
GUILayout.Label(label, GUILayout.Width(180f));
GUILayout.Label(string.IsNullOrWhiteSpace(value) ? "-" : value, GUI.skin.box);
GUILayout.EndHorizontal();
}
}