More features
This commit is contained in:
@@ -19,11 +19,12 @@ public class ViewerRepository : IViewerRepository
|
||||
|
||||
public async Task<Models.Viewer?> GetViewerBySocialConnection(SocialAccountType accountType, ulong socialId)
|
||||
{
|
||||
return (await _dbContext.Set<SocialAccountConnection>()
|
||||
.AsNoTracking()
|
||||
.Include(sac => sac.Viewer)
|
||||
.FirstOrDefaultAsync(sac => sac.AccountType == accountType && sac.AccountId == socialId))
|
||||
?.Viewer;
|
||||
// SocialAccountConnection is [Owned]-by-Viewer — can't be queried as a top-level Set<T>.
|
||||
// Look up the Viewer that has a matching owned connection instead.
|
||||
return await _dbContext.Set<Models.Viewer>()
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(v => v.SocialAccountConnections.Any(sac =>
|
||||
sac.AccountType == accountType && sac.AccountId == socialId));
|
||||
}
|
||||
|
||||
public async Task<Models.Viewer?> GetViewerWithSocials(long id)
|
||||
@@ -32,10 +33,31 @@ public class ViewerRepository : IViewerRepository
|
||||
.FirstOrDefaultAsync(viewer => viewer.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a viewer with every navigation property needed to render the home-screen
|
||||
/// (/load/index). Heavy query — only call from LoadController.Index.
|
||||
/// </summary>
|
||||
public async Task<Models.Viewer?> GetViewerByShortUdid(long shortUdid)
|
||||
{
|
||||
return await _dbContext.Set<Models.Viewer>().AsNoTracking().Include(viewer => viewer.MissionData)
|
||||
.Include(viewer => viewer.Info).FirstOrDefaultAsync(viewer => viewer.ShortUdid == shortUdid);
|
||||
return await _dbContext.Set<Models.Viewer>()
|
||||
.AsNoTracking()
|
||||
.Include(v => v.MissionData)
|
||||
.Include(v => v.Info).ThenInclude(i => i.SelectedEmblem)
|
||||
.Include(v => v.Info).ThenInclude(i => i.SelectedDegree)
|
||||
.Include(v => v.Currency)
|
||||
.Include(v => v.Classes).ThenInclude(c => c.Class).ThenInclude(c => c.LeaderSkins)
|
||||
.Include(v => v.Classes).ThenInclude(c => c.LeaderSkin)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Class)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.Sleeve)
|
||||
.Include(v => v.Decks).ThenInclude(d => d.LeaderSkin)
|
||||
.Include(v => v.Cards).ThenInclude(c => c.Card)
|
||||
.Include(v => v.Items).ThenInclude(i => i.Item)
|
||||
.Include(v => v.Sleeves)
|
||||
.Include(v => v.Emblems)
|
||||
.Include(v => v.Degrees)
|
||||
.Include(v => v.LeaderSkins).ThenInclude(ls => ls.Class)
|
||||
.Include(v => v.MyPageBackgrounds)
|
||||
.FirstOrDefaultAsync(viewer => viewer.ShortUdid == shortUdid);
|
||||
}
|
||||
|
||||
public async Task<Models.Viewer> RegisterViewer(string displayName, SocialAccountType socialType,
|
||||
@@ -46,7 +68,7 @@ public class ViewerRepository : IViewerRepository
|
||||
DisplayName = displayName
|
||||
};
|
||||
GameConfiguration gameConfig = await new GlobalsRepository(_dbContext).GetGameConfiguration("default");
|
||||
|
||||
|
||||
viewer.SocialAccountConnections.Add(new SocialAccountConnection
|
||||
{
|
||||
AccountId = socialAccountIdentifier,
|
||||
@@ -61,23 +83,40 @@ public class ViewerRepository : IViewerRepository
|
||||
viewer.Currency.RedEther = gameConfig.DefaultEther;
|
||||
viewer.MissionData.TutorialState = 100; // finishes tutorial for now
|
||||
|
||||
List<ClassEntry> classes = await _dbContext.Set<ClassEntry>().ToListAsync();
|
||||
viewer.Classes = classes.Select(ce => new ViewerClassData
|
||||
// Load classes WITH their LeaderSkins — DefaultLeaderSkin iterates the nav collection
|
||||
// and would otherwise be null (audit §6 #3 latent NRE — this is the one).
|
||||
List<ClassEntry> classes = await _dbContext.Set<ClassEntry>()
|
||||
.Include(c => c.LeaderSkins)
|
||||
.ToListAsync();
|
||||
|
||||
viewer.Classes = classes.Select(ce =>
|
||||
{
|
||||
Class = ce,
|
||||
Exp = 0,
|
||||
Level = 0,
|
||||
LeaderSkin = ce.DefaultLeaderSkin
|
||||
var skin = ce.DefaultLeaderSkin ?? ce.LeaderSkins.FirstOrDefault();
|
||||
return new ViewerClassData
|
||||
{
|
||||
Class = ce,
|
||||
Exp = 0,
|
||||
Level = 0,
|
||||
LeaderSkin = skin ?? new LeaderSkinEntry { Id = 0, Name = "<missing>", ClassId = ce.Id }
|
||||
};
|
||||
}).ToList();
|
||||
|
||||
viewer.Sleeves.Add(gameConfig.DefaultSleeve);
|
||||
viewer.Degrees.Add(gameConfig.DefaultDegree);
|
||||
viewer.Emblems.Add(gameConfig.DefaultEmblem);
|
||||
viewer.MyPageBackgrounds.Add(gameConfig.DefaultMyPageBackground);
|
||||
viewer.LeaderSkins.AddRange(viewer.Classes.Select(vcd => vcd.LeaderSkin));
|
||||
if (gameConfig.DefaultSleeve is not null) viewer.Sleeves.Add(gameConfig.DefaultSleeve);
|
||||
if (gameConfig.DefaultDegree is not null) viewer.Degrees.Add(gameConfig.DefaultDegree);
|
||||
if (gameConfig.DefaultEmblem is not null) viewer.Emblems.Add(gameConfig.DefaultEmblem);
|
||||
if (gameConfig.DefaultMyPageBackground is not null) viewer.MyPageBackgrounds.Add(gameConfig.DefaultMyPageBackground);
|
||||
|
||||
// Grant one of each class's default leader skin. Filter out the synthetic placeholders
|
||||
// (Id=0) and dedupe — skins are many-to-many via SleeveEntryViewer-style join.
|
||||
var grantedSkins = viewer.Classes
|
||||
.Select(vcd => vcd.LeaderSkin)
|
||||
.Where(s => s.Id != 0)
|
||||
.DistinctBy(s => s.Id)
|
||||
.ToList();
|
||||
viewer.LeaderSkins.AddRange(grantedSkins);
|
||||
|
||||
_dbContext.Set<Models.Viewer>().Add(viewer);
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return viewer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user