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 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(); } 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 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; } }