using System.Collections.Immutable; using System.Reflection; using System.Text.Json; using Microsoft.Extensions.Logging; using RPG.GameCore.Excel.Attributes; namespace RPG.GameCore.Excel; public class ExcelTables { private readonly ILogger _logger; private ImmutableDictionary>? _tables; public ExcelTables(ILogger logger) { _logger = logger; } public TExcelRow? GetExcelRow(ExcelType type, uint id) where TExcelRow : ExcelRow { if (_tables == null) throw new InvalidOperationException("GetExcelRow called when ExcelTables not loaded."); if (_tables.TryGetValue(type, out ImmutableArray rows)) { return rows.SingleOrDefault(row => row.Id == id) as TExcelRow; } throw new ArgumentException($"GetExcelRow: table for excel type not found {type}"); } public IEnumerable GetAllRows(ExcelType type) { if (_tables == null) throw new InvalidOperationException("GetAllRows called when ExcelTables not loaded."); if (_tables.TryGetValue(type, out ImmutableArray rows)) { return rows; } throw new ArgumentException($"GetAllRows: table for excel type not found {type}"); } public void Load() { ImmutableDictionary>.Builder tables = ImmutableDictionary.CreateBuilder>(); IEnumerable types = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type.GetCustomAttribute() != null); foreach (Type type in types) { ExcelTableAttribute attribute = type.GetCustomAttribute()!; // TODO: asset provider JsonDocument tableJson = JsonDocument.Parse(File.ReadAllText("data/ExcelBinOutput/" + attribute.Path)); ImmutableArray.Builder rows = ImmutableArray.CreateBuilder(); foreach (JsonProperty property in tableJson.RootElement.EnumerateObject()) { if (property.Value.ValueKind != JsonValueKind.Object) throw new ArgumentException($"Failed to load excel: expected an object, got {property.Value.ValueKind}"); ExcelRow row = (property.Value.Deserialize(type) as ExcelRow)!; rows.Add(row); } tables.Add(attribute.Type, rows.ToImmutable()); } _tables = tables.ToImmutable(); _logger.LogInformation("Loaded {count} excel tables", _tables.Count); } }