1709 lines
59 KiB
C#
1709 lines
59 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using asap.core;
|
||
using cfg;
|
||
using EventPartnerGather;
|
||
using game;
|
||
using GameCore;
|
||
using Newtonsoft.Json;
|
||
using UniRx;
|
||
using UnityEngine;
|
||
|
||
using EEventBuildBuildState = EventPartnerGatherRequests.EEventBuildBuildState;
|
||
using EventPartnerGatherDetailResp = EventPartnerGatherRequests.EventPartnerGatherDetailResp;
|
||
using EventBuildBotInfo = EventPartnerData.EventBuildBotInfo;
|
||
using EEventBuildState = EventPartnerGatherRequests.EEventBuildState;
|
||
using AutoMatchStatusResponse = EventPartnerGatherRequests.AutoMatchStatusResponse;
|
||
using AutoMatchToggleResponse = EventPartnerGatherRequests.AutoMatchToggleResponse;
|
||
|
||
namespace DataCenter
|
||
{
|
||
public enum ESpinState
|
||
{
|
||
Normal,
|
||
Freespin,
|
||
Morespin
|
||
}
|
||
|
||
// EventPartnerGather 游戏数据结构
|
||
public class EventPartnerGatherData
|
||
{
|
||
public bool FirstOpen = true;
|
||
public int EventId;
|
||
public DateTime StartTime;
|
||
public DateTime EndTime;
|
||
|
||
// UI数据 和实际数据可能不同,进入游戏的时候,可以进入下一步,保存的情况下执行开发
|
||
// public int CurrentUIPoints = 0;
|
||
|
||
|
||
// 核心游戏数据
|
||
public int CurrentPoints = 0; // 当前积分
|
||
public int CurrentMiningProgress = 0; // 挖矿进度
|
||
|
||
// 同意需要多个
|
||
// public readonly List<int> CompletedNodes = new(); // 已完成的节点
|
||
|
||
// 好友系统数据(第二阶段)
|
||
// public List<FriendData> Friends = new();
|
||
public int Token = 0;
|
||
|
||
public int InvitedCount = 0;
|
||
// 代币数量, Detail的时候会获得吗
|
||
public int TicketCount; // 公用的
|
||
|
||
public List<List<int>> CompletedNodesList;
|
||
//
|
||
public List<(int myScore, int FriendScore)> BuilderPartnerScore;
|
||
|
||
// 获取当前的 More状态
|
||
// public List<(float BonusPercent, DateTime BonusExpireUtc)> BuilderPartnerBonus;
|
||
|
||
// public List<int> BuildFreeSpinNum;
|
||
|
||
|
||
public (float BonusPercent, DateTime BonusExpireUtc) PartnerBonus;
|
||
|
||
public int FreeSpinNum;
|
||
|
||
|
||
// 获取机器人
|
||
public Dictionary<int, EventBuildBotInfo> Bots { get; set; }
|
||
|
||
// 是否领取最终奖励
|
||
public bool IsRecvFinalReward = false;
|
||
|
||
// UI 上显示是否完成,
|
||
public List<bool> UIFinishedPartners;
|
||
|
||
// 当前活动 是否结束
|
||
public bool IsFinished = false;
|
||
// 默认显示
|
||
// public ESpinState SpinState = ESpinState.Normal;
|
||
//MoreSpin
|
||
// public float BonusPercent = 0f;
|
||
// public DateTime BonusExpireUtc = DateTime.MinValue;
|
||
//FreeSpin
|
||
// public int freeSpinNum = 0;
|
||
public ESpinState SpinState;
|
||
|
||
public float InflationRate;
|
||
|
||
// 自动匹配状态
|
||
public bool IsEnableAutoMatch = false; // 自动匹配开关
|
||
public DateTime LastAutoMatchTime = DateTime.MinValue; // 上次匹配时间
|
||
}
|
||
|
||
// EventPartnerGather 管理器
|
||
public class EventPartnerGatherManager : IAutoMatchManagerContext
|
||
{
|
||
private const bool EnableTraceLogs = false;
|
||
public const string SaveKey = "EventPartnerGatherData";
|
||
[Inject] public Tables _tables { get; set; }
|
||
|
||
[Inject] public EventPartnerService EventPartnerService { get; set; }
|
||
|
||
|
||
private FishingEvent _fishingEvent;
|
||
|
||
// 检查数据是否改变过
|
||
private bool _isEventDataChanged = false;
|
||
// 管理数值
|
||
public PartnerInfoManager PartnerInfoManager { get; private set; } = new();
|
||
public EventPartnerGatherRobotInvitationSystem RobotInvitationSystem { get; private set; } = new();
|
||
//
|
||
public EventPartnerGatherData GatherData { get; private set; }
|
||
// 数据
|
||
public EventPartnerMineMain EventPartnerMineMainData { get; private set; }
|
||
// 抽奖数据
|
||
public List<EventPartnerMineSpinPoint> EventPartnerMineSpinPointList { get; private set; }
|
||
// 模型数据,目前开来需要构造模型从表里读取
|
||
public EventPartnerMineInit EventPartnerMineInitData { get; private set; }
|
||
// 累分状态
|
||
private readonly List<int> _nodeCumulativeSteps = new();
|
||
// 状态积分,最后需要去除一个
|
||
private readonly List<int> _nodeSteps = new();
|
||
//
|
||
public List<int> NodeSteps => _nodeSteps;
|
||
public List<int> NodeCumulativeSteps => _nodeCumulativeSteps;
|
||
public int MaxSteps => _nodeCumulativeSteps.Count - 1;
|
||
public int EventId => GatherData?.EventId ?? -1;
|
||
public bool ShouldCloseAutoMatch => PartnerInfoManager.IsFullyMatched;
|
||
public bool IsAutoMatchEnabled => GatherData?.IsEnableAutoMatch ?? false;
|
||
public int AutoMatchSlotCount => PartnerInfoManager.BuildPartners.Length;
|
||
|
||
public DateTime StartTime;
|
||
// 结束时间
|
||
public DateTime EndTime;
|
||
|
||
|
||
|
||
|
||
private readonly List<int> _stageDropList = new();
|
||
|
||
private CompositeDisposable _disposables;
|
||
|
||
public bool IsFirstOpen
|
||
{
|
||
get => GatherData?.FirstOpen ?? false;
|
||
set
|
||
{
|
||
if (GatherData != null && GatherData.FirstOpen)
|
||
{
|
||
GatherData.FirstOpen = false;
|
||
SaveData();
|
||
}
|
||
}
|
||
}
|
||
|
||
public void UpdateEventData(FishingEvent fishingEvent)
|
||
{
|
||
Trace($"UpdateEventData eventId={fishingEvent?.ID}");
|
||
_fishingEvent = fishingEvent;
|
||
if (GatherData != null && _fishingEvent != null && GatherData.EventId != _fishingEvent.ID)
|
||
{
|
||
ClearData();
|
||
}
|
||
|
||
if (!_isInit || GatherData == null)
|
||
{
|
||
_isInit = false;
|
||
Init();
|
||
}
|
||
else
|
||
{
|
||
// {
|
||
UpdateLocalData();
|
||
UpdateTime();
|
||
SetRedPoint();
|
||
// }
|
||
}
|
||
}
|
||
|
||
#region 红点相关
|
||
public void SetRedPoint()
|
||
{
|
||
if (GatherData != null)
|
||
{
|
||
RedPointManager.Instance.SetRedPointState(RedPointKey, GatherData.TicketCount > 0, GatherData.TicketCount);
|
||
}
|
||
else
|
||
{
|
||
RedPointManager.Instance.SetRedPointState(RedPointKey, false);
|
||
}
|
||
}
|
||
|
||
public string RedPointKey { get; private set; } = RedPointName.Home_Parther;
|
||
#endregion
|
||
|
||
// 有可能改时间的,改时间不可清空保存的值
|
||
// public void ProcessLastChallenge()
|
||
// {
|
||
// UpdateTime();
|
||
// if (GatherData != null)
|
||
// {
|
||
// if (!IsTimeFinished())
|
||
// {
|
||
// ClearData();
|
||
// }
|
||
// }
|
||
// }
|
||
|
||
//
|
||
|
||
|
||
private bool _isInit = false;
|
||
|
||
public void Init()
|
||
{
|
||
if (_fishingEvent == null)
|
||
return;
|
||
if (_isInit)
|
||
return;
|
||
Trace($"Init eventId={EventId}");
|
||
|
||
if (GatherData == null)
|
||
{
|
||
CreateNewData();
|
||
}
|
||
InitManager();
|
||
UpdateLocalData();
|
||
UpdateTime();
|
||
SetRedPoint();
|
||
_isInit = true;
|
||
}
|
||
|
||
|
||
public void ReInit()
|
||
{
|
||
_isInit = false;
|
||
Init();
|
||
}
|
||
|
||
private void CreateNewData()
|
||
{
|
||
var limitedTime = (LimitedTime)_fishingEvent.TimeDefinition;
|
||
var startTime = GlobalUtils.TryParseDateTime(limitedTime.StartTime, ZZTimeHelper.UtcNow());
|
||
var endTime = GlobalUtils.TryParseDateTime(limitedTime.EndTime, ZZTimeHelper.UtcNow());
|
||
var ticketCount = GContext.container.Resolve<FishingEventData>().GetInitWelcomeGift(_fishingEvent.ID);
|
||
GatherData = new EventPartnerGatherData
|
||
{
|
||
FirstOpen = true,
|
||
EventId = _fishingEvent.ID,
|
||
StartTime = startTime,
|
||
EndTime = endTime,
|
||
CurrentPoints = 0,
|
||
CurrentMiningProgress = 0,
|
||
TicketCount = ticketCount,
|
||
|
||
BuilderPartnerScore = new List<(int myScore, int partnerScore)>(),
|
||
|
||
// {
|
||
// (0,0),(0,0),(0,0)
|
||
// },
|
||
PartnerBonus = (0F, DateTime.MinValue),
|
||
CompletedNodesList = new List<List<int>>(),
|
||
// {
|
||
// new(),
|
||
// new(),
|
||
// new(),
|
||
// },
|
||
// BuildFreeSpinNum = new List<int>{0,0,0},
|
||
FreeSpinNum = 0,
|
||
Bots = new Dictionary<int, EventBuildBotInfo>(),
|
||
// IsGetFinalReward = new List<bool>
|
||
// {
|
||
// false,false,false,
|
||
// },
|
||
IsRecvFinalReward = false,
|
||
UIFinishedPartners = new List<bool>(),
|
||
// { false, false, false },
|
||
InflationRate = GContext.container.Resolve<PlayerData>().InflationRate,
|
||
};
|
||
|
||
for (var i = 0; i < PartnerInfoManager.BuilderCapacity; ++i)
|
||
{
|
||
GatherData.BuilderPartnerScore.Add( (myScore:0,FriendScore:0));
|
||
GatherData.CompletedNodesList.Add(new List<int>());
|
||
GatherData.UIFinishedPartners.Add(false);
|
||
}
|
||
|
||
StartTime = startTime;
|
||
EndTime = endTime;
|
||
GContext.container.Resolve<FishingEventData>().SaveTransitionData(EventId, GatherData.TicketCount);
|
||
SaveData();
|
||
}
|
||
|
||
private void InitManager()
|
||
{
|
||
InitPartnerInfoManager();
|
||
InitRobotInvitationSystem();
|
||
}
|
||
|
||
private void InitPartnerInfoManager()
|
||
{
|
||
PartnerInfoManager.Init();
|
||
PartnerInfoManager.EventId = EventId;
|
||
}
|
||
|
||
private void InitRobotInvitationSystem()
|
||
{
|
||
RobotInvitationSystem.Init();
|
||
}
|
||
|
||
|
||
private void UpdateLocalData()
|
||
{
|
||
Trace($"UpdateLocalData eventId={EventId}");
|
||
if (_fishingEvent == null) return;
|
||
|
||
var redirectId = _fishingEvent.RedirectID;
|
||
var eventPartnerDataList = _tables.TbEventPartnerMineMain.DataList;
|
||
EventPartnerMineMainData = eventPartnerDataList.FirstOrDefault(data => data.ID == redirectId);
|
||
// var allSpinPoints = _tables.TbEventPartnerMineSpinPoint.DataList;
|
||
var ids = EventPartnerMineMainData?.SpinPoint;
|
||
if (ids is { Count: > 0 })
|
||
{
|
||
var filtered = new List<EventPartnerMineSpinPoint>();
|
||
foreach (var id in ids)
|
||
{
|
||
var sp = _tables.TbEventPartnerMineSpinPoint.GetOrDefault(id);
|
||
if (sp != null) filtered.Add(sp);
|
||
}
|
||
EventPartnerMineSpinPointList = filtered;
|
||
}
|
||
else
|
||
{
|
||
EventPartnerMineSpinPointList = new List<EventPartnerMineSpinPoint>();
|
||
}
|
||
_nodeCumulativeSteps.Clear();
|
||
_nodeSteps.Clear();
|
||
if (EventPartnerMineMainData?.StagePoint is { Count: > 0 })
|
||
{
|
||
var sum = 0;
|
||
foreach (var stagePoint in EventPartnerMineMainData.StagePoint)
|
||
{
|
||
_nodeSteps.Add(stagePoint);
|
||
sum += stagePoint;
|
||
_nodeCumulativeSteps.Add(sum);
|
||
}
|
||
}
|
||
var eventPartnerMineInitDataList = _tables.TbEventPartnerMineInit.DataList;
|
||
EventPartnerMineInitData = eventPartnerMineInitDataList.FirstOrDefault(data => data.ID == redirectId);
|
||
|
||
// if (EventPartnerMineMainData != null)
|
||
// GContext.container.Resolve<OfferRushDataProvider>().EventRefresh(_fishingEvent, EventPartnerMineMainData.RushId, RushType.OneDataKey);
|
||
}
|
||
|
||
private void UpdateTime()
|
||
{
|
||
if (_fishingEvent != null)
|
||
{
|
||
var limitedTime = (LimitedTime)_fishingEvent.TimeDefinition;
|
||
var startTime = GlobalUtils.TryParseDateTime(limitedTime.StartTime, ZZTimeHelper.UtcNow());
|
||
var endTime = GlobalUtils.TryParseDateTime(limitedTime.EndTime, ZZTimeHelper.UtcNow().AddDays(-1));
|
||
if (GatherData != null)
|
||
{
|
||
if (GatherData.EventId == _fishingEvent.ID)
|
||
{
|
||
GatherData.StartTime = startTime;
|
||
GatherData.EndTime = endTime;
|
||
}
|
||
else
|
||
{
|
||
GatherData.EndTime = DateTime.Now.AddDays(-1);
|
||
}
|
||
}
|
||
EndTime = endTime;
|
||
StartTime = startTime;
|
||
}
|
||
}
|
||
|
||
private void ValidateAndUpdateData()
|
||
{
|
||
if (GatherData == null) return;
|
||
// 验证时间有效性
|
||
// if (!IsTimeFinished())
|
||
// {
|
||
// HandleEventEnd();
|
||
// }
|
||
}
|
||
|
||
public bool IsTimeFinished()
|
||
{
|
||
var now = ZZTimeHelper.UtcNow();
|
||
Trace($"CheckTimeFinished now={now} endTime={EndTime}");
|
||
return now > EndTime;
|
||
}
|
||
|
||
|
||
public bool IsTimeValid()
|
||
{
|
||
if (GatherData == null) return false;
|
||
|
||
var now = ZZTimeHelper.UtcNow();
|
||
return now >= StartTime && now <= EndTime;
|
||
}
|
||
|
||
public TimeSpan GetRemainingTime()
|
||
{
|
||
if (GatherData == null)
|
||
return TimeSpan.Zero;
|
||
|
||
return EndTime - ZZTimeHelper.UtcNow();
|
||
}
|
||
|
||
public int GetFreeSpin(int slotId)
|
||
{
|
||
if (GatherData == null) return 0;
|
||
// var freeSpinNum = GatherData.BuildFreeSpinNum[slotId];
|
||
// return freeSpinNum;
|
||
return GatherData.FreeSpinNum;
|
||
}
|
||
|
||
public TimeSpan GetMoreTimeSpan(int slotId)
|
||
{
|
||
if (GatherData == null) return TimeSpan.Zero;
|
||
if (!IsBonusActive(slotId)) return TimeSpan.Zero;
|
||
var builderPartnerBonus = GatherData.PartnerBonus;
|
||
// var timespan = DateTime.MinValue - ZZTimeHelper.UtcNow();
|
||
// Log($"builderPartnerBonus = {builderPartnerBonus.BonusExpireUtc},{builderPartnerBonus.BonusPercent}");
|
||
return builderPartnerBonus.BonusExpireUtc - ZZTimeHelper.UtcNow();
|
||
}
|
||
|
||
|
||
|
||
public bool CheckOpen()
|
||
{
|
||
if (GatherData == null) return false;
|
||
if (!IsTimeValid()) return false;
|
||
if (GatherData.IsFinished) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
public static T WeightedRandom<T>(Dictionary<T, int> weightTable)
|
||
{
|
||
// 1. 计算总权重
|
||
var totalWeight = weightTable.Values.Sum();
|
||
// 2. 生成随机数
|
||
var randomValue = UnityEngine.Random.Range(0, totalWeight);
|
||
|
||
// 3. 线性遍历选择
|
||
var currentWeight = 0;
|
||
foreach (var (key, value) in weightTable)
|
||
{
|
||
currentWeight += value;
|
||
if (randomValue < currentWeight)
|
||
return key;
|
||
}
|
||
return default; // 理论上不会执行到这里
|
||
}
|
||
|
||
// 核心游戏逻辑
|
||
// 抽奖数据
|
||
public EventPartnerMineSpinPoint GetSpinPointElem(bool noCheating = false)
|
||
{
|
||
if (EventPartnerMineSpinPointList is { Count: > 0 })
|
||
{
|
||
// 根据权重,生成字典
|
||
var dict = EventPartnerMineSpinPointList.ToDictionary(elem => elem, elem => elem.Weight);
|
||
var elem = WeightedRandom(dict);
|
||
Trace($"GetSpinPointElem spinId={elem.ID}");
|
||
if (_userGm && _spinId != -1)
|
||
{
|
||
var elem1 = EventPartnerMineSpinPointList.Find(ele => ele.ID == _spinId);
|
||
if (elem1 != null)
|
||
{
|
||
Trace($"GetSpinPointElemGM spinId={elem1.ID}");
|
||
return elem1;
|
||
}
|
||
}
|
||
return elem;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public void AddPoints(int points)
|
||
{
|
||
if (GatherData == null)
|
||
{
|
||
LogWarning($"AddPointsInvalid eventId={EventId} reason=GatherDataNull");
|
||
return;
|
||
}
|
||
|
||
if (GatherData.IsFinished)
|
||
{
|
||
LogWarning($"AddPointsInvalid eventId={EventId} reason=EventFinished");
|
||
return;
|
||
}
|
||
|
||
if (points <= 0)
|
||
{
|
||
LogWarning($"AddPointsInvalid eventId={EventId} reason=InvalidValue points={points}");
|
||
return;
|
||
}
|
||
|
||
GatherData.CurrentPoints += points;
|
||
// var currentMiningProgress = CalcMiningProgressOld(GatherData.CurrentPoints);
|
||
// GatherData.CurrentMiningProgress = currentMiningProgress;
|
||
CurrentBuildPartner.AddSelfScore(points);
|
||
SavePartnerInfo(CurrentBuildPartner.SlotId);
|
||
Trace($"AddPoints eventId={EventId} delta={points} totalPoints={GatherData.CurrentPoints}");
|
||
UpdatePointAdd();
|
||
}
|
||
|
||
// 挖完了的时候,Step算在后面
|
||
public int CalcMiningProgressNew(int points)
|
||
{
|
||
var maxStep = _nodeCumulativeSteps.Count;
|
||
for (var i = 0; i < maxStep; ++i)
|
||
{
|
||
if (points < _nodeCumulativeSteps[i])
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
return maxStep - 1;
|
||
}
|
||
// 计算落在阶段,考虑机器人用,别出意外
|
||
public int CalcMiningProgressOld(int points)
|
||
{
|
||
var maxStep = _nodeCumulativeSteps.Count;
|
||
for (var i = 0; i < maxStep; ++i)
|
||
{
|
||
if (points <= _nodeCumulativeSteps[i])
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
return maxStep - 1;
|
||
}
|
||
|
||
private void UpdatePointAdd()
|
||
{
|
||
GContext.Publish(new EventPartnerGatherPointsUpdate { Points = GatherData.CurrentPoints });
|
||
// 检查是否需要触发自动挖矿
|
||
// CheckAutoMining();
|
||
}
|
||
|
||
public bool CompleteStage(int stageIndex)
|
||
{
|
||
Trace($"CompleteStage eventId={EventId} stageIndex={stageIndex} slotId={CurrentBuildPartner?.SlotId}");
|
||
var stageReward = EventPartnerMineMainData.StageReward;
|
||
|
||
var slotId = CurrentBuildPartner.SlotId;
|
||
var completedNodes = GatherData.CompletedNodesList[slotId];
|
||
if (stageIndex >= 0 && stageIndex < stageReward.Count)
|
||
{
|
||
if (!completedNodes.Contains(stageIndex))
|
||
{
|
||
completedNodes.Add(stageIndex);
|
||
_stageDropList.Add(EventPartnerMineMainData.StageReward[stageIndex]);
|
||
// 发放节点奖励
|
||
// DistributeStageReward(nodeIndex);
|
||
if (CurrentBuildPartner.IsPartnerRobot)
|
||
{
|
||
CurrentBuildPartner.ScheduleBotScoreAction();
|
||
}
|
||
SaveData();
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
public bool IsCompleteStageAll(int slotId)
|
||
{
|
||
var completedNodes = GatherData.CompletedNodesList[slotId];
|
||
var stageReward = EventPartnerMineMainData.StageReward;
|
||
|
||
var finalStaqe = stageReward.Count - 1;
|
||
return completedNodes.Contains(finalStaqe);
|
||
}
|
||
|
||
private void DistributeStageReward(int stageIndex)
|
||
{
|
||
Trace($"DistributeStageReward stageIndex={stageIndex}");
|
||
var stageReward = EventPartnerMineMainData.StageReward;
|
||
var playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||
if (stageIndex >= 0 && stageIndex < stageReward.Count - 1)
|
||
{
|
||
var dropId = stageReward[stageIndex];
|
||
ChangeSource changeSource = new ChangeSource(GatherData.EventId, "Event_Minigame4", "Event_Minigame4_Partner", "StageReward");
|
||
|
||
playerItemData.AddItemByDropListLureInflation(GatherData.InflationRate, new List<int> { dropId, }, changeSource);
|
||
GContext.Publish(new ShowData());
|
||
}
|
||
}
|
||
|
||
private int GetNodeRewardDropId(int nodeIndex)
|
||
{
|
||
return EventPartnerMineMainData.StageReward[nodeIndex];
|
||
}
|
||
|
||
private void DistributeFinalReward()
|
||
{
|
||
var dropId = GetFinalRewardDropId();
|
||
if (dropId > 0)
|
||
{
|
||
var playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||
var rewards = playerItemData.GetItemDataByDropIdLureInflation(GatherData.InflationRate, dropId);
|
||
ChangeSource changeSource = new ChangeSource(GatherData.EventId, "Event_Minigame4", "Event_Minigame4_Partner", "GrandReward");
|
||
|
||
playerItemData.AddItem(rewards, changeSource);
|
||
GContext.Publish(new ShowData(rewards));
|
||
}
|
||
}
|
||
|
||
private int GetFinalRewardDropId()
|
||
{
|
||
// 最终奖励掉落ID(后续从配置表读取)
|
||
return EventPartnerMineMainData.Reward;
|
||
}
|
||
|
||
// private void HandleEventEnd()
|
||
// {
|
||
// if (GatherData == null || GatherData.IsFinished) return;
|
||
//
|
||
// Log("Event Ended");
|
||
//
|
||
// // 结算未领取的奖励
|
||
// if (GatherData.CurrentMiningProgress >= MaxSteps && !GatherData.IsFinished)
|
||
// {
|
||
// HandleGameComplete();
|
||
// }
|
||
//
|
||
// ClearData();
|
||
// }
|
||
|
||
public int ResolvePointsWithBuffer(int points)
|
||
{
|
||
var rtPoints = points;
|
||
var slotId = CurrentBuildPartner?.SlotId ?? -1;
|
||
if (IsBonusActive(slotId))
|
||
{
|
||
// rtPoints *= (1 + GatherData.BonusPercent);
|
||
// var slotId = CurrentBuildPartner.SlotId;
|
||
// var (bonusPercent, bonusExpireUtc) = GatherData.BuilderPartnerBonus[slotId];
|
||
var (bonusPercent, bonusExpireUtc) = GatherData.PartnerBonus;
|
||
rtPoints = (int)(rtPoints * (1 + bonusPercent));
|
||
}
|
||
return Mathf.Max(0, rtPoints);
|
||
}
|
||
|
||
// public int ResolveSpinPoints(EventPartnerMineSpinPoint p)
|
||
// {
|
||
// if (p?.SpinPointParam == null) return 0;
|
||
// return p.SpinPointParam switch
|
||
// {
|
||
// NormalSpinPoint n => ResolvePointsWithBuffer(n.SpinPoints),
|
||
// FreeSpinPoint f => ResolvePointsWithBuffer(f.SpinPoints),
|
||
// MoreSpinPoint m => ResolvePointsWithBuffer(m.SpinPoints),
|
||
// _ => 0
|
||
// };
|
||
// }
|
||
//
|
||
// public ESpinState GetSpinState(EventPartnerMineSpinPoint p)
|
||
// {
|
||
// var spinState = p.SpinPointParam switch
|
||
// {
|
||
// NormalSpinPoint n => ESpinState.Normal,
|
||
// FreeSpinPoint f => ESpinState.Freespin,
|
||
// MoreSpinPoint m => ESpinState.Morespin,
|
||
// _ => ESpinState.Normal
|
||
// };
|
||
// return spinState;
|
||
// }
|
||
|
||
public void DoEventWithSpinState(EventPartnerMineSpinPoint p)
|
||
{
|
||
switch (p.SpinPointParam)
|
||
{
|
||
case NormalSpinPoint n:
|
||
FinFreeSpin();
|
||
break;
|
||
case FreeSpinPoint f:
|
||
ApplyFreeSpin(1);
|
||
break;
|
||
case MoreSpinPoint m:
|
||
FinFreeSpin();
|
||
ResolveBonus(m.BonusPercent, m.BonusDuration);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
public int ResolveSpinAndGetPoints(EventPartnerMineSpinPoint p, out ESpinState spinState)
|
||
{
|
||
spinState = ESpinState.Normal;
|
||
if (p?.SpinPointParam == null) return 0;
|
||
|
||
switch (p.SpinPointParam)
|
||
{
|
||
case NormalSpinPoint n:
|
||
spinState = ESpinState.Normal;
|
||
return ResolvePointsWithBuffer(n.SpinPoints);
|
||
case FreeSpinPoint f:
|
||
spinState = ESpinState.Freespin;
|
||
return ResolvePointsWithBuffer(f.SpinPoints);
|
||
case MoreSpinPoint m:
|
||
spinState = ESpinState.Morespin;
|
||
return ResolvePointsWithBuffer(m.SpinPoints);
|
||
}
|
||
return 0;
|
||
}
|
||
public void CleanSpinState()
|
||
{
|
||
if (GatherData == null) return;
|
||
// GatherData.freeSpinNum = 0;
|
||
GatherData.SpinState = ESpinState.Normal;
|
||
}
|
||
// 添加FreeSpin 状态
|
||
private void ApplyFreeSpin(int freeSpinNum)
|
||
{
|
||
if (GatherData == null) return;
|
||
var slot = CurrentBuildPartner.SlotId;
|
||
// GatherData.BuildFreeSpinNum[slot] = freeSpinNum;
|
||
GatherData.FreeSpinNum = freeSpinNum;
|
||
}
|
||
|
||
public void FinFreeSpin()
|
||
{
|
||
if (GatherData == null) return;
|
||
// var slot = CurrentBuildPartner.SlotId;
|
||
// GatherData.BuildFreeSpinNum[slot] = 0;
|
||
GatherData.FreeSpinNum = 0;
|
||
}
|
||
|
||
|
||
// 临时保存
|
||
|
||
public float BonusPercent;
|
||
public int BonusExpireDuration;
|
||
// public int spinPoint;
|
||
//
|
||
// public int SavePoint(int point)
|
||
// {
|
||
// spinPoint = point;
|
||
// return point;
|
||
// }
|
||
public void ResolveBonus(float percent, int durationSec)
|
||
{
|
||
BonusPercent = percent;
|
||
BonusExpireDuration = Mathf.Max(0, durationSec);
|
||
Trace($"ResolveBonus percent={BonusPercent} durationSec={BonusExpireDuration}");
|
||
}
|
||
|
||
private void ApplyBonus(float percent, int durationSec)
|
||
{
|
||
if (GatherData == null) return;
|
||
if (CurrentBuildPartner == null) return;
|
||
|
||
// var buildSlot = CurrentBuildPartner.SlotId;
|
||
// if (GatherData.BuilderPartnerBonus != null)
|
||
// {
|
||
// GatherData.BuilderPartnerBonus[buildSlot] = (Mathf.Max(0f, percent),
|
||
// ZZTimeHelper.UtcNow().AddSeconds(Mathf.Max(0, durationSec)));
|
||
// }
|
||
GatherData.PartnerBonus = (Mathf.Max(0f, percent),
|
||
ZZTimeHelper.UtcNow().AddSeconds(Mathf.Max(0, durationSec) + 0.5f));
|
||
SaveData();
|
||
}
|
||
|
||
// 确定是否过期??
|
||
public void EnsureBonusValid()
|
||
{
|
||
if (GatherData == null) return;
|
||
if (CurrentBuildPartner == null) return;
|
||
|
||
// var slotId = CurrentBuildPartner.SlotId;
|
||
// var (_, bonusExpireUtc) = GatherData.BuilderPartnerBonus[slotId];
|
||
var (_, bonusExpireUtc) = GatherData.PartnerBonus;
|
||
if (ZZTimeHelper.UtcNow() > bonusExpireUtc)
|
||
{
|
||
// GatherData.BonusPercent = 0f;
|
||
// GatherData.BonusExpireUtc = DateTime.MinValue;
|
||
// GatherData.BuilderPartnerBonus[slotId] = (0f, DateTime.MinValue);
|
||
GatherData.PartnerBonus = (0f, DateTime.MinValue);
|
||
SaveData();
|
||
GContext.Publish(new EventPartnerGatherBonusEndEvent());
|
||
}
|
||
|
||
// if (CurrentBuildPartner == null) return;
|
||
// if (CurrentBuildPartner.BonusPercent > 0f && ZZTimeHelper.UtcNow() > CurrentBuildPartner.BonusExpireUtc)
|
||
// {
|
||
// GatherData.BonusPercent = 0f;
|
||
// GatherData.BonusExpireUtc = DateTime.MinValue;
|
||
// SaveData();
|
||
// GContext.Publish(new EventPartnerGatherRefreshBonus());
|
||
// }
|
||
}
|
||
public bool IsBonusActive(int slotId)
|
||
{
|
||
if (GatherData == null) return false;
|
||
if (slotId == -1) return false;
|
||
// var (bonusPercent, bonusExpireUtc) = GatherData.BuilderPartnerBonus[slotId];
|
||
var (bonusPercent, bonusExpireUtc) = GatherData.PartnerBonus;
|
||
return bonusPercent > 0f && ZZTimeHelper.UtcNow() < bonusExpireUtc;
|
||
}
|
||
public void SaveData()
|
||
{
|
||
// Log("SaveData()-> ");
|
||
|
||
#if UNITY_EDITOR
|
||
Trace($"SaveData eventId={EventId}");
|
||
#endif
|
||
{
|
||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(GatherData));
|
||
}
|
||
}
|
||
public void LoadData(string dataValue)
|
||
{
|
||
Trace($"LoadData eventId={EventId} hasData={!string.IsNullOrEmpty(dataValue)}");
|
||
if (!string.IsNullOrEmpty(dataValue))
|
||
{
|
||
GatherData = JsonConvert.DeserializeObject<EventPartnerGatherData>(dataValue);
|
||
}
|
||
}
|
||
public void ClearData()
|
||
{
|
||
GatherData = null;
|
||
|
||
CurrentBuildPartner?.ClearData();
|
||
// CurrentBuildPartner.ClearReceivedCalls();
|
||
SaveData();
|
||
}
|
||
|
||
// 进入游戏场景
|
||
public void EnterGatherScene()
|
||
{
|
||
Trace($"EnterGatherScene eventId={EventId}");
|
||
IsFirstOpen = false;
|
||
// var list = EventPartnerMineMainData.Addressable;
|
||
GContext.Publish(new UnloadActToNextAct("EventPartnerGatherAct", UITypes.CloudTransitionPanel, 0.5f));
|
||
}
|
||
|
||
public BuildPartner CurrentBuildPartner { get; set; }
|
||
// 开始采矿
|
||
public void StartBuildProgress(BuildPartner buildPartner)
|
||
{
|
||
CurrentBuildPartner = buildPartner;
|
||
// 更新点数
|
||
var points = buildPartner.ScorePartnerActual + buildPartner.ScoreSelfActual;
|
||
GatherData.CurrentPoints = points;
|
||
// GatherData.CurrentMiningProgress = CalcMiningProgressNew(points);
|
||
Trace($"StartBuildProgress eventId={EventId} slotId={CurrentBuildPartner?.SlotId} partnerId={CurrentBuildPartner?.PartnerId}");
|
||
((EventPartnerGatherAct)_act)?.OnEnterGather();
|
||
}
|
||
|
||
public void FinishMining()
|
||
{
|
||
Trace($"FinishMining eventId={EventId}");
|
||
((EventPartnerGatherAct)_act)?.OnLeaveGather();
|
||
}
|
||
|
||
private static void LogError(object t)
|
||
{
|
||
Debug.LogError($"<color=red>EventPartnerGatherManager-> {t} </color>");
|
||
}
|
||
private static void ELog(object t)
|
||
{
|
||
#if UNITY_EDITOR
|
||
Debug.Log($"<color=cyan>EventPartnerGatherManager-> {t} </color>");
|
||
#endif
|
||
}
|
||
[System.Diagnostics.Conditional("UNITY_EDITOR")]
|
||
private static void Trace(object t)
|
||
{
|
||
if (!EnableTraceLogs) return;
|
||
ELog(t);
|
||
}
|
||
//-
|
||
public static void Log(string message)
|
||
{
|
||
Debug.Log($"<color=cyan>EventPartnerGatherManager-> {message} </color>");
|
||
}
|
||
public static void LogWarning(string message)
|
||
{
|
||
Debug.LogWarning($"<color=yellow>EventPartnerGatherManager-> {message} </color>");
|
||
}
|
||
|
||
private AGameAct _act;
|
||
public void SetGameAct(AGameAct act)
|
||
{
|
||
_act = act;
|
||
}
|
||
|
||
public AGameAct GetGameAct()
|
||
{
|
||
return _act;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 通知所有绑定组件刷新数据显示
|
||
/// </summary>
|
||
public void RefreshAllUI()
|
||
{
|
||
if (GatherData == null) return;
|
||
// 刷新抽奖面板
|
||
// if (_drawPanel)
|
||
// {
|
||
// _drawPanel?.SetMiningProgress(GatherData.CurrentMiningProgress);
|
||
// }
|
||
|
||
Trace($"RefreshAllUI eventId={EventId}");
|
||
}
|
||
|
||
|
||
// 有可能会激活,不应该在OnEnable 中调用Init();
|
||
// public bool CheckForOnEnable()
|
||
// {
|
||
//
|
||
// return false
|
||
// }
|
||
|
||
// 获取挖矿的数量
|
||
public int CalcWaNum(int point, out int leftPoint)
|
||
{
|
||
var minePoint = EventPartnerMineMainData.MinePoint;
|
||
var num = Mathf.Clamp(point / minePoint, 0, point);
|
||
|
||
leftPoint = (point - num * minePoint);
|
||
return num;
|
||
}
|
||
|
||
// 获取当前Spin的Cost
|
||
public int CalcSpinCost(int multipleValue)
|
||
{
|
||
return multipleValue * EventPartnerMineMainData.SpinRequire;
|
||
}
|
||
//
|
||
public int GetCumulativeStepPoint(int prevStep)
|
||
{
|
||
if (prevStep < 0)
|
||
return 0;
|
||
prevStep = Mathf.Clamp(0, prevStep, _nodeCumulativeSteps.Count - 1);
|
||
return _nodeCumulativeSteps[prevStep];
|
||
}
|
||
|
||
public int GetStageReward(int step)
|
||
{
|
||
return EventPartnerMineMainData.StageReward[step];
|
||
}
|
||
//
|
||
public int GetStepPoints(int step)
|
||
{
|
||
return step < _nodeSteps.Count ? _nodeSteps[step] : 0;
|
||
}
|
||
|
||
public int GetGoColumn(int waPoint, int waProgress)
|
||
{
|
||
var num = CalcWaNum(waPoint, out var leftPoint);
|
||
var column = 0;
|
||
// if (leftPoint > 0)
|
||
// {
|
||
// num += 1;
|
||
// }
|
||
var mps = EventPartnerMineMainData.MinePointShow[waProgress];
|
||
if (EventPartnerMineMainData != null)
|
||
{
|
||
column = num / mps;
|
||
// column2 = num2 / mps;
|
||
}
|
||
Trace($"GetGoColumn waPoint={waPoint} num={num} curProgress={waProgress} mps={mps} column={column}");
|
||
return column;
|
||
}
|
||
|
||
// private readonly int maxCol = 3;
|
||
// 每次挖矿最多消耗的点数,根据排数进行计算
|
||
public int GetConsumePoint(int curProgress)
|
||
{
|
||
var maxCol = EventPartnerMineMainData.MaxColumn;
|
||
var oreScore = EventPartnerMineMainData.MinePoint;
|
||
var mps = EventPartnerMineMainData.MinePointShow[curProgress];
|
||
return mps * maxCol * oreScore;
|
||
}
|
||
|
||
// 根据点数获得进度
|
||
|
||
// AGG 使用
|
||
public int GetMiningProgress()
|
||
{
|
||
// return GatherData.CurrentMiningProgress;
|
||
var currentProgress = CalcMiningProgressNew(CurrentBuildPartner.ScorePartnerActual + CurrentBuildPartner.ScoreSelfActual);
|
||
return currentProgress;
|
||
}
|
||
|
||
//
|
||
// public int NextMiningProgress()
|
||
// {
|
||
// Log($"NextMiningProgress()-> {GatherData.CurrentMiningProgress}");
|
||
// GatherData.CurrentMiningProgress += 1;
|
||
// // var curLeftPoint = GetStepPoints(GatherData.CurrentMiningProgress);
|
||
// // SetLeftPoint(curLeftPoint);
|
||
// Log($"NextMiningProgress()-> End: {GatherData.CurrentMiningProgress}");
|
||
// SaveData();
|
||
// return GatherData.CurrentMiningProgress;
|
||
// }
|
||
//
|
||
// public int GetFullStep()
|
||
// {
|
||
// var stagePoint = EventPartnerMineMainData.StagePoint;
|
||
// return stagePoint.Count;
|
||
// }
|
||
|
||
public bool PlayGetStageReward()
|
||
{
|
||
Trace($"PlayGetStageReward currentProgress={GatherData?.CurrentMiningProgress} dropCount={_stageDropList.Count}");
|
||
var playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||
if (_stageDropList.Count > 0)
|
||
{
|
||
ChangeSource changeSource = new ChangeSource(GatherData.EventId, "Event_Minigame4", "Event_Minigame4_Partner", "StageReward");
|
||
|
||
var itemDatas = playerItemData.AddItemByDropListLureInflation(GatherData.InflationRate, _stageDropList, changeSource);
|
||
GContext.Publish(new ShowData());
|
||
_stageDropList.Clear();
|
||
|
||
var partnerId = CurrentBuildPartner?.PartnerId ?? "";
|
||
if (CurrentBuildPartner is { IsPartnerRobot: true })
|
||
{
|
||
partnerId = "robot";
|
||
}
|
||
Trace($"PlayGetFinalReward partnerId={partnerId}");
|
||
#if AGG
|
||
using (var e = GEvent.GameEvent("event_partners_gather_reward"))
|
||
{
|
||
var hookCount = 0;
|
||
if (itemDatas is { Count: > 0 })
|
||
{
|
||
for (int i = 0; i < itemDatas.Count; i++)
|
||
{
|
||
if (itemDatas[i].id == 1001)
|
||
{
|
||
hookCount += itemDatas[i].count;
|
||
}
|
||
}
|
||
}
|
||
e.AddContent("teammate_id", partnerId)
|
||
.AddContent("position_id", CurrentBuildPartner.SlotId)
|
||
.AddContent("stage_id", GetMiningProgress())
|
||
.AddContent("reward_hook", hookCount);
|
||
}
|
||
#endif
|
||
SaveData();
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
// 某一个stage获得奖励
|
||
public bool PlayGetStageReward(int stageIndex)
|
||
{
|
||
var stageReward = EventPartnerMineMainData.StageReward;
|
||
var playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||
if (stageIndex >= 0 && stageIndex < stageReward.Count - 1)
|
||
{
|
||
var dropId = stageReward[stageIndex];
|
||
ChangeSource changeSource = new ChangeSource(GatherData.EventId, "Event_Minigame4", "Event_Minigame4_Partner", "StageReward");
|
||
|
||
playerItemData.AddItemByDropListLureInflation(GatherData.InflationRate, new List<int> { dropId, }, changeSource);
|
||
GContext.Publish(new ShowData());
|
||
}
|
||
|
||
// CompleteTrainNode(stageIndex);
|
||
return false;
|
||
}
|
||
private int GetFinalReward()
|
||
{
|
||
return EventPartnerMineMainData.Reward;
|
||
}
|
||
public void PlayGetFinalReward()
|
||
{
|
||
// var slotId = CurrentBuildPartner.SlotId;
|
||
if (GatherData.IsRecvFinalReward)
|
||
{
|
||
return;
|
||
}
|
||
GatherData.IsRecvFinalReward = true;
|
||
// SaveData();
|
||
var playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||
var dropId = GetFinalReward();
|
||
ChangeSource changeSource = new ChangeSource(GatherData.EventId, "Event_Minigame4", "Event_Minigame4_Partner", "GrandReward");
|
||
|
||
var itemDatas = playerItemData.AddItemByDropListLureInflation(GatherData.InflationRate, new List<int> { dropId, }, changeSource);
|
||
|
||
var partnerId = CurrentBuildPartner?.PartnerId ?? "";
|
||
if (CurrentBuildPartner is { IsPartnerRobot: true })
|
||
{
|
||
partnerId = "robot";
|
||
}
|
||
Trace($"PlayGetFinalReward partnerId={partnerId}");
|
||
|
||
#if AGG
|
||
using (var e = GEvent.GameEvent("event_partners_gather_reward"))
|
||
{
|
||
var hookCount = 0;
|
||
if (itemDatas is { Count: > 0 })
|
||
{
|
||
for (int i = 0; i < itemDatas.Count; i++)
|
||
{
|
||
if (itemDatas[i].id == 1001)
|
||
{
|
||
hookCount += itemDatas[i].count;
|
||
}
|
||
}
|
||
}
|
||
e.AddContent("teammate_id", partnerId)
|
||
.AddContent("position_id", 99)
|
||
.AddContent("stage_id", 99)
|
||
.AddContent("reward_hook", hookCount);
|
||
}
|
||
#endif
|
||
GContext.Publish(new ShowData());
|
||
|
||
SaveData();
|
||
}
|
||
//
|
||
public int CollectPointAndCalcValid(int step, int points)
|
||
{
|
||
// var step = GatherData.CurrentMiningProgress;
|
||
// return AddCollectPoints(points)
|
||
return points - GetCumulativeStepPoint(step - 1);
|
||
}
|
||
|
||
private int _spinId = -1;
|
||
private bool _userGm = false;
|
||
|
||
public void GmSetSpinId(int spinId)
|
||
{
|
||
_spinId = spinId;
|
||
if (spinId > 0)
|
||
{
|
||
_userGm = true;
|
||
}
|
||
}
|
||
|
||
public void CloseGM()
|
||
{
|
||
_userGm = false;
|
||
_spinId = -1;
|
||
}
|
||
|
||
public List<int> GetSpinMag()
|
||
{
|
||
return EventPartnerMineMainData.SpinMag;
|
||
}
|
||
|
||
public bool IsStepFinished(int slotId, int step)
|
||
{
|
||
// return GatherData?.CompletedNodes?.Contains(step) ?? false;
|
||
// var slotId = CurrentBuildPartner.SlotId;
|
||
var completeNode = GatherData?.CompletedNodesList[slotId] ?? new List<int>();
|
||
return completeNode?.Contains(step) ?? false;
|
||
}
|
||
|
||
|
||
public void LoadPlayFabData()
|
||
{
|
||
// PartnerInfoManager.LoadPlayFabData();
|
||
|
||
// 之前是为了适配,后面看看是否可删除
|
||
var buildScore = GatherData.BuilderPartnerScore;
|
||
if (buildScore == null)
|
||
{
|
||
//buildScore = new List<(int myScore, int FriendScore)> { (0, 0), (0, 0), (0, 0) };
|
||
buildScore = new List<(int myScore, int FriendScore)>();
|
||
for (var i = 0; i < PartnerInfoManager.BuilderCapacity; ++i)
|
||
{
|
||
buildScore.Add((0, 0));
|
||
}
|
||
|
||
|
||
GatherData.BuilderPartnerScore = buildScore;
|
||
// 很少会调用
|
||
SaveData();
|
||
}
|
||
|
||
// var builderPartnerBonus = GatherData.BuilderPartnerBonus;
|
||
// var builderPartnerBonus = GatherData.PartnerBonus;
|
||
// if (builderPartnerBonus == null)
|
||
{
|
||
// builderPartnerBonus = new List<(float BonusPercent, DateTime BonusExpireUtc)>
|
||
// {
|
||
// (0F, DateTime.MinValue), (0F, DateTime.MinValue), (0F, DateTime.MinValue)
|
||
// };
|
||
// GatherData.PartnerBonus = (0F, DateTime.MinValue);
|
||
// SaveData();
|
||
}
|
||
|
||
var completedNodesList = GatherData.CompletedNodesList;
|
||
if (completedNodesList == null)
|
||
{
|
||
completedNodesList = new List<List<int>>();
|
||
// {
|
||
// new(), new(), new(),
|
||
// };
|
||
for (var i = 0; i < PartnerInfoManager.BuilderCapacity; ++i)
|
||
{
|
||
completedNodesList.Add(new List<int>());
|
||
}
|
||
GatherData.CompletedNodesList = completedNodesList;
|
||
SaveData();
|
||
}
|
||
|
||
var bots = GatherData.Bots;
|
||
if (bots == null)
|
||
{
|
||
bots = new Dictionary<int, EventBuildBotInfo>();
|
||
GatherData.Bots = bots;
|
||
SaveData();
|
||
}
|
||
|
||
|
||
var fi = GatherData.UIFinishedPartners;
|
||
if (fi == null)
|
||
{
|
||
fi = new List<bool> { false, false, false };
|
||
GatherData.UIFinishedPartners = fi;
|
||
SaveData();
|
||
}
|
||
|
||
// var bf = GatherData.BuildFreeSpinNum;
|
||
// if (bf == null)
|
||
// {
|
||
// bf = new List<int> { 0, 0, 0 };
|
||
// GatherData.BuildFreeSpinNum = bf;
|
||
// SaveData();
|
||
// }
|
||
|
||
PartnerInfoManager.SyncGatherData(this);
|
||
}
|
||
|
||
//
|
||
private readonly int _timeCount = 60 * 2;
|
||
// 定时
|
||
private DateTime _dateTimeForGetEvent = DateTime.MinValue;
|
||
// 是否允许请求
|
||
private bool CheckGetDetailEnable()
|
||
{
|
||
var timeSpan = ZZTimeHelper.UtcNow() - _dateTimeForGetEvent;
|
||
return timeSpan.TotalSeconds > _timeCount;
|
||
}
|
||
public async Task<bool> GetEventDetail(bool force = false)
|
||
{
|
||
if (!force && !CheckGetDetailEnable())
|
||
return false;
|
||
|
||
_dateTimeForGetEvent = ZZTimeHelper.UtcNow();
|
||
|
||
var resp = await EventPartnerService.GetEventDetail(EventId);
|
||
switch (resp?.State)
|
||
{
|
||
case EEventBuildState.Success:
|
||
LoadBuilderData(resp);
|
||
return true;
|
||
case EEventBuildState.Failed:
|
||
case EEventBuildState.InviteNotFound:
|
||
case EEventBuildState.AlreadyExist:
|
||
case EEventBuildState.NoActiveEvent:
|
||
case EEventBuildState.Full:
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public void LoadBuilderData(EventPartnerGatherDetailResp resp)
|
||
{
|
||
Trace($"LoadBuilderData eventId={EventId} state={resp?.State}");
|
||
PartnerInfoManager.LoadBuildInfo(resp.Detail, GatherData.Bots);
|
||
PartnerInfoManager.LoadScore(resp.Detail.Scores, GatherData.BuilderPartnerScore);
|
||
}
|
||
|
||
public async Task<bool> BuildWorks(int score, int cost)
|
||
{
|
||
if (GatherData.TicketCount < cost)
|
||
{
|
||
// Log("当前的代币不够用了");
|
||
// ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_21"));
|
||
GContext.Publish(new EventPartnerGatherShowPack());
|
||
return false;
|
||
}
|
||
|
||
|
||
if (score <= 0 && cost > 0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
var partnerId = CurrentBuildPartner.PartnerId;
|
||
var newScore = CurrentBuildPartner.ScoreSelfActual + score;
|
||
// CurrentBuildPartner.ScoreSelfActual = newScore;
|
||
Trace($"BuildWorks eventId={EventId} partnerId={partnerId} newScore={newScore} cost={cost}");
|
||
|
||
if (partnerId.EndsWith(EventPartnerBot.RobotIdentifier))
|
||
{
|
||
// CurrentBuildPartner.SyncRobotScore();
|
||
// DoNothing();
|
||
}
|
||
else
|
||
{
|
||
var response = await EventPartnerService.BuildWorks(partnerId, newScore, EventId);
|
||
if (response.State != EEventBuildBuildState.Success)
|
||
{
|
||
LogWarning($"BuildRequestFailed eventId={EventId} partnerId={partnerId} state={response.State} reason={response.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
AddTicket(-cost);
|
||
return true;
|
||
}
|
||
|
||
public void AddTicketPure(int costValue)
|
||
{
|
||
if (GatherData != null)
|
||
{
|
||
GatherData.TicketCount += costValue;
|
||
if (GatherData.TicketCount < 0)
|
||
{
|
||
GatherData.TicketCount = 0;
|
||
}
|
||
GContext.container.Resolve<FishingEventData>().SaveTransitionData(EventId, GatherData.TicketCount);
|
||
GContext.Publish(new EventPartnerGatherUpdateTicketCount());
|
||
SaveData();
|
||
}
|
||
}
|
||
public void AddTicket(int costValue)
|
||
{
|
||
if (GatherData != null)
|
||
{
|
||
GatherData.TicketCount += costValue;
|
||
if (GatherData.TicketCount < 0)
|
||
{
|
||
GatherData.TicketCount = 0;
|
||
}
|
||
GContext.container.Resolve<FishingEventData>().SaveTransitionData(EventId, GatherData.TicketCount);
|
||
GContext.Publish(new EventPartnerGatherUpdateTicketCount());
|
||
SaveData();
|
||
}
|
||
SetRedPoint();
|
||
}
|
||
|
||
public int GetLeftPoint(int usedPoints, int progress)
|
||
{
|
||
// var progress = CalcMiningProgressOld(usedPoints);
|
||
if (progress >= _nodeCumulativeSteps.Count)
|
||
{
|
||
return 0;
|
||
}
|
||
return NodeCumulativeSteps[progress] - usedPoints;
|
||
}
|
||
|
||
public void AddInvitationCount()
|
||
{
|
||
GatherData.InvitedCount++;
|
||
}
|
||
|
||
public void ResetBuildPartner(int slotId)
|
||
{
|
||
Trace($"ResetBuildPartner eventId={EventId} slotId={slotId}");
|
||
//
|
||
if (GatherData.UIFinishedPartners != null && slotId < GatherData.UIFinishedPartners.Count)
|
||
{
|
||
GatherData.UIFinishedPartners[slotId] = false;
|
||
}
|
||
|
||
if (GatherData.BuilderPartnerScore != null && slotId < GatherData.BuilderPartnerScore.Count)
|
||
{
|
||
GatherData.BuilderPartnerScore[slotId] = (0, 0);
|
||
}
|
||
|
||
if (GatherData.CompletedNodesList != null && slotId < GatherData.CompletedNodesList.Count)
|
||
{
|
||
GatherData.CompletedNodesList[slotId] = new List<int>();
|
||
}
|
||
}
|
||
|
||
public void SavePartnerInfo(int slotId)
|
||
{
|
||
Trace($"SavePartnerInfo eventId={EventId} slotId={slotId}");
|
||
var partners = PartnerInfoManager.BuildPartners;
|
||
if (slotId > partners.Length - 1)
|
||
{
|
||
Trace($"SyncFromPartnerInfoFailed eventId={EventId} slotId={slotId} partnerCount={partners.Length}");
|
||
return;
|
||
}
|
||
|
||
var partner = partners[slotId];
|
||
partner.ScorePartnerDisplay = partner.ScorePartnerActual;
|
||
partner.ScoreSelfDisplay = partner.ScoreSelfActual;
|
||
GatherData.BuilderPartnerScore[slotId] = (partner.ScoreSelfActual, partner.ScorePartnerActual);
|
||
SaveData();
|
||
}
|
||
|
||
public void SyncPartnerInfoToSave()
|
||
{
|
||
Trace($"SyncFromPartnerInfo eventId={EventId}");
|
||
var partners = PartnerInfoManager.BuildPartners;
|
||
for (var i = 0; i < partners.Length; ++i)
|
||
{
|
||
var partner = partners[i];
|
||
GatherData.BuilderPartnerScore[i] = (partner.ScoreSelfActual, partner.ScorePartnerActual);
|
||
}
|
||
SaveData();
|
||
}
|
||
|
||
public int GetProgressBySlotId(int slotId)
|
||
{
|
||
if (slotId > GatherData.BuilderPartnerScore.Count)
|
||
{
|
||
return -1;
|
||
}
|
||
var (myScore, partnerScore) = GatherData.BuilderPartnerScore[slotId];
|
||
var buildScore = myScore + partnerScore;
|
||
return CalcMiningProgressOld(buildScore);
|
||
}
|
||
|
||
public void SaveBotInfo(int idx, EventBuildBotInfo botInfo)
|
||
{
|
||
// throw new NotImplementedException();
|
||
var ret = GatherData.Bots.TryAdd(idx, botInfo);
|
||
if (ret)
|
||
{
|
||
// dosmt
|
||
}
|
||
}
|
||
|
||
public int startTime;
|
||
|
||
public int delta;
|
||
|
||
public void GMRobotStartTIme(int timeSeconds)
|
||
{
|
||
startTime = timeSeconds;
|
||
}
|
||
|
||
public void GMRobotDelta(int timeSeconds)
|
||
{
|
||
delta = timeSeconds;
|
||
}
|
||
|
||
public bool GetDoRecommendBot()
|
||
{
|
||
// if (true)
|
||
// {
|
||
// return true;
|
||
// }
|
||
return !PartnerInfoManager.IsFullyMatched && (GatherData.InvitedCount >= _tables.TbEventPartnerConfig.RobotRecommendTriggerCount);
|
||
}
|
||
|
||
public static void EnsureTokenExchangeContextRegistered(EventPartnerGatherManager manager)
|
||
{
|
||
var context = GContext.container.Resolve<IEventPartnerTokenExchangeContext>();
|
||
if (context == null)
|
||
{
|
||
GContext.container.Unregister<IEventPartnerTokenExchangeContext>();
|
||
GContext.container.Register<IEventPartnerTokenExchangeContext, EventPartnerGatherExchangeContext>().AsSingleton();
|
||
context = GContext.container.Resolve<IEventPartnerTokenExchangeContext>();
|
||
}
|
||
if (context is EventPartnerGatherExchangeContext tokenExchangeContext)
|
||
tokenExchangeContext.SetManager(manager);
|
||
// EventPartnerTokenExchangeContextRegistry.Context = context;
|
||
}
|
||
|
||
// 结算
|
||
public void OnSettle()
|
||
{
|
||
Trace($"OnSettle eventId={EventId}");
|
||
FinishMining();
|
||
}
|
||
|
||
// 一轮完成的时候调用
|
||
public void UpdateSpinData()
|
||
{
|
||
if (BonusExpireDuration != 0 && BonusPercent > 0)
|
||
{
|
||
ApplyBonus(BonusPercent, BonusExpireDuration);
|
||
}
|
||
BonusPercent = 0;
|
||
BonusExpireDuration = 0;
|
||
}
|
||
|
||
#region 自动匹配相关方法
|
||
|
||
public async Task<AutoMatchStatusResponse> FetchAndProcessAutoMatchStatus(bool force = true)
|
||
{
|
||
var response = await GetAutoMatchStatusResponseAsync(force);
|
||
if (response?.State == EEventBuildState.Success)
|
||
ProcessAutoMatchStatusSuccess(response);
|
||
return response;
|
||
}
|
||
|
||
private void ProcessAutoMatchStatusSuccess(AutoMatchStatusResponse response)
|
||
{
|
||
if (response?.Partners is { Count: > 0 } && !ShouldCloseAutoMatch)
|
||
{
|
||
for (var i = 0; i < response.Partners.Count; ++i)
|
||
{
|
||
if (i >= AutoMatchSlotCount)
|
||
break;
|
||
TryAddAutoMatchedPartner(i, response.Partners[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
public bool TryAddAutoMatchedPartner(int slotIndex, PlayerInfo partner)
|
||
{
|
||
if (partner == null || slotIndex < 0 || slotIndex >= PartnerInfoManager.BuildPartners.Length)
|
||
return false;
|
||
if (partner.PlayFabId.EndsWith(BuildPartner.RobotIdentifier))
|
||
return false;
|
||
|
||
var buildPartner = PartnerInfoManager.BuildPartners[slotIndex];
|
||
if (buildPartner != null && buildPartner.IsValid())
|
||
return false;
|
||
|
||
var builder = new BuildPartner
|
||
{
|
||
SlotId = slotIndex,
|
||
PartnerId = partner.PlayFabId,
|
||
AvatarUrl = partner.AvatarUrl,
|
||
DisplayName = partner.DisplayName,
|
||
Cache = PartnerInfoManager.Cache,
|
||
};
|
||
|
||
var ret = PartnerInfoManager.AddBuildPartner(builder);
|
||
if (ret)
|
||
{
|
||
GContext.Publish(new EventPartnerGatherAddPartner
|
||
{
|
||
SlotId = slotIndex,
|
||
});
|
||
}
|
||
|
||
#if AGG
|
||
if (ret)
|
||
{
|
||
using (var e = GEvent.GameEvent("event_partners_gather_invite"))
|
||
{
|
||
e.AddContent("teammate_id", partner.PlayFabId)
|
||
.AddContent("position_id", slotIndex)
|
||
.AddContent("inviter_id", "auto");
|
||
}
|
||
}
|
||
#endif
|
||
return ret;
|
||
}
|
||
|
||
/// <summary> 自动匹配 status 请求最短间隔(秒),仅对 force=false 生效 </summary>
|
||
private const int AutoMatchStatusMinIntervalSeconds = 3;
|
||
|
||
private readonly object _autoMatchStatusGate = new object();
|
||
private Task<AutoMatchStatusResponse> _autoMatchStatusInFlight;
|
||
private DateTime _lastAutoMatchStatusUtc = DateTime.MinValue;
|
||
private AutoMatchStatusResponse _cachedAutoMatchStatus;
|
||
|
||
// 设置自动匹配状态
|
||
public void SetAutoMatchEnabled(bool enabled)
|
||
{
|
||
GatherData.IsEnableAutoMatch = enabled;
|
||
SaveData();
|
||
}
|
||
|
||
public async Task<AutoMatchToggleResponse> ControlAutoMatch(bool enable)
|
||
{
|
||
return await EventPartnerService.ControlAutoMatch(EventId, enable);
|
||
}
|
||
|
||
public void NotifyAutoMatchStopped()
|
||
{
|
||
GContext.Publish(new EventForAutoMatchChangeStage
|
||
{
|
||
State = AutoMatchState.AutoMatchOff
|
||
});
|
||
}
|
||
|
||
public void NotifyAutoMatchFailed(string reason)
|
||
{
|
||
GContext.Publish(new EventAutoMatchFailed { Reason = reason });
|
||
}
|
||
|
||
// 检查是否可以开启自动匹配
|
||
public bool CanStopAutoMatch(out int leftTimes)
|
||
{
|
||
leftTimes = -1;
|
||
// 检查是否已满员
|
||
if (PartnerInfoManager.IsFullyMatched)
|
||
return false;
|
||
|
||
// 检查冷却时间
|
||
var config = _tables.TbEventPartnerConfig;
|
||
var cooldownSeconds = config.AutoMatchCD;
|
||
var elapsed = (DateTime.UtcNow - GatherData.LastAutoMatchTime).TotalSeconds;
|
||
leftTimes = (int)Math.Floor(cooldownSeconds - elapsed);
|
||
leftTimes = leftTimes > 0 ? leftTimes : 0;
|
||
Trace($"CanStopAutoMatch eventId={EventId} elapsedSec={elapsed:F2} leftSec={leftTimes}");
|
||
return elapsed >= cooldownSeconds;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 拉取自动匹配完整状态(合并并发请求、可选短节流)。业务侧应优先通过本方法访问,勿直接调 EventPartnerService.GetAutoMatchResult。
|
||
/// </summary>
|
||
/// <param name="force">true:忽略短节流(轮询、关键操作后刷新等仍会与进行中的请求合并为一次 HTTP)</param>
|
||
public async Task<AutoMatchStatusResponse> GetAutoMatchStatusResponseAsync(bool force = false)
|
||
{
|
||
if (GatherData == null || EventId < 0)
|
||
{
|
||
return new AutoMatchStatusResponse
|
||
{
|
||
State = EEventBuildState.Failed,
|
||
Message = "No active gather data or event",
|
||
IsInMatching = false
|
||
};
|
||
}
|
||
|
||
if (!force && _cachedAutoMatchStatus != null)
|
||
{
|
||
var elapsed = (DateTime.UtcNow - _lastAutoMatchStatusUtc).TotalSeconds;
|
||
if (elapsed < AutoMatchStatusMinIntervalSeconds)
|
||
return _cachedAutoMatchStatus;
|
||
}
|
||
|
||
Task<AutoMatchStatusResponse> taskToAwait;
|
||
lock (_autoMatchStatusGate)
|
||
{
|
||
if (_autoMatchStatusInFlight != null)
|
||
taskToAwait = _autoMatchStatusInFlight;
|
||
else
|
||
taskToAwait = _autoMatchStatusInFlight = FetchAutoMatchStatusFromServerAsync();
|
||
}
|
||
|
||
try
|
||
{
|
||
return await taskToAwait;
|
||
}
|
||
finally
|
||
{
|
||
lock (_autoMatchStatusGate)
|
||
{
|
||
if (ReferenceEquals(_autoMatchStatusInFlight, taskToAwait))
|
||
_autoMatchStatusInFlight = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
private async Task<AutoMatchStatusResponse> FetchAutoMatchStatusFromServerAsync()
|
||
{
|
||
try
|
||
{
|
||
var response = await EventPartnerService.GetAutoMatchResult(EventId);
|
||
lock (_autoMatchStatusGate)
|
||
{
|
||
_cachedAutoMatchStatus = response;
|
||
_lastAutoMatchStatusUtc = DateTime.UtcNow;
|
||
}
|
||
|
||
return response;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
LogError($"AutoMatchFetchStatusFailed eventId={EventId} error={e.Message}");
|
||
return new AutoMatchStatusResponse
|
||
{
|
||
State = EEventBuildState.Failed,
|
||
Message = e.Message,
|
||
IsInMatching = false
|
||
};
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Token Exchange
|
||
|
||
public int GetTicketItemId()
|
||
{
|
||
return EventPartnerMineMainData?.ItemID ?? 0;
|
||
}
|
||
|
||
public int GetTokenExchangeId()
|
||
{
|
||
return EventPartnerMineMainData?.TokenExchangeId ?? 0;
|
||
}
|
||
|
||
public int GetTokenExchangeItemId()
|
||
{
|
||
var tokenExchangeId = GetTokenExchangeId();
|
||
return _tables.TbEventPartnerTokenExchange[tokenExchangeId].TokenItem;
|
||
}
|
||
#endregion
|
||
|
||
|
||
}
|
||
}
|