using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using asap.core; using cfg; using game; using GameCore; using Newtonsoft.Json; using UnityEngine; namespace DataCenter { // 锁链礼包 public class TOfferChainsData { public class TItem { public int Id; public int Item; public int Number; // 0 可选,1 高亮 2 糊了 ,锁链隐藏 应该转换成Enum public int Status; // public int SKUId; } public bool FirstOpen; // 是否首次打开 public int EventId; // 默认存一下ID public DateTime StartTime; // 开始时间 public DateTime EndTime;// 结束时间 public int ItemId = -1; // 当前抽奖次数,必须抽了才会更新 public int LotteryNum; public List Items; public bool Finished; public int ChestReward; public List RewardList; // 当前获得的奖励Item } public class OfferChainsChestManager { public const string SaveKey = "OfferChainsChestData"; [Inject] public Tables _tables { get; set; } // 计入当前Event private FishingEvent _fishingEvent; // public EventOfferChainsChestMain OfferChainsChestMain { get; set; } public List OfferChainsChestRewards { get; set; } // 当前可保存数据 public TOfferChainsData OfferChainsData { get; private set; } public List ValidIds; public bool IsFirstOpen { get => OfferChainsData.FirstOpen; set { if (OfferChainsData.FirstOpen) { OfferChainsData.FirstOpen = false; SaveData(); } } } public void UpdateEventData(FishingEvent fishingEvent) { ELog($"UpdateEventData - > {fishingEvent}"); _fishingEvent = fishingEvent; UpdateLocalData(); } private void UpdateLocalData() { //选择当前的 Main var redirectId = _fishingEvent.RedirectID; var configList = _tables.TbEventOfferChainsChestMain.DataList; foreach (var eventChallenge in configList.Where(eventChallenge => eventChallenge.ID == redirectId)) { OfferChainsChestMain = eventChallenge; break; } OfferChainsChestRewards = _tables.TbEventOfferChainsChestRewards.DataList; // SkuIds = OfferChainsChestMain.IapList; } private bool _isInit = false; public void Init() { ELog("Init-> "); if (_fishingEvent == null) return; //- if (_fishingEvent.ID != OfferChainsData?.EventId) { ClearOfferChainsData(); } if (_isInit) return; if (OfferChainsData == null) { if (_fishingEvent == null) // 不存在Event { return; } InitOfferChainsData(); // CreateNewData(); } UpdateOfferChainsData(); //UpdateData() _isInit = true; ELog("初始化完成-> "); } // private void ProcessLastOne() { ELog("ProcessLastOne-> "); if (OfferChainsData != null) { Settle(); // if (!IsTimeAllow()) // { // Settle(); // // ClearOfferChainsData(); // } // // else if (IsCanGetFinalReward()) // else // { // Settle(); // 补充一下最终大奖 // } } } private void UpdateOfferChainsData() { ELog("UpdateOfferChainsData"); // 更新可用数据 UpdateTime(); UpdateOfferChainsItems(); UpdateValidIds(); GetLotteryItemId(); //- if (_fishingEvent != null && OfferChainsData != null) { GContext.container.Resolve().AddGiftFaceUI(_fishingEvent.ID, new UIType(OfferChainsChestMain.UIPanel), 0); } } private void UpdateValidIds() { var lotteryNum = OfferChainsData.LotteryNum; ValidIds = (from item in OfferChainsData?.Items where item.Status == 0 select item.Id).ToList(); } private void InitOfferChainsData() { var limitedTime = (LimitedTime)_fishingEvent.TimeDefinition; var startTime = GlobalUtils.TryParseDateTime(limitedTime.StartTime, ZZTimeHelper.UtcNow()); var endTime = GlobalUtils.TryParseDateTime(limitedTime.EndTime, ZZTimeHelper.UtcNow()); OfferChainsData = new TOfferChainsData { FirstOpen = true, EventId = _fishingEvent.ID, StartTime = startTime, EndTime = endTime, Items = new List(), RewardList = new List(), ChestReward = OfferChainsChestMain.ChestReward, // 最终大奖存储下,方便额外的处理 }; for (var i = 0; i < OfferChainsChestRewards.Count; ++i) { var item = new TOfferChainsData.TItem { Id = OfferChainsChestRewards[i].ID, Item = OfferChainsChestRewards[i].Item, Number = OfferChainsChestRewards[i].Number, Status = 0, // SKUId = OfferChainsChestMain.IapList[i], }; OfferChainsData.Items.Add(item); } } public bool IsTimeAllow() { var now = ZZTimeHelper.UtcNow(); var startTime = OfferChainsData.StartTime; var endTime = OfferChainsData.EndTime; #if UNITY_EDITOR var timeOpened = (now - startTime).TotalSeconds; var timeEnded = (endTime - now).TotalSeconds; ELog($"StartTime: {startTime} Now: {now} EndTime:{endTime} TimeOpened:{timeOpened} TimeToEnd:{timeEnded} Other: {1800000 - timeOpened} IsTimeAllow => {now <= endTime}"); #endif return now >= startTime && now <= endTime; } public void CheckInit() { ELog("CheckInit -> "); ProcessLastOne(); Init(); } // ReSharper disable Unity.PerformanceAnalysis private static void Log(object t) { Debug.Log($"OfferChainsChestManager -> {t} "); } private static void ELog(object t) { #if UNITY_EDITOR Debug.Log($"OfferChainsChestManager -> {t} "); #endif } public bool CheckOpen() { // if (OfferChainsData == null) return false; // if (!IsTimeAllow()) return false; if (OfferChainsChestMain == null) { return false; } if (IsFinished()) { return false; } return true; } public bool IsFinished() { return OfferChainsData?.Finished ?? false; } private void SaveData() { ELog($"SaveData-> {JsonConvert.SerializeObject(OfferChainsData)}"); PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(OfferChainsData)); } public void LoadData(string dataValue) { ELog($"LoadData -> {dataValue}"); OfferChainsData = JsonConvert.DeserializeObject(dataValue); } // 进入游戏舞台 public async void OnEnterGameAct() { Log("OnEnterGameAct()"); IsFirstOpen = false; await UIManager.Instance.ShowUI(new UIType(OfferChainsChestMain.UIPanel)); } public static T WeightedRandom(Dictionary 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; // 理论上不会执行到这里 } // 活动当前的抽奖索引 private int CalcLotteryItemId() { var lotteryNum = OfferChainsData.LotteryNum; if (ValidIds.Count <= 0) { return -1; } if (OfferChainsChestRewards == null) { return -1; } // // while (true) // { var dict = OfferChainsChestRewards.Where( item => ValidIds.Contains(item.ID) && item.LimitConfig <= lotteryNum) .ToDictionary(elem => (elem.ID, elem.LimitConfig), elem => elem.Weight); var (elemId, limitConfig) = WeightedRandom(dict); Log($"CalcLotteryItemId -> {lotteryNum} {elemId} {limitConfig}"); // if (limitConfig >0 && lotteryNum > limitConfig ) return elemId; // } } public int GetLotteryItemId() { ELog($"GetLotteryItemId -> {OfferChainsData.ItemId}"); if (OfferChainsData.ItemId == -1 || !ValidIds.Contains(OfferChainsData.ItemId)) { UpdateLotteryItemId(); } return OfferChainsData.ItemId; } private void UpdateOfferChainsItems() { if (OfferChainsData != null && _fishingEvent != null && OfferChainsData.EventId == _fishingEvent.ID) { var items = OfferChainsData.Items; if (OfferChainsChestRewards is { Count: > 0 }) { for (int i = 0; i < items.Count; ++i) { EventOfferChainsChestRewards reward = null; if (i < OfferChainsChestRewards.Count) { reward = OfferChainsChestRewards[i]; } if (reward != null) { items[i].Id = reward.ID; items[i].Item = reward.Item; items[i].Number = reward.Number; } } } if (OfferChainsChestMain != null) { OfferChainsData.ChestReward = OfferChainsChestMain.ChestReward; } } // for (var i = 0; i < OfferChainsChestRewards.Count; ++i) // { // var item = new TOfferChainsData.TItem // { // Id = OfferChainsChestRewards[i].ID, // Item = OfferChainsChestRewards[i].Item, // Number = OfferChainsChestRewards[i].Number, // Status = 0, // }; // OfferChainsData.Items.Add(item); // } } private void UpdateTime() { if (OfferChainsData != null && _fishingEvent != null && OfferChainsData.EventId == _fishingEvent.ID) { var limitedTime = (LimitedTime)_fishingEvent.TimeDefinition; var startTime = GlobalUtils.TryParseDateTime(limitedTime.StartTime, ZZTimeHelper.UtcNow()); var endTime = GlobalUtils.TryParseDateTime(limitedTime.EndTime, ZZTimeHelper.UtcNow().AddDays(-1)); OfferChainsData.StartTime = startTime; OfferChainsData.EndTime = endTime; } } private void UpdateLotteryItemId() { var targetId = CalcLotteryItemId(); ELog($"UpdateLotteryItemId -> {OfferChainsData.ItemId} => {targetId}"); OfferChainsData.ItemId = targetId; SaveData(); } //- 结束当前 public void FinishLottery(int targetId) { Log($"FinishLottery -> {targetId}"); var lastItem = OfferChainsData.Items.SingleOrDefault(it => it.Id == targetId); if (lastItem is { Status: not 2 }) { lastItem.Status = 2; } } //- 开始下一轮数据 public void UpdateForNextLottery() { UpdateValidIds(); UpdateLotteryItemId(); } public bool IsCanGetFinalReward() { var ret = OfferChainsData.LotteryNum >= OfferChainsData.Items.Count && !OfferChainsData.Finished; ELog($"IsCanGetFinalReward {ret} : {OfferChainsData.LotteryNum} {OfferChainsData.Items.Count} {OfferChainsData.Finished}"); return ret; } public void ClearOfferChainsData() { OfferChainsData = null; _isInit = false; SaveData(); } public TOfferChainsData.TItem GetTItemById(int targetId) { var lastItem = OfferChainsData.Items.FirstOrDefault(it => it.Id == targetId); return lastItem; } public int GetDropIdById(int id) { var item = GetTItemById(id); var itemData = _tables.TbItem.GetOrDefault(item.Item); return itemData.RedirectID; } public void OnGetFinalReward() { ELog("OnGetFinalReward()-> "); // var item = _tables.TbItem.GetOrDefault(OfferChainsChestMain.ChestReward); var item = _tables.TbItem.GetOrDefault(OfferChainsData.ChestReward); var itemFinal = GContext.container.Resolve() .GetItemDropItemList(item.RedirectID, 1); GContext.container.Resolve().LureInflation(itemFinal, null); GContext.container.Resolve().AddItem(itemFinal, null); GContext.Publish(new ShowData(itemFinal)); GContext.Publish(new ShowData()); OfferChainsData.Finished = true; SaveData(); GContext.Publish(new OfferChainsRefreshEvent()); } public float GetProbability(int id) { var theIdWeight = OfferChainsChestRewards.FirstOrDefault(item => item.ID == id)?.Weight ?? 0; var weightTable = OfferChainsChestRewards .Where(item => !IsItemFinished(item.ID)) .Select(item => item.Weight).ToList(); var totalWeight = weightTable.Sum(); return (float)Math.Round((float)theIdWeight / totalWeight * 100, 2); } private bool IsItemFinished(int itemID) { var lastItem = OfferChainsData.Items.SingleOrDefault(it => it.Id == itemID); return lastItem?.Status == 2; } public TimeSpan GetTimeRemain() { if (OfferChainsData != null) { return OfferChainsData.EndTime - ZZTimeHelper.UtcNow(); } // 活动未开始 return ZZTimeHelper.UtcNow().AddDays(-1) - ZZTimeHelper.UtcNow(); } public void Settle() { ELog("Settle"); if (IsCanGetFinalReward()) { OnGetFinalReward(); } } public bool UIRunning { get; set; } = false; public void OnBuySuccess() { Log("OnBuySuccess -> "); OfferChainsData.RewardList.Add(OfferChainsData.ItemId); OfferChainsData.LotteryNum += 1; // 为了处理打点 if (IsCanGetFinalReward()) { OfferChainsData.RewardList.Add(OfferChainsData.ChestReward); } FinishLottery(OfferChainsData.ItemId); SaveData(); // -存 EventTracking(); //NEXT TURN if (UIRunning) { // 播放动画逻辑,交给UI return; } UpdateForNextLottery(); Settle(); } public void EventTracking() { //var price = GetPayAmountById(OfferChainsData.ItemId); var price = GetIapItemListThisTime(OfferChainsData.LotteryNum - 1)?.PaymentAmount ?? 0F; var itemEnt = GetTItemById(OfferChainsData.ItemId); var rewardStr = string.Join(',', OfferChainsData.RewardList); var number = OfferChainsData.LotteryNum; #if AGG using (var e = GEvent.TackEvent("offer_chainchest")) { e.AddContent("event_id", OfferChainsData.EventId); e.AddContent("number", number); e.AddContent("price", price); e.AddContent("reward", OfferChainsData.ItemId); e.AddContent("reward_claimed_list", rewardStr); } #endif Log($"EventTracking: event_id: {OfferChainsData.EventId} number: {number} price: {price} " + $"reward :{OfferChainsData.ItemId} reward_claimed_list :{rewardStr}"); } public IAPItemList GetIapItemListThisTime() { return GetIapItemListThisTime(OfferChainsData.LotteryNum); } private IAPItemList GetIapItemListThisTime(int index) { // var index = OfferChainsData.LotteryNum; index = Mathf.Clamp(index, 0, OfferChainsChestMain.IapList.Count - 1); var iapId = OfferChainsChestMain.IapList[index]; var iAPItemList = _tables.TbIAPItemList.GetOrDefault(iapId); return iAPItemList; } } }