using Microsoft.EntityFrameworkCore; using SVSim.Bootstrap.Models.Seed; using SVSim.Database; using SVSim.Database.Models; namespace SVSim.Bootstrap.Importers; /// /// Idempotent upsert of achievement-catalog rows from seeds/achievement-catalog.json. /// Keyed by (AchievementType, Level) so re-running with new captures grows the ladder. /// Rows missing from the seed are LEFT INTACT. /// public class AchievementCatalogImporter { public async Task ImportAsync(SVSimDbContext context, string seedDir) { var seed = SeedLoader.LoadList(Path.Combine(seedDir, "achievement-catalog.json")); if (seed.Count == 0) { Console.WriteLine("[AchievementCatalogImporter] No seed rows; skipping."); return 0; } var existing = await context.AchievementCatalog .ToDictionaryAsync(e => (e.AchievementType, e.Level)); int created = 0, updated = 0; var unmappedTypes = new HashSet(); foreach (var s in seed) { if (s.AchievementType == 0 || s.Level == 0) continue; var key = (s.AchievementType, s.Level); var entry = existing.TryGetValue(key, out var ex) ? ex : new AchievementCatalogEntry { AchievementType = s.AchievementType, Level = s.Level, }; entry.Name = s.Name; entry.RequireNumber = s.RequireNumber; entry.RewardType = s.RewardType; entry.RewardDetailId = s.RewardDetailId; entry.RewardNumber = s.RewardNumber; entry.OrderNum = s.OrderNum; entry.EventType = s.EventType; entry.EventArg = s.EventArg; if (ex is null) { context.AchievementCatalog.Add(entry); existing[key] = entry; created++; } else updated++; if (s.EventType is null) unmappedTypes.Add(s.AchievementType); } await context.SaveChangesAsync(); Console.WriteLine($"[AchievementCatalogImporter] +{created}/~{updated}"); if (unmappedTypes.Count > 0) { Console.WriteLine($"[AchievementCatalogImporter] WARN: {unmappedTypes.Count} types " + $"with no event_type: [{string.Join(", ", unmappedTypes.OrderBy(x => x))}] — " + "add to ACHIEVEMENT_EVENT_MAP in data_dumps/scripts/extract-achievements.py"); } return created + updated; } }