using System.Text.Json; using Yuanshen.Protocol; namespace Yuanshen.Gameserver.Game; internal sealed record GachaBucket(string Type, uint Weight, IReadOnlyList ItemIds); internal sealed class GachaBanner { public required string Id { get; init; } public required GachaInfo Info { get; init; } public required IReadOnlyList Buckets { get; init; } public uint PityCount { get; init; } public IReadOnlyList PityTypes { get; init; } = Array.Empty(); public uint FeaturedRate { get; init; } public IReadOnlyList GuaranteeTypes { get; init; } = Array.Empty(); public IReadOnlyDictionary> FeaturedPools { get; init; } = new Dictionary>(); } internal sealed class GachaBannerTable { public IReadOnlyList Banners { get; } public GachaBannerTable() { Banners = Load("banners.json"); } public GachaBanner? Find(uint gachaType, uint scheduleId) => Banners.FirstOrDefault(banner => banner.Info.GachaType == gachaType && banner.Info.ScheduleId == scheduleId) ?? Banners.FirstOrDefault(banner => banner.Info.GachaType == gachaType); private static List Load(string fileName) { List banners = new(); string path = Path.Combine(AppContext.BaseDirectory, "assets", "gacha", fileName); if (!File.Exists(path)) return banners; using JsonDocument document = JsonDocument.Parse(File.ReadAllText(path)); foreach (JsonElement entry in document.RootElement.EnumerateArray()) { if (!entry.GetProperty("ship").GetBoolean()) continue; JsonElement info = entry.GetProperty("gachaInfo"); List buckets = new(); foreach (JsonElement bucket in entry.GetProperty("buckets").EnumerateArray()) { List ids = new(); foreach (JsonElement id in bucket.GetProperty("itemIds").EnumerateArray()) ids.Add(id.GetUInt32()); buckets.Add(new GachaBucket(bucket.GetProperty("type").GetString()!, bucket.GetProperty("weight").GetUInt32(), ids)); } uint pityCount = 0; List pityTypes = new(); if (entry.TryGetProperty("pity", out JsonElement pity)) { pityCount = pity.GetProperty("count").GetUInt32(); foreach (JsonElement type in pity.GetProperty("types").EnumerateArray()) pityTypes.Add(type.GetString()!); } uint featuredRate = 0; List guaranteeTypes = new(); Dictionary> featuredPools = new(); if (entry.TryGetProperty("featured", out JsonElement featured)) { featuredRate = featured.GetProperty("rate").GetUInt32(); foreach (JsonElement type in featured.GetProperty("guaranteeTypes").EnumerateArray()) guaranteeTypes.Add(type.GetString()!); foreach (JsonProperty poolEntry in featured.GetProperty("pools").EnumerateObject()) { List ids = new(); foreach (JsonElement id in poolEntry.Value.EnumerateArray()) ids.Add(id.GetUInt32()); if (ids.Count != 0) featuredPools[poolEntry.Name] = ids; } } banners.Add(new GachaBanner { Id = entry.GetProperty("id").GetString()!, Info = BuildInfo(info), Buckets = buckets, PityCount = pityCount, PityTypes = pityTypes, FeaturedRate = featuredRate, GuaranteeTypes = guaranteeTypes, FeaturedPools = featuredPools }); } return banners; } private static GachaInfo BuildInfo(JsonElement info) => new() { GachaType = info.GetProperty("gachaType").GetUInt32(), ScheduleId = info.GetProperty("scheduleId").GetUInt32(), BeginTime = info.GetProperty("beginTime").GetUInt32(), EndTime = info.GetProperty("endTime").GetUInt32(), CostItemId = info.GetProperty("costItemId").GetUInt32(), CostItemNum = info.GetProperty("costItemNum").GetUInt32(), GachaPrefabPath = info.GetProperty("gachaPrefabPath").GetString(), GachaProbUrl = info.GetProperty("gachaProbUrl").GetString(), GachaRecordUrl = info.GetProperty("gachaRecordUrl").GetString(), GachaPreviewPrefabPath = info.GetProperty("gachaPreviewPrefabPath").GetString(), TenCostItemId = info.GetProperty("tenCostItemId").GetUInt32(), TenCostItemNum = info.GetProperty("tenCostItemNum").GetUInt32(), LeftGachaTimes = info.GetProperty("leftGachaTimes").GetUInt32(), GachaTimesLimit = info.GetProperty("gachaTimesLimit").GetUInt32(), GachaSortId = info.GetProperty("gachaSortId").GetUInt32() }; }