using Gs2.Unity.Util; using Gs2.Unity.Core; using System; using Cysharp.Threading.Tasks; using System.Collections.Generic; using Gs2.Unity.Gs2Inbox.Model; using UnityEngine; public sealed class AdventureEventView : MonoBehaviour { [SerializeField] private AdventureLogin login; private Gs2Domain Client => login.Gs2; private IGameSession Session => login == null ? null : login.Session; private readonly List messages = new List(); private bool busy; private Func pendingOperation; private bool destroyed; private Action unsubscribe; private string message = "Load the inbox"; private Vector2 scroll; private string startMinutes = "15"; private string endMinutes = "30"; private string startsAt = ""; private string endsAt = ""; private string startMillis = ""; private string endMillis = ""; private const string Inbox = "adventure-inbox"; private void OnGUI() { if (Session == null) return; GUILayout.BeginArea(new Rect(700, 20, 650, Screen.height - 40), GUI.skin.box); scroll = GUILayout.BeginScrollView(scroll); GUILayout.Label("Event announcements and rewards"); GUILayout.Label(message); GUILayout.Label("Set event times (minutes from now)"); startMinutes = GUILayout.TextField(startMinutes); endMinutes = GUILayout.TextField(endMinutes); if (GUILayout.Button("Generate start and end times")) MakeDates(); GUILayout.Label("Studio start time / end time"); GUILayout.TextField(startsAt); GUILayout.TextField(endsAt); GUILayout.Label("SDK template START_AT / END_AT"); GUILayout.TextField(startMillis); GUILayout.TextField(endMillis); GUI.enabled = !busy && pendingOperation == null; if (GUILayout.Button("Receive announcements and update inbox")) Run(() => Load()).Forget(); foreach (var item in messages) { GUILayout.Label(item.Metadata); GUI.enabled = !busy && pendingOperation == null && !item.IsRead; if (GUILayout.Button(item.IsRead ? "Opened" : "Open and claim reward")) RunWrite(id => Read(item.Name, id)).Forget(); } GUI.enabled = !busy && pendingOperation != null; if (GUILayout.Button("Retry the same operation")) RetryWrite().Forget(); GUI.enabled = true; GUILayout.EndScrollView(); GUILayout.EndArea(); } private void MakeDates() { if (!int.TryParse(startMinutes, out var start) || !int.TryParse(endMinutes, out var end) || start >= end || start < -1440 || end > 1440) { message = "Set start before end, both within 1440 minutes of now"; return; } var now = System.DateTimeOffset.Now; startsAt = now.AddMinutes(start).ToString("yyyy-MM-dd HH:mm:ss zzz"); endsAt = now.AddMinutes(end).ToString("yyyy-MM-dd HH:mm:ss zzz"); startMillis = now.AddMinutes(start).ToUnixTimeMilliseconds().ToString(); endMillis = now.AddMinutes(end).ToUnixTimeMilliseconds().ToString(); } private async UniTask Run(System.Func action) { if (busy || pendingOperation != null) return; busy = true; try { await action(); } catch (System.Exception error) { message = error.Message; } finally { busy = false; } } private void OnDestroy() { destroyed = true; unsubscribe?.Invoke(); } private async UniTask Load() { var user = Client.Inbox.Namespace(Inbox).Me(Session); await user.ReceiveGlobalMessageAsync(); user.InvalidateMessages(); var items = new List(); await foreach (var item in user.MessagesAsync()) if (item != null) items.Add(item); if (destroyed) return; unsubscribe?.Invoke(); UpdateMessages(items.ToArray()); var id = user.SubscribeMessages(UpdateMessages); unsubscribe = () => user.UnsubscribeMessages(id); message = messages.Count == 0 ? "No messages received" : "Inbox updated"; } private void UpdateMessages(EzMessage[] items) { messages.Clear(); messages.AddRange(items); } private async UniTask Read(string name, string requestId) { var transaction = await Client.Inbox.Namespace(Inbox).Me(Session) .Message(name).ReadAsync(speculativeExecute: false, duplicationAvoider: requestId); if (transaction != null) await transaction.WaitAsync(all: true); } private async UniTask RunWrite(Func operation) { if (busy || pendingOperation != null || Session == null) return; var requestId = Guid.NewGuid().ToString(); pendingOperation = () => operation(requestId); await RetryWrite(); } private async UniTask RetryWrite() { if (busy || pendingOperation == null) return; busy = true; message = "Processing..."; try { await pendingOperation(); pendingOperation = null; message = "Done"; } catch (Exception error) when ( error is Gs2.Core.Exception.BadRequestException || error is Gs2.Gs2Money2.Exception.InsufficientException || error is Gs2.Gs2Inventory.Exception.InsufficientException || error is Gs2.Gs2Stamina.Exception.InsufficientException) { pendingOperation = null; message = "Action failed: " + error.Message; } catch (Exception error) { message = "Check the connection and retry the same operation: " + error.GetType().Name; } finally { busy = false; } } }