VanguardReMaster/server/src/Vanguard.Content/TrialDeckCatalog.cs

98 lines
3.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace Vanguard.Content;
public sealed record TrialDeckCard(string PrintingId, int Count);
public sealed record TrialDeckDefinition(
string Id,
string Name,
string? Clan,
IReadOnlyList<TrialDeckCard> Cards)
{
public int TotalCards => Cards.Sum(card => card.Count);
/// <summary>Разворачивает counts в список printingId длиной 50.</summary>
public IReadOnlyList<string> ToDeck() =>
Cards.SelectMany(card => Enumerable.Repeat(card.PrintingId, card.Count)).ToList();
}
/// <summary>Две триал-деки из content/trial-decks.yaml.</summary>
public sealed class TrialDeckCatalog
{
private readonly Dictionary<string, TrialDeckDefinition> _decks;
private TrialDeckCatalog(IEnumerable<TrialDeckDefinition> decks)
{
_decks = decks.ToDictionary(deck => deck.Id, StringComparer.OrdinalIgnoreCase);
}
public IReadOnlyList<TrialDeckDefinition> Decks => _decks.Values.ToList();
public bool TryGet(string id, out TrialDeckDefinition deck) =>
_decks.TryGetValue(id, out deck!);
public static TrialDeckCatalog Load(string path)
{
if (!File.Exists(path))
throw new FileNotFoundException($"Файл триал-дек не найден: {path}");
var deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.IgnoreUnmatchedProperties()
.Build();
var file = deserializer.Deserialize<TrialDeckFile>(File.ReadAllText(path))
?? throw new InvalidOperationException($"Пустой файл триал-дек: {path}");
if (file.Decks.Count == 0)
throw new InvalidOperationException("В trial-decks.yaml нет дек.");
var decks = new List<TrialDeckDefinition>();
var ids = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in file.Decks)
{
if (string.IsNullOrWhiteSpace(entry.Id) || string.IsNullOrWhiteSpace(entry.Name))
throw new InvalidOperationException("У триал-деки должны быть id и name.");
if (!ids.Add(entry.Id))
throw new InvalidOperationException($"Дубликат id триал-деки: {entry.Id}");
var cards = entry.Cards
.Where(card => !string.IsNullOrWhiteSpace(card.PrintingId) && card.Count > 0)
.Select(card => new TrialDeckCard(card.PrintingId, card.Count))
.ToList();
var total = cards.Sum(card => card.Count);
if (total != 50)
throw new InvalidOperationException(
$"Триал-дека {entry.Id}: {total} карт, требуется 50.");
decks.Add(new TrialDeckDefinition(entry.Id, entry.Name, entry.Clan, cards));
}
return new TrialDeckCatalog(decks);
}
private sealed class TrialDeckFile
{
public List<TrialDeckEntry> Decks { get; set; } = new();
}
private sealed class TrialDeckEntry
{
public string Id { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string? Clan { get; set; }
public List<TrialDeckCardEntry> Cards { get; set; } = new();
}
private sealed class TrialDeckCardEntry
{
public string PrintingId { get; set; } = string.Empty;
public int Count { get; set; }
}
}