using UnityEngine; using asap.core; using System.Collections.Generic; using UniRx; using System.Linq; /// /// 单次加分对应的待播进度条动画参数;队列挂在 Data 单例上,避免 UI Manager 被销毁重建后丢失。 /// public struct EventPartnerStatueTokenExchangePendingUi { public float StartFill; public int OldTicketCount; public int TokenToGive; public float EndProgressRatio; } public class EventPartnerStatueTokenExchangeBomb { public int Multiplier { get; set; } } public class EventPartnerStatueTokenExchangeFishRaid { public int Multiplier { get; set; } } // public static class EventPartnerTokenExchangeContextRegistry // { // public static IEventPartnerTokenExchangeContext Context; // } // /// 待播 UI 队列有新条目时发布,供 Manager 在激活状态下启动消费协程。 // public class EventPartnerStatueTokenExchangePendingUiEnqueued // { // } //- 处理道具获得逻辑 public class EventPartnerStatueTokenExchangeData { #region State private int _eventId = 0; private int _tokenGiven = 0; private int _currentScore = 0; public int EventId => _eventId; public int TokenGiven => _tokenGiven; public int CurrentScore => _currentScore; #endregion private readonly Queue _pendingScoreUi = new Queue(); public int PendingScoreUiCount => _pendingScoreUi.Count; public int PendingScoreUiTokenToGive => _pendingScoreUi.Sum(item => item.TokenToGive); public void EnqueuePendingScoreUi(in EventPartnerStatueTokenExchangePendingUi item) { _pendingScoreUi.Enqueue(item); } public bool TryPeekPendingScoreUi(out EventPartnerStatueTokenExchangePendingUi item) { if (_pendingScoreUi.Count == 0) { item = default; return false; } item = _pendingScoreUi.Peek(); return true; } /// 在对应条目的动画完整播放后调用,从队列移除队首。 public void DequeueConsumedPendingScoreUi() { if (_pendingScoreUi.Count > 0) _pendingScoreUi.Dequeue(); } public void ClearPendingScoreUiQueue() { _pendingScoreUi.Clear(); } private CompositeDisposable _exchangeEventDisposables; private void EnsureExchangeEventSubscriptions() { if (_exchangeEventDisposables != null) return; _exchangeEventDisposables = new CompositeDisposable(); GContext.OnEvent() .Subscribe(OnTokenExchangeBomb) .AddTo(_exchangeEventDisposables); GContext.OnEvent() .Subscribe(OnTokenExchangeFishRaid) .AddTo(_exchangeEventDisposables); } private void OnTokenExchangeBomb(EventPartnerStatueTokenExchangeBomb evt) { Debug.Log("[EventPartnerStatueTokenExchange] OnTokenExchangeBomb: " + evt.Multiplier); var bombBaseScore = GetBombBaseScore(); ApplyTokenExchangeScore(evt.Multiplier * bombBaseScore); } private void OnTokenExchangeFishRaid(EventPartnerStatueTokenExchangeFishRaid evt) { Debug.Log("[EventPartnerStatueTokenExchange] OnTokenExchangeFishRaid: " + evt.Multiplier); var fishRaidBaseScore = GetFishRaidBaseScore(); ApplyTokenExchangeScore(evt.Multiplier * fishRaidBaseScore); } /// /// 逻辑加分并入队待播 UI;与 Manager 解耦,订阅在 中建立。 /// private void ApplyTokenExchangeScore(int addedScore) { Debug.Log("[EventPartnerStatueTokenExchange] ApplyTokenExchangeScore: " + addedScore); var context = GContext.container.Resolve(); if (context == null) { Debug.LogError("[EventPartnerStatueTokenExchange] token exchange context is null"); return; } int tokenGivenBefore = _tokenGiven; int currentScoreBefore = _currentScore; float startFill = GetCurrentPercentage(); (float progressRatio, int oldTicketCount, int tokenToGive) = OnAddScore(addedScore); if (_tokenGiven == tokenGivenBefore && _currentScore == currentScoreBefore) return; EnqueuePendingScoreUi(new EventPartnerStatueTokenExchangePendingUi { StartFill = startFill, OldTicketCount = oldTicketCount, TokenToGive = tokenToGive, EndProgressRatio = progressRatio }); // RedPointManager.Instance.SetRedPointState(context.RedPointKey, context.TicketCount > 0, context.TicketCount); // GContext.Publish(new EventPartnerStatueTokenExchangePendingUiEnqueued()); } private float _inflationRate = 1f; private GameCore.PlayerItemData _playerItemData = GContext.container.Resolve(); #region Data provider public float GetCurrentPercentage() { var p = (float)CurrentScore / GetExchangeRequirement(TokenGiven); p = Mathf.Clamp(p, 0f, 1f); return p; } #endregion #region Data storage public static void Load(cfg.FishingEvent e) { var data = GContext.container.Resolve(); if (data == null) { GContext.container.Register().AsSingleton(); data = GContext.container.Resolve(); } // data.BindContext(EventPartnerTokenExchangeContextRegistry.Context); data.EnsureExchangeEventSubscriptions(); var res = data.LoadData(); if (!res || data.EventId != e.ID) { data.SetData(e.ID, 0, 0); data.ClearPendingScoreUiQueue(); } } public void SetData(int eventId, int tokenGiven, int currentScore) { var context = GContext.container.Resolve(); _eventId = eventId; _tokenGiven = tokenGiven; _currentScore = currentScore; _inflationRate = context != null ? context.LureInflationRate : 1f; } private readonly string PlayfabKey = "EventPartnerStatueTokenExchangeData"; public void SaveData() { PlayFabMgr.Instance.UpdateUserDataValue(PlayfabKey, $"{_eventId}|{_tokenGiven}|{_currentScore}"); } public bool LoadData() { var s = PlayFabMgr.Instance.GetLocalData(PlayfabKey); if (s == null) return false; try { var tokens = s.Split('|'); var eventId = int.Parse(tokens[0]); var tokenGiven = int.Parse(tokens[1]); var currentScore = int.Parse(tokens[2]); SetData(eventId, tokenGiven, currentScore); return true; } catch (System.Exception e) { Debug.LogError(e); return false; } } #endregion #region Data logic public (float progressRatio, int oldTicketCount, int tokenToGive) OnAddScore(int addedScore) { var context = GContext.container.Resolve(); if (context == null) { Debug.LogError("[EventPartnerStatueTokenExchange] token exchange context is null"); return (0, 0, 0); } (int tokenToGive, float progressRatio, int newScore) = GetProgressDataV2(_tokenGiven, _currentScore, addedScore); _tokenGiven += tokenToGive; GContext.Publish(new game.TargetAddData(context.TokenExchangeItemId, _currentScore, addedScore)); _currentScore = newScore; var oldTicketCount = context.TicketCount; context.AddTicket(tokenToGive); SaveData(); return (progressRatio, oldTicketCount, tokenToGive); } #endregion #region TableData private List TokenExchangeStep { get { var context = GContext.container.Resolve(); var id = context.TokenExchangeId; return GContext.container.Resolve().TbEventPartnerTokenExchange[id].TokenExchangeStep; } } private List TokenExchangeRequirement { get { var context = GContext.container.Resolve(); var id = context.TokenExchangeId; return GContext.container.Resolve().TbEventPartnerTokenExchange[id].TokenExchangeRequirement; } } /// /// Get the exchange requirement for the given number of tokens /// /// The number of tokens given /// The exchange requirement private int GetExchangeRequirement(int tokenGiven) { var requirement = TokenExchangeRequirement; var step = TokenExchangeStep; if (requirement.Count == 0) { Debug.LogError("[EventPartnerStatueTokenExchange] TokenExchangeRequirement is empty"); return 100; } if (step.Count > 0 && requirement.Count < step.Count + 1) { Debug.LogError( $"[EventPartnerStatueTokenExchange] TokenExchangeRequirement.Count ({requirement.Count}) must be >= TokenExchangeStep.Count + 1 ({step.Count + 1})"); return 100; } int tierIndex; if (step.Count == 0) tierIndex = 0; else { tierIndex = step.Count; for (int i = 0; i < step.Count; i++) { if (tokenGiven < step[i]) { tierIndex = i; break; } } } int res = requirement[tierIndex]; res = _playerItemData.IntInflation(res, _inflationRate); if (res <= 0) { Debug.LogError($"[EventPartnerStatueTokenExchange] GetExchangeRequirement returned {res} for tokenGiven {tokenGiven}"); return 100; } return res; } private (int tokenToGive, float progressRatio, int remainingScore) GetProgressDataV2(int tokenGiven, int currentScore, int scoreToAdd) { int totalScore = currentScore + scoreToAdd; int tokenToGive = 0; int requirement = GetExchangeRequirement(tokenGiven); // Normalize + process in one loop while (totalScore >= requirement) { totalScore -= requirement; tokenToGive++; requirement = GetExchangeRequirement(tokenGiven + tokenToGive); } float ratio = (float)totalScore / requirement; return (tokenToGive, ratio, totalScore); } public int GetBombBaseScore() { var context = GContext.container.Resolve(); return GContext.container.Resolve().TbEventPartnerTokenExchange[context.TokenExchangeId].ExchangeParam[1]; } public int GetFishRaidBaseScore() { var context = GContext.container.Resolve(); return GContext.container.Resolve().TbEventPartnerTokenExchange[context.TokenExchangeId].ExchangeParam[0]; } #endregion }