using Gs2.Unity.Util; using Gs2.Unity.Core; using System; using Cysharp.Threading.Tasks; using System.Linq; using Gs2.Unity.Gs2LoginReward.Model; using Gs2.Unity.Gs2Mission.Model; using UnityEngine; public sealed class AdventureDaily : MonoBehaviour { [SerializeField] private AdventureLogin login; private Gs2Domain Client => login.Gs2; private IGameSession Session => login == null ? null : login.Session; [SerializeField] private string missionGroup = "adventure"; [SerializeField] private string missionName = "clear3"; private bool ready; private bool busy; private Func pendingOperation; private bool destroyed; private Action unsubscribe; private string message = "読み込み中です"; private EzReceiveStatus loginStatus; private EzCounter counter; private EzComplete complete; private const string LoginNamespace = "adventure-login-reward"; private const string MissionNamespace = "adventure-mission"; private void OnGUI() { if (Session == null) return; GUILayout.BeginArea(new Rect(700, 20, 650, 850), GUI.skin.box); GUILayout.Label("ログインボーナスとミッション"); GUILayout.Label(message); if (!ready) { GUILayout.EndArea(); return; } for (var day = 0; day < 3; day++) { var claimed = loginStatus != null && loginStatus.ReceivedSteps != null && day < loginStatus.ReceivedSteps.Count && loginStatus.ReceivedSteps[day]; GUILayout.Label((day + 1) + "日目: " + (day + 1) * 10 + "コイン / " + (claimed ? "受取済み" : "未受取")); } GUI.enabled = ready && !busy && pendingOperation == null; if (GUILayout.Button("今日のログインボーナスを受け取る")) RunWrite(ReceiveLogin).Forget(); var clears = counter?.Values?.FirstOrDefault(value => value.ResetType == "notReset")?.Value ?? 0; var received = complete?.ReceivedMissionTaskNames?.Contains(missionName) == true; GUILayout.Label("冒険の累計クリア回数: " + clears); var completed = complete?.CompletedMissionTaskNames?.Contains(missionName) == true; GUILayout.Label(received ? "受取済み" : completed ? "ミッション報酬30コインを受け取れます" : "ミッションに挑戦中です"); GUI.enabled = !busy && pendingOperation == null && completed && !received; var mission = missionName; if (GUILayout.Button("ミッション報酬30コインを受け取る")) RunWrite(id => ReceiveMission(mission, 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 login = Client.LoginReward.Namespace(LoginNamespace).Me(Session).ReceiveStatus("daily"); var loginId = await login.SubscribeWithInitialCallAsync(value => loginStatus = value); if (!KeepSubscription(() => login.Unsubscribe(loginId))) return; var count = Client.Mission.Namespace(MissionNamespace).Me(Session).Counter("clear"); var counterId = await count.SubscribeWithInitialCallAsync(value => counter = value); if (!KeepSubscription(() => count.Unsubscribe(counterId))) return; var mission = Client.Mission.Namespace(MissionNamespace).Me(Session).Complete(missionGroup); var completeId = await mission.SubscribeWithInitialCallAsync(value => complete = value); if (!KeepSubscription(() => mission.Unsubscribe(completeId))) return; ready = true; message = ""; } catch (OperationCanceledException) { } catch (Exception error) { message = "読み込めませんでした: " + error.GetType().Name; } } private bool KeepSubscription(Action stop) { if (destroyed) { stop(); return false; } unsubscribe += stop; return true; } private async UniTask ReceiveLogin(string requestId) { var transaction = await Client.LoginReward.Namespace(LoginNamespace).Me(Session).Bonus() .ReceiveAsync("daily", speculativeExecute: false, duplicationAvoider: requestId); if (transaction != null) await transaction.WaitAsync(all: true); } private async UniTask ReceiveMission(string mission, string requestId) { var transaction = await Client.Mission.Namespace(MissionNamespace).Me(Session).Complete(missionGroup) .ReceiveRewardsAsync(mission, 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; } } }