Files
back_cantanBuilding/Assets/Scripts/EventBreak/EventBreakTableContext.cs
2026-05-26 16:15:54 +08:00

420 lines
15 KiB
C#

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<Tables>();
#endregion
public int TunnelCount => _tableTunnels.Length;
private readonly PlayerItemData _playerItemData = GContext.container.Resolve<PlayerItemData>();
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;
}
/// <summary>
/// Get DrillJob. Before calling this, do save the seed if necessarry.
/// </summary>
/// <param name="idx">In which tunnel</param>
/// <param name="seed">By what rng seed. If seed is less than table threshold, fallback into initial fixed drops.</param>
/// <returns>The drill job</returns>
public DrillJobModel GetDrillJob(int idx, int seed)
{
var tunnelData = _tableTunnels[idx];
var res = new DrillJobModel
{
Cost = tunnelData.ItemRequired,
};
var rewardBlockDatas = new List<DrillBlockData>();
var blockDatas = new List<DrillBlockData>();
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<ItemData> GetInitTunnelDropIds(EventDrillTunnel tunnel, int fixedDropIdx)
{
if (fixedDropIdx < 0 || fixedDropIdx >= tunnel.FixDropId.Count)
{
return null;
}
return _playerItemData.GetItemDataByDropId(tunnel.FixDropId[fixedDropIdx]);
}
/// <summary>
/// Get the drop ids for the tunnel. First drop is the the gem of the tunnel.
/// </summary>
/// <param name="tunnel">tunnel data from table</param>
/// <returns>The dropIds for the tunnel.</returns>
private List<int> GetTunnelDropIds(EventDrillTunnel tunnel, SystemRandom rng)
{
var dropIds = new List<int>();
dropIds.Add(tunnel.DropGem);
var count = tunnel.DropCountList[FtMathUtils.GetRandomIdxFromWeightList(tunnel.DropWeightList, rng)];
while (count > 0)
{
dropIds.Add(tunnel.DropItemId);
count--;
}
return dropIds;
}
/// <summary>
/// Assuming that Random state is set before calling. Will seperate gem.
/// </summary>
/// <param name="dropId">The drop id that represents a weighted random item.</param>
/// <returns>The actual item id and count.</returns>
private DrillBlockData[] GetBlockDataFromDropId(int dropId, SystemRandom rng, int gemId)
{
ItemData item;
var res = new List<DrillBlockData>();
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;
}
}