using Gs2.Unity.Util; using Gs2.Unity.Core; using System; using Cysharp.Threading.Tasks; using Gs2.Unity.Gs2Inventory.Model; using UnityEngine; public sealed class AdventureItems : MonoBehaviour { private Gs2Domain Client => Gs2ClientHolder.Instance.Gs2; private IGameSession Session => Gs2GameSessionHolder.Instance != null && Gs2GameSessionHolder.Instance.Initialized ? Gs2GameSessionHolder.Instance.GameSession : null; private EzSimpleItem potion; private bool ready; private bool busy; private Func pendingOperation; private bool destroyed; private Action unsubscribe; private string message = "로딩 중"; private const string InventoryNamespace = "Inventory"; private void OnGUI() { if (Session == null) return; GUILayout.BeginArea(new Rect(700, 20, 650, 650), GUI.skin.box); GUILayout.Label("회복약"); GUILayout.Label(message); if (!ready) { GUILayout.EndArea(); return; } GUILayout.Label("회복약: " + (potion?.Count ?? 0) + "개"); GUI.enabled = !busy && pendingOperation == null; if (GUILayout.Button("회복약 1개로 스태미나 5 회복")) RunWrite(id => Exchange("use_potion", id)).Forget(); if (GUILayout.Button("20코인으로 회복약 1개 구매")) RunWrite(id => Exchange("buy_potion", id)).Forget(); GUI.enabled = !busy && pendingOperation != null; if (GUILayout.Button("같은 작업 재시도")) RetryWrite().Forget(); GUI.enabled = true; GUILayout.EndArea(); } private void Start() => Subscribe().Forget(); private void OnDestroy() { destroyed = true; unsubscribe?.Invoke(); } private async UniTask Subscribe() { try { await UniTask.WaitUntil(() => Session != null, cancellationToken: this.GetCancellationTokenOnDestroy()); var item = Client.Inventory.Namespace(InventoryNamespace).Me(Session) .SimpleInventory("Inventory").SimpleItem("potion"); var id = await item.SubscribeWithInitialCallAsync(value => potion = value); unsubscribe = () => item.Unsubscribe(id); if (destroyed) { unsubscribe(); return; } ready = true; message = ""; } catch (OperationCanceledException) { } catch (Exception error) { message = "불러오지 못했습니다: " + error.GetType().Name; } } private async UniTask Exchange(string rate, string requestId) { var transaction = await Client.Exchange.Namespace("adventure-item-actions").Me(Session).Exchange() .ExchangeAsync(rate, 1, 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; } } }