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 = "Waiting for login"; 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("Start: " + quest.Name)) RunWrite(() => BeginQuest(quest.Name)).Forget(); } GUI.enabled = CanWrite && player.Progress != null; if (GUILayout.Button("Complete")) RunWrite(CompleteQuest).Forget(); } private void DrawStatus() { GUILayout.Label(player.Wallet?.Summary != null ? "Coins: " + player.Wallet.Summary.Free : "Could not load the coin balance"); GUILayout.Label(player.Progress == null ? "Choose an adventure" : "Adventure in progress"); if (player.Stamina == null) { GUILayout.Label("Could not load stamina"); return; } var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + (player.Session.AccessToken.TimeOffset ?? 0) * 1000L; var display = player.Stamina.PredictRecovery(now); GUILayout.Label("Stamina: " + display.Value + " / " + player.Stamina.MaxValue); GUILayout.Label(display.NextRecoveryAt() > 0 ? "Next recovery: " + DateTimeOffset.FromUnixTimeMilliseconds(display.NextRecoveryAt()).ToLocalTime() : "Not waiting for natural recovery"); } 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 = "Loading..."; player = new AdventurePlayer(login.Gs2, login.Session); await player.Load(); message = ""; } catch (OperationCanceledException) { } catch (Exception error) { message = "Could not load: " + 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 ? "Not enough stamina. Recover stamina and try again." : error is Gs2.Gs2Money2.Exception.InsufficientException ? "Not enough coins. Earn more in adventures and try again." : "Action failed. Check the settings."; } return "Cannot confirm the result. New actions are paused: " + error.GetType().Name; } }