yuanshen/Yuanshen.Gameserver/Game/GachaBannerTable.cs
wisedev 61cc2055cf First working version of the server
KCP gameserver with packet dispatch, scene streaming, combat, gacha and the
shop, plus a small HTTP server for the login flow and the wish history page.

Game data under assets is pulled out of the client instead of being typed by
hand. The excel tables come from the packed bin container and the spawn points
from the compiled scene scripts.
2026-09-04 02:06:53 +03:00

125 lines
5.1 KiB
C#

using System.Text.Json;
using Yuanshen.Protocol;
namespace Yuanshen.Gameserver.Game;
internal sealed record GachaBucket(string Type, uint Weight, IReadOnlyList<uint> ItemIds);
internal sealed class GachaBanner
{
public required string Id { get; init; }
public required GachaInfo Info { get; init; }
public required IReadOnlyList<GachaBucket> Buckets { get; init; }
public uint PityCount { get; init; }
public IReadOnlyList<string> PityTypes { get; init; } = Array.Empty<string>();
public uint FeaturedRate { get; init; }
public IReadOnlyList<string> GuaranteeTypes { get; init; } = Array.Empty<string>();
public IReadOnlyDictionary<string, IReadOnlyList<uint>> FeaturedPools { get; init; }
= new Dictionary<string, IReadOnlyList<uint>>();
}
internal sealed class GachaBannerTable
{
public IReadOnlyList<GachaBanner> 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<GachaBanner> Load(string fileName)
{
List<GachaBanner> 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<GachaBucket> buckets = new();
foreach (JsonElement bucket in entry.GetProperty("buckets").EnumerateArray())
{
List<uint> 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<string> 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<string> guaranteeTypes = new();
Dictionary<string, IReadOnlyList<uint>> 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<uint> 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()
};
}