using cfg; using asap.core; using GameCore; using SystemRandom = System.Random; using UnityEngine; using System.Linq; using System.Collections.Generic; using UnityEngine.Assertions; using System; using Castle.Core.Internal; public class EventBreakTableContext { #region Private Table References private readonly EventDrillMain _tableMain; private readonly EventDrillTunnel[] _tableTunnels; private readonly TbEventDrillReward _tableTask; private readonly FishingEvent _tableEvent; private readonly FishingEventCycleItem2 _tableCycle; private readonly Tables _tables = GContext.container.Resolve(); #endregion public int TunnelCount => _tableTunnels.Length; private readonly PlayerItemData _playerItemData = GContext.container.Resolve(); public SystemRandom Random; public readonly int BlockCountPerTunnel = 8; private EventBreakTableContext(EventDrillMain tableMain, EventDrillTunnel[] tableTunnels, TbEventDrillReward tableTask, FishingEvent tableEvent, FishingEventCycleItem2 tableCycle, Tables tables) { _tableMain = tableMain; _tableTunnels = tableTunnels; _tableTask = tableTask; _tableEvent = tableEvent; _tableCycle = tableCycle; _tables = tables; } public static EventBreakTableContext ReadTables(int eventId, Tables tables) { int redirectId, cycleId; cycleId = tables.TbFishingEvent[eventId].RedirectID; redirectId = tables.TbFishingEventCycleItem2[cycleId].RedirectID; var tableEvent = tables.TbFishingEvent[eventId]; var tableCycle = tables.TbFishingEventCycleItem2[cycleId]; var tableMain = tables.TbEventDrillMain[redirectId]; var tableTunnels = tables.TbEventDrillTunnel.DataList.Where(t => tableMain.TunnelList.Contains(t.Tunnel)).ToArray(); var tableTask = tables.TbEventDrillReward; return new EventBreakTableContext(tableMain, tableTunnels, tableTask, tableEvent, tableCycle, tables); } #region TaskInfoProcess public EventBreakTaskInfo GetTaskInfo(int taskId, int tunnelIdx, int gemProgress = 0) { if (!_tableTask.DataMap.TryGetValue(taskId, out var taskTableData)) { Debug.Log($"[EventBreak]Task id {taskId} not found in table."); return null; } int targetItemId = GetItemIdFromDrop(_tableTunnels[tunnelIdx].DropGem); if (targetItemId == -1) { return null; } // var taskReward = GetBlockDataFromDropId(_tableTask[taskId].DropGem); var taskReward = _playerItemData.GetItemDataByDropId(_tableTask[taskId].DropGem)[0]; return new EventBreakTaskInfo { TaskId = taskTableData.TaskID, TargetItemId = targetItemId, Reward = taskReward, TotalGemRequired = _tableTask[taskId].TokenRequired, CurrentGemProgress = gemProgress }; } public EventBreakTaskInfo GetNextTaskInfo(EventBreakTaskInfo taskInfo) { Assert.IsTrue(taskInfo.CurrentGemProgress >= taskInfo.TotalGemRequired, "[EventBreak]Current gem progress is less than total gem required."); var dataFlag = _tables.TbEventDrillReward.DataMap.TryGetValue(taskInfo.TaskId, out var taskTableData); if (!dataFlag) { Debug.Log($"[Drill]Task id {taskInfo.TaskId} not found in reward table."); return null; } var nextTaskId = taskTableData.NextTarget; dataFlag = _tables.TbEventDrillReward.DataMap.TryGetValue(nextTaskId, out var nextTaskTableData); if (!dataFlag) { Debug.Log($"[Drill]Next task id {nextTaskId} not found in reward table, end of mission chain."); return null; } // var taskReward = GetBlockDataFromDropId(nextTaskTableData.DropGem); var taskReward = _playerItemData.GetItemDataByDropId(nextTaskTableData.DropGem)[0]; return new EventBreakTaskInfo { TaskId = nextTaskId, TargetItemId = taskInfo.TargetItemId, Reward = taskReward, TotalGemRequired = nextTaskTableData.TokenRequired, CurrentGemProgress = taskInfo.CurrentGemProgress - taskInfo.TotalGemRequired }; } #endregion public void GetFreshNewModelData(int[] jobSeeds, out int welcomeGift, out DrillJobModel[] drillJobs, out EventBreakTaskInfo[] taskInfoList) { welcomeGift = _tableCycle.WelcomeGift; drillJobs = new DrillJobModel[TunnelCount]; taskInfoList = new EventBreakTaskInfo[TunnelCount]; var defaultTaskIds = _tableTunnels.Select(t => t.TaskList).ToArray(); for (int i = 0; i < TunnelCount; i++) { drillJobs[i] = GetDrillJob(i, jobSeeds[i]); taskInfoList[i] = GetTaskInfo(_tableTunnels[i].TaskList, i); } } public int GetEntranceRedDotTicketThreshold() { return _tableCycle.RedDot; } public DrillJobModel[] GetDrillJobModels(int[] seeds) { var res = new DrillJobModel[seeds.Length]; for (int i = 0; i < seeds.Length; i++) res[i] = GetDrillJob(i, seeds[i]); return res; } public EventBreakTaskInfo[] GetTaskInfoArray((int id, int progress)[] taskData) { var res = new EventBreakTaskInfo[taskData.Length]; for (int i = 0; i < taskData.Length; i++) { // Debug.Log($"[EventBreak]Task init: id {taskData[i].id}, progress {taskData[i].progress}"); res[i] = GetTaskInfo(taskData[i].id, i, taskData[i].progress); } return res; } /// /// Get DrillJob. Before calling this, do save the seed if necessarry. /// /// In which tunnel /// By what rng seed. If seed is less than table threshold, fallback into initial fixed drops. /// The drill job public DrillJobModel GetDrillJob(int idx, int seed) { var tunnelData = _tableTunnels[idx]; var res = new DrillJobModel { Cost = tunnelData.ItemRequired, }; var rewardBlockDatas = new List(); var blockDatas = new List(); for (int i = 0; i < BlockCountPerTunnel; i++) blockDatas.Add(DrillBlockData.CreateEmpty()); SystemRandom rng; var gemId = GetItemIdFromDrop(tunnelData.DropGem); if (IsSeedFixed(idx, seed)) { rng = new SystemRandom(seed + idx); var dropId = tunnelData.FixDropId[seed]; var items = _playerItemData.GetItemDataByDropId(dropId); foreach (var item in items) { if (item.id == gemId) { int n = (int)item.count; while (n > 0) { rewardBlockDatas.Add(new DrillBlockData { Item = new ItemData(item.id, 1) }); n--; } } else rewardBlockDatas.Add(new DrillBlockData { Item = item }); } } else { rng = new SystemRandom(seed); Assert.IsTrue(idx >= 0 && idx < _tableTunnels.Length, $"Tunnel Index {idx} not within range [0, {_tableTunnels.Length - 1}]."); var dropIds = GetTunnelDropIds(_tableTunnels[idx], rng); Assert.IsTrue(dropIds.Count <= BlockCountPerTunnel, "[EventBreak]Reward count is greater than block count"); foreach (var dropId in dropIds) rewardBlockDatas.AddRange(GetBlockDataFromDropId(dropId, rng, gemId)); } var itemCount = rewardBlockDatas.Count; // int i = itemCount; // while (i < BlockCountPerTunnel) // { // blockDatas.Add(DrillBlockData.CreateEmpty()); // i++; // } rewardBlockDatas = rewardBlockDatas.OrderBy(x => rng.Next()).ToList(); if (rewardBlockDatas.IsNullOrEmpty()) { Debug.LogError($"[EventBreak] No reward found in tunnel {idx}"); res.Blocks = blockDatas.ToArray(); return res; } var indicesToPick = Enumerable.Range(0, BlockCountPerTunnel).ToList(); int idxPicked = rng.Next(0, BlockCountPerTunnel); blockDatas[idxPicked] = rewardBlockDatas[0]; indicesToPick.Remove(idxPicked); indicesToPick.Remove(idxPicked + 1); indicesToPick.Remove(idxPicked - 1); for (int i = 1; i < rewardBlockDatas.Count; i++) { idxPicked = indicesToPick[rng.Next(0, indicesToPick.Count)]; blockDatas[idxPicked] = rewardBlockDatas[i]; indicesToPick.Remove(idxPicked); } res.Blocks = blockDatas.ToArray(); return res; } public bool IsSeedFixed(int idx, int seed) { return seed >= 0 && seed < _tableTunnels[idx].FixDropId.Count; } public bool DoesSeedNeedInc(int idx, int seed) { return seed >= 0 && seed < _tableTunnels[idx].FixDropId.Count - 1; } private List GetInitTunnelDropIds(EventDrillTunnel tunnel, int fixedDropIdx) { if (fixedDropIdx < 0 || fixedDropIdx >= tunnel.FixDropId.Count) { return null; } return _playerItemData.GetItemDataByDropId(tunnel.FixDropId[fixedDropIdx]); } /// /// Get the drop ids for the tunnel. First drop is the the gem of the tunnel. /// /// tunnel data from table /// The dropIds for the tunnel. private List GetTunnelDropIds(EventDrillTunnel tunnel, SystemRandom rng) { var dropIds = new List(); dropIds.Add(tunnel.DropGem); var count = tunnel.DropCountList[FtMathUtils.GetRandomIdxFromWeightList(tunnel.DropWeightList, rng)]; while (count > 0) { dropIds.Add(tunnel.DropItemId); count--; } return dropIds; } /// /// Assuming that Random state is set before calling. Will seperate gem. /// /// The drop id that represents a weighted random item. /// The actual item id and count. private DrillBlockData[] GetBlockDataFromDropId(int dropId, SystemRandom rng, int gemId) { ItemData item; var res = new List(); if (!_tables.TbDrop.DataMap.TryGetValue(dropId, out var drop)) { Debug.Log($"[EventBreak]Drop id {dropId} not found."); return res.ToArray(); } if (drop.Type != DropType.Weight) { Debug.Log($"[EventBreak]Unsupported drop type {drop.Type} from drop Id {dropId}."); return res.ToArray(); } if (rng == null) { Debug.Log($"[EventBreak]Need random number generator for this drop type."); return res.ToArray(); } try { var idx = FtMathUtils.GetRandomIdxFromWeightList(drop.DropList.DropProbList, rng); item = new ItemData(drop.DropList.DropIDList[idx], drop.DropList.DropCountList[idx]); } catch (Exception e) { Debug.LogError($"[EventBreak]Invalid drop id {drop}: {e.Message}\n{e.StackTrace}"); return res.ToArray(); } _playerItemData.ItemTransition(item); if (item.id == gemId) for (int i = 0; i < (int)item.count; i++) res.Add(new DrillBlockData { Item = new ItemData(id: gemId, count: 1) }); else res.Add(new DrillBlockData { Item = item }); return res.ToArray(); } private int GetItemIdFromDrop(int dropId) { if (!_tables.TbDrop.DataMap.TryGetValue(dropId, out var drop)) { Debug.Log($"[EventBreak]Drop id {dropId} not found."); return -1; } return drop.DropList.DropIDList[0]; } public EventBreakEntranceData GetEntranceButtonData() { var res = new EventBreakEntranceData(); res.BtnIconUrl = _tableMain.Icon; res.RedPointTicketThreshold = _tableCycle.RedDot; var et = new DateTime(); var st = new DateTime(); try { et = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime); st = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).StartTime); } catch (Exception e) { Debug.Log($"[EventBreak] {e.Message}\n{e.StackTrace}"); return null; } finally { res.ExpiryTime = et; res.StartTime = st; } return res; } public EventBreakUIData GetUIData() { return new EventBreakUIData { MainPanelUrl = _tableMain.UIPanel, InfoPanelUrl = _tableMain.InfoPanel, ChainPackPanelUrl = _tableMain.ChainPackPanel, NormalPackPanelUrl = _tableMain.PackPanel, RewardPanelUrl = _tableMain.RewardPanel }; } public EventChainPackInfo GetPackData() { var chianList = _tables.TbEventPackManager[_tableMain.PackId].VIPPackList[0]; var expireTime = new DateTime(); try { expireTime = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime); } catch (Exception e) { Debug.Log($"[EventBreak] {e.Message}\n{e.StackTrace}"); return null; } var chainListIdSet = chianList.ToHashSet(); var packs = _tables.TbPack.DataList.Where(p => chainListIdSet.Contains(p.ID)).ToArray();//? return new EventChainPackInfo() { ChainList = chianList, ExpireTime = expireTime, Packs = packs, RedPointKey = "eventbreak.pack" }; } public bool[] IsTicketEnough(int ticketCount) { return _tableTunnels.Select(t => ticketCount >= t.ItemRequired).ToArray(); } public bool IsItemGem(ItemData item) { return _tableTunnels.Any(t => GetItemIdFromDrop(t.DropGem) == item.id); } public int GetGemIdx(int gemId) { int idx = 0; while (idx < _tableTunnels.Length) { if (GetItemIdFromDrop(_tableTunnels[idx].DropGem) == gemId) return idx; idx++; } return idx; } public EventBreakNormalPackInfo GetNormalPackInfo() { var expireTime = new DateTime(); try { expireTime = DateTime.Parse((_tableEvent.TimeDefinition as LimitedTime).EndTime); } catch (Exception e) { Debug.Log($"[EventBreak] {e.Message}\n{e.StackTrace}"); return null; } var packList = _tables.TbEventPackManager[_tableMain.PackId2].VIPPackList[0]; return new EventBreakNormalPackInfo { EventId = _tableEvent.ID, PackLeft = _tables.TbPack[packList[0]], PackRight = _tables.TbPack[packList[1]], ExpireTime = expireTime, }; } public bool IsItemFishCard(ItemData item) { return _tables.TbItem[item.id].Type == 5; } }