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 = "받은 편지함을 불러오세요"; 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("이벤트 공지와 보상"); GUILayout.Label(message); GUILayout.Label("개최 시각 만들기(지금부터 몇 분 뒤인지)"); startMinutes = GUILayout.TextField(startMinutes); endMinutes = GUILayout.TextField(endMinutes); if (GUILayout.Button("시작·종료 시각 만들기")) MakeDates(); GUILayout.Label("Studio 시작 시각 / 종료 시각"); GUILayout.TextField(startsAt); GUILayout.TextField(endsAt); GUILayout.Label("SDK 템플릿 START_AT / END_AT"); GUILayout.TextField(startMillis); GUILayout.TextField(endMillis); GUI.enabled = !busy && pendingOperation == null; if (GUILayout.Button("공지 수신 및 목록 갱신")) Run(() => Load()).Forget(); foreach (var item in messages) { GUILayout.Label(item.Metadata); GUI.enabled = !busy && pendingOperation == null && !item.IsRead; if (GUILayout.Button(item.IsRead ? "개봉 완료" : "개봉하고 보상 받기")) RunWrite(id => Read(item.Name, id)).Forget(); } GUI.enabled = !busy && pendingOperation != null; if (GUILayout.Button("같은 작업 재시도")) 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 = "시작은 종료보다 앞이어야 하며 현재로부터 전후 1440분 이내로 입력하세요"; 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 ? "도착한 메시지가 없습니다" : "받은 편지함을 갱신했습니다"; } 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 = "처리 중"; try { await pendingOperation(); pendingOperation = null; message = "완료했습니다"; } 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 = "작업을 실행하지 못했습니다: " + error.Message; } catch (Exception error) { message = "연결을 확인하고 같은 작업을 재시도하세요: " + error.GetType().Name; } finally { busy = false; } } }