using System; using Cysharp.Threading.Tasks; using Gs2.Unity.Gs2Stamina.Model; using UnityEngine; public sealed class AdventurePlay : MonoBehaviour { [SerializeField] private AdventureLogin login; private AdventurePlayer player; private bool busy; private bool awaitingResult; private bool blocked; private string message = "로그인 대기 중"; private bool CanInteract => player?.Ready == true && !busy; private bool CanWrite => CanInteract && player.HasPlayerData && !blocked; private async UniTask BeginQuest(string questName) { var transaction = await player.Gs2.Quest.Namespace("adventure-quest").Me(player.Session) .StartAsync("main", questName, force: false, speculativeExecute: false); awaitingResult = true; if (transaction != null) await transaction.WaitAsync(all: true); } private async UniTask CompleteQuest() { var transaction = await player.Gs2.Quest.Namespace("adventure-quest").Me(player.Session) .Progress().EndAsync(isComplete: true, speculativeExecute: false); awaitingResult = true; if (transaction != null) await transaction.WaitAsync(all: true); } private async UniTask BuyRefill() { var transaction = await player.Gs2.Exchange.Namespace("adventure-shop").Me(player.Session) .Exchange().ExchangeAsync("refill", 1, speculativeExecute: false); awaitingResult = true; if (transaction != null) await transaction.WaitAsync(all: true); } private void OnGUI() { if (login.Session == null) return; GUILayout.BeginArea(new Rect(20, 210, 650, 650), GUI.skin.box); GUILayout.Label(message); if (player?.Ready == true) { DrawStatus(); DrawQuestButtons(); DrawShop(); } GUI.enabled = true; GUILayout.EndArea(); } private void DrawQuestButtons() { GUI.enabled = CanWrite && player.Progress == null; foreach (var quest in player.Quests) { GUILayout.Label(quest.Metadata + " (" + quest.Name + ")"); if (GUILayout.Button("시작: " + quest.Name)) RunWrite(() => BeginQuest(quest.Name)).Forget(); } GUI.enabled = CanWrite && player.Progress != null; if (GUILayout.Button("클리어")) RunWrite(CompleteQuest).Forget(); } private void DrawStatus() { GUILayout.Label(player.Wallet?.Summary != null ? "코인: " + player.Wallet.Summary.Free : "코인 잔액을 가져올 수 없습니다"); GUILayout.Label(player.Progress == null ? "모험을 선택하세요" : "모험 진행 중"); if (player.Stamina == null) { GUILayout.Label("스태미나를 가져올 수 없습니다"); return; } var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + (player.Session.AccessToken.TimeOffset ?? 0) * 1000L; var display = player.Stamina.PredictRecovery(now); GUILayout.Label("스태미나: " + display.Value + " / " + player.Stamina.MaxValue); GUILayout.Label(display.NextRecoveryAt() > 0 ? "다음 회복: " + DateTimeOffset.FromUnixTimeMilliseconds(display.NextRecoveryAt()).ToLocalTime() : "자연 회복 대기 중이 아닙니다"); } private void DrawShop() { GUI.enabled = CanWrite; if (GUILayout.Button("20코인으로 스태미나 10 회복")) RunWrite(BuyRefill).Forget(); } private void Start() => Initialize().Forget(); private void OnDestroy() => player?.Dispose(); private async UniTask Initialize() { busy = true; try { await UniTask.WaitUntil(() => login.Session != null, cancellationToken: this.GetCancellationTokenOnDestroy()); message = "로딩 중"; player = new AdventurePlayer(login.Gs2, login.Session); await player.Load(); message = ""; } catch (OperationCanceledException) { } catch (Exception error) { message = "불러오지 못했습니다: " + error.GetType().Name; } finally { busy = false; } } private async UniTask RunWrite(Func operation) { if (!CanWrite) return; busy = true; awaitingResult = false; try { blocked = true; await operation(); blocked = false; message = ""; } catch (Exception error) { message = WriteError(error); } finally { busy = false; } } private string WriteError(Exception error) { if (error is Gs2.Gs2Stamina.Exception.InsufficientException || error is Gs2.Gs2Money2.Exception.InsufficientException || (!awaitingResult && error is Gs2.Core.Exception.BadRequestException)) { blocked = false; return error is Gs2.Gs2Stamina.Exception.InsufficientException ? "스태미나가 부족합니다. 회복한 뒤 다시 시도하세요" : error is Gs2.Gs2Money2.Exception.InsufficientException ? "코인이 부족합니다. 모험에서 모은 뒤 다시 시도하세요" : "작업을 실행하지 못했습니다. 설정을 확인하세요"; } return "처리 결과를 확인할 수 없어 새 작업을 중지했습니다: " + error.GetType().Name; } }