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
}