fix: app
This commit is contained in:
@@ -6,13 +6,14 @@ using Serilog;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides aggregated analytics metrics for dashboards.
|
||||
/// </summary>
|
||||
public class AnalyticsService : IAnalyticsService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public AnalyticsService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public AnalyticsService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<AnalyticsSummary> GetSummaryAsync(CancellationToken ct = default)
|
||||
{
|
||||
|
||||
@@ -4,52 +4,98 @@ using LctMonolith.Services.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
public class DialogueService : IDialogueService
|
||||
namespace LctMonolith.Services
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public DialogueService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public async Task<Dialogue?> GetDialogueByMissionIdAsync(Guid missionId)
|
||||
public class DialogueService : IDialogueService
|
||||
{
|
||||
try { return await _uow.Dialogues.Query(d => d.MissionId == missionId).FirstOrDefaultAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetDialogueByMissionIdAsync failed {MissionId}", missionId); throw; }
|
||||
}
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public async Task<Dialogue> CreateDialogueAsync(Dialogue dialogue)
|
||||
{
|
||||
try
|
||||
public DialogueService(IUnitOfWork uow)
|
||||
{
|
||||
dialogue.Id = Guid.NewGuid();
|
||||
await _uow.Dialogues.AddAsync(dialogue);
|
||||
await _uow.SaveChangesAsync();
|
||||
return dialogue;
|
||||
_uow = uow;
|
||||
}
|
||||
catch (Exception ex) { Log.Error(ex, "CreateDialogueAsync failed {MissionId}", dialogue.MissionId); throw; }
|
||||
}
|
||||
|
||||
public async Task<DialogueMessage?> GetDialogueMessageByIdAsync(Guid messageId)
|
||||
{
|
||||
try { return await _uow.DialogueMessages.GetByIdAsync(messageId); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetDialogueMessageByIdAsync failed {MessageId}", messageId); throw; }
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DialogueMessageResponseOption>> GetResponseOptionsAsync(Guid messageId)
|
||||
{
|
||||
try { return await _uow.DialogueMessageResponseOptions.Query(o => o.ParentDialogueMessageId == messageId).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetResponseOptionsAsync failed {MessageId}", messageId); throw; }
|
||||
}
|
||||
|
||||
public async Task<DialogueMessage?> ProcessDialogueResponseAsync(Guid messageId, Guid responseOptionId, Guid playerId)
|
||||
{
|
||||
try
|
||||
public async Task<Dialogue?> GetDialogueByMissionIdAsync(Guid missionId)
|
||||
{
|
||||
var option = await _uow.DialogueMessageResponseOptions.Query(o => o.Id == responseOptionId && o.ParentDialogueMessageId == messageId).FirstOrDefaultAsync();
|
||||
if (option == null) return null;
|
||||
if (option.DestinationDialogueMessageId == null) return null; // end branch
|
||||
return await _uow.DialogueMessages.GetByIdAsync(option.DestinationDialogueMessageId);
|
||||
try
|
||||
{
|
||||
return await _uow.Dialogues
|
||||
.Query(d => d.MissionId == missionId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetDialogueByMissionIdAsync failed {MissionId}", missionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dialogue> CreateDialogueAsync(Dialogue dialogue)
|
||||
{
|
||||
try
|
||||
{
|
||||
dialogue.Id = Guid.NewGuid();
|
||||
await _uow.Dialogues.AddAsync(dialogue);
|
||||
await _uow.SaveChangesAsync();
|
||||
return dialogue;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "CreateDialogueAsync failed {MissionId}", dialogue.MissionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DialogueMessage?> GetDialogueMessageByIdAsync(Guid messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _uow.DialogueMessages.GetByIdAsync(messageId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetDialogueMessageByIdAsync failed {MessageId}", messageId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<DialogueMessageResponseOption>> GetResponseOptionsAsync(Guid messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _uow.DialogueMessageResponseOptions
|
||||
.Query(o => o.ParentDialogueMessageId == messageId)
|
||||
.ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetResponseOptionsAsync failed {MessageId}", messageId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DialogueMessage?> ProcessDialogueResponseAsync(Guid messageId, Guid responseOptionId, Guid playerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var option = await _uow.DialogueMessageResponseOptions
|
||||
.Query(o => o.Id == responseOptionId && o.ParentDialogueMessageId == messageId)
|
||||
.FirstOrDefaultAsync();
|
||||
if (option == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (option.DestinationDialogueMessageId == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return await _uow.DialogueMessages.GetByIdAsync(option.DestinationDialogueMessageId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "ProcessDialogueResponseAsync failed {MessageId} {ResponseId}", messageId, responseOptionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { Log.Error(ex, "ProcessDialogueResponseAsync failed {MessageId} {ResponseId}", messageId, responseOptionId); throw; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,46 +4,102 @@ using LctMonolith.Services.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
public class MissionCategoryService : IMissionCategoryService
|
||||
namespace LctMonolith.Services
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public MissionCategoryService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public async Task<MissionCategory?> GetCategoryByIdAsync(Guid categoryId)
|
||||
public class MissionCategoryService : IMissionCategoryService
|
||||
{
|
||||
try { return await _uow.MissionCategories.GetByIdAsync(categoryId); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetCategoryByIdAsync failed {CategoryId}", categoryId); throw; }
|
||||
}
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public async Task<MissionCategory?> GetCategoryByTitleAsync(string title)
|
||||
{
|
||||
try { return await _uow.MissionCategories.Query(c => c.Title == title).FirstOrDefaultAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetCategoryByTitleAsync failed {Title}", title); throw; }
|
||||
}
|
||||
public MissionCategoryService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MissionCategory>> GetAllCategoriesAsync()
|
||||
{
|
||||
try { return await _uow.MissionCategories.Query().OrderBy(c => c.Title).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetAllCategoriesAsync failed"); throw; }
|
||||
}
|
||||
public async Task<MissionCategory?> GetCategoryByIdAsync(Guid categoryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _uow.MissionCategories.GetByIdAsync(categoryId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetCategoryByIdAsync failed {CategoryId}", categoryId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MissionCategory> CreateCategoryAsync(MissionCategory category)
|
||||
{
|
||||
try { category.Id = Guid.NewGuid(); await _uow.MissionCategories.AddAsync(category); await _uow.SaveChangesAsync(); return category; }
|
||||
catch (Exception ex) { Log.Error(ex, "CreateCategoryAsync failed {Title}", category.Title); throw; }
|
||||
}
|
||||
public async Task<MissionCategory?> GetCategoryByTitleAsync(string title)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _uow.MissionCategories.Query(c => c.Title == title).FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetCategoryByTitleAsync failed {Title}", title);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MissionCategory> UpdateCategoryAsync(MissionCategory category)
|
||||
{
|
||||
try { _uow.MissionCategories.Update(category); await _uow.SaveChangesAsync(); return category; }
|
||||
catch (Exception ex) { Log.Error(ex, "UpdateCategoryAsync failed {Id}", category.Id); throw; }
|
||||
}
|
||||
public async Task<IEnumerable<MissionCategory>> GetAllCategoriesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _uow.MissionCategories.Query().OrderBy(c => c.Title).ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetAllCategoriesAsync failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteCategoryAsync(Guid categoryId)
|
||||
{
|
||||
try { var c = await _uow.MissionCategories.GetByIdAsync(categoryId); if (c == null) return false; _uow.MissionCategories.Remove(c); await _uow.SaveChangesAsync(); return true; }
|
||||
catch (Exception ex) { Log.Error(ex, "DeleteCategoryAsync failed {CategoryId}", categoryId); throw; }
|
||||
public async Task<MissionCategory> CreateCategoryAsync(MissionCategory category)
|
||||
{
|
||||
try
|
||||
{
|
||||
category.Id = Guid.NewGuid();
|
||||
await _uow.MissionCategories.AddAsync(category);
|
||||
await _uow.SaveChangesAsync();
|
||||
return category;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "CreateCategoryAsync failed {Title}", category.Title);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MissionCategory> UpdateCategoryAsync(MissionCategory category)
|
||||
{
|
||||
try
|
||||
{
|
||||
_uow.MissionCategories.Update(category);
|
||||
await _uow.SaveChangesAsync();
|
||||
return category;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "UpdateCategoryAsync failed {Id}", category.Id);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteCategoryAsync(Guid categoryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = await _uow.MissionCategories.GetByIdAsync(categoryId);
|
||||
if (c == null) { return false; }
|
||||
_uow.MissionCategories.Remove(c);
|
||||
await _uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "DeleteCategoryAsync failed {CategoryId}", categoryId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,50 +9,124 @@ namespace LctMonolith.Services;
|
||||
public class RankService : IRankService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public RankService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public RankService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<Rank?> GetRankByIdAsync(Guid rankId)
|
||||
{
|
||||
try { return await _uow.Ranks.GetByIdAsync(rankId); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetRankByIdAsync failed {RankId}", rankId); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.Ranks.GetByIdAsync(rankId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetRankByIdAsync failed {RankId}", rankId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Rank?> GetRankByTitleAsync(string title)
|
||||
{
|
||||
try { return await _uow.Ranks.Query(r => r.Title == title).FirstOrDefaultAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetRankByTitleAsync failed {Title}", title); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.Ranks.Query(r => r.Title == title).FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetRankByTitleAsync failed {Title}", title);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Rank>> GetAllRanksAsync()
|
||||
{
|
||||
try { return await _uow.Ranks.Query().OrderBy(r => r.ExpNeeded).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetAllRanksAsync failed"); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.Ranks.Query().OrderBy(r => r.ExpNeeded).ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetAllRanksAsync failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Rank> CreateRankAsync(Rank rank)
|
||||
{
|
||||
try { rank.Id = Guid.NewGuid(); await _uow.Ranks.AddAsync(rank); await _uow.SaveChangesAsync(); return rank; }
|
||||
catch (Exception ex) { Log.Error(ex, "CreateRankAsync failed {Title}", rank.Title); throw; }
|
||||
try
|
||||
{
|
||||
rank.Id = Guid.NewGuid();
|
||||
await _uow.Ranks.AddAsync(rank);
|
||||
await _uow.SaveChangesAsync();
|
||||
return rank;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "CreateRankAsync failed {Title}", rank.Title);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Rank> UpdateRankAsync(Rank rank)
|
||||
{
|
||||
try { _uow.Ranks.Update(rank); await _uow.SaveChangesAsync(); return rank; }
|
||||
catch (Exception ex) { Log.Error(ex, "UpdateRankAsync failed {RankId}", rank.Id); throw; }
|
||||
try
|
||||
{
|
||||
_uow.Ranks.Update(rank);
|
||||
await _uow.SaveChangesAsync();
|
||||
return rank;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "UpdateRankAsync failed {RankId}", rank.Id);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteRankAsync(Guid rankId)
|
||||
{
|
||||
try { var r = await _uow.Ranks.GetByIdAsync(rankId); if (r == null) return false; _uow.Ranks.Remove(r); await _uow.SaveChangesAsync(); return true; }
|
||||
catch (Exception ex) { Log.Error(ex, "DeleteRankAsync failed {RankId}", rankId); throw; }
|
||||
try
|
||||
{
|
||||
var r = await _uow.Ranks.GetByIdAsync(rankId);
|
||||
if (r == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_uow.Ranks.Remove(r);
|
||||
await _uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "DeleteRankAsync failed {RankId}", rankId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> CanPlayerAdvanceToRankAsync(Guid playerId, Guid rankId)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
var player = await _uow.Players.GetByIdAsync(playerId) ?? throw new KeyNotFoundException("Player not found");
|
||||
var rank = await _uow.Ranks.GetByIdAsync(rankId) ?? throw new KeyNotFoundException("Rank not found");
|
||||
if (player.Experience < rank.ExpNeeded) return false;
|
||||
if (player.Experience < rank.ExpNeeded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var missionReqs = await _uow.RankMissionRules.Query(rmr => rmr.RankId == rankId).Select(r => r.MissionId).ToListAsync();
|
||||
if (missionReqs.Count > 0)
|
||||
{
|
||||
var completed = await _uow.PlayerMissions.Query(pm => pm.PlayerId == playerId && pm.Completed != null).Select(pm => pm.MissionId).ToListAsync();
|
||||
if (missionReqs.Except(completed).Any()) return false;
|
||||
if (missionReqs.Except(completed).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var skillReqs = await _uow.RankSkillRules.Query(rsr => rsr.RankId == rankId).ToListAsync();
|
||||
if (skillReqs.Count > 0)
|
||||
{
|
||||
@@ -60,16 +134,38 @@ public class RankService : IRankService
|
||||
foreach (var req in skillReqs)
|
||||
{
|
||||
var ps = playerSkills.FirstOrDefault(s => s.SkillId == req.SkillId);
|
||||
if (ps == null || ps.Score < req.Min) return false;
|
||||
if (ps == null || ps.Score < req.Min)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; }
|
||||
catch (Exception ex) { Log.Error(ex, "CanPlayerAdvanceToRankAsync failed {PlayerId}->{RankId}", playerId, rankId); throw; }
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "CanPlayerAdvanceToRankAsync failed {PlayerId}->{RankId}", playerId, rankId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Rank?> GetNextRankAsync(Guid currentRankId)
|
||||
{
|
||||
try {
|
||||
var current = await _uow.Ranks.GetByIdAsync(currentRankId); if (current == null) return null; return await _uow.Ranks.Query(r => r.ExpNeeded > current.ExpNeeded).OrderBy(r => r.ExpNeeded).FirstOrDefaultAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetNextRankAsync failed {RankId}", currentRankId); throw; }
|
||||
try
|
||||
{
|
||||
var current = await _uow.Ranks.GetByIdAsync(currentRankId);
|
||||
if (current == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await _uow.Ranks.Query(r => r.ExpNeeded > current.ExpNeeded).OrderBy(r => r.ExpNeeded).FirstOrDefaultAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetNextRankAsync failed {RankId}", currentRankId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,36 @@ namespace LctMonolith.Services;
|
||||
public class RewardService : IRewardService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public RewardService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public RewardService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MissionSkillReward>> GetMissionSkillRewardsAsync(Guid missionId)
|
||||
{
|
||||
try { return await _uow.MissionSkillRewards.Query(r => r.MissionId == missionId, null, r => r.Skill).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetMissionSkillRewardsAsync failed {MissionId}", missionId); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.MissionSkillRewards.Query(r => r.MissionId == missionId, null, r => r.Skill).ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetMissionSkillRewardsAsync failed {MissionId}", missionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MissionItemReward>> GetMissionItemRewardsAsync(Guid missionId)
|
||||
{
|
||||
try { return await _uow.MissionItemRewards.Query(r => r.MissionId == missionId).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetMissionItemRewardsAsync failed {MissionId}", missionId); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.MissionItemRewards.Query(r => r.MissionId == missionId).ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetMissionItemRewardsAsync failed {MissionId}", missionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DistributeMissionRewardsAsync(Guid missionId, Guid playerId)
|
||||
@@ -33,7 +51,6 @@ public class RewardService : IRewardService
|
||||
player.Experience += mission.ExpReward;
|
||||
player.Mana += mission.ManaReward;
|
||||
|
||||
// Skill rewards
|
||||
var skillRewards = await _uow.MissionSkillRewards.Query(r => r.MissionId == missionId).ToListAsync();
|
||||
foreach (var sr in skillRewards)
|
||||
{
|
||||
@@ -50,7 +67,6 @@ public class RewardService : IRewardService
|
||||
}
|
||||
}
|
||||
|
||||
// Item rewards (store items) one each
|
||||
var itemRewards = await _uow.MissionItemRewards.Query(r => r.MissionId == missionId).ToListAsync();
|
||||
foreach (var ir in itemRewards)
|
||||
{
|
||||
@@ -60,10 +76,12 @@ public class RewardService : IRewardService
|
||||
inv = new UserInventoryItem { UserId = player.UserId, StoreItemId = ir.ItemId, Quantity = 1, AcquiredAt = DateTime.UtcNow };
|
||||
await _uow.UserInventoryItems.AddAsync(inv);
|
||||
}
|
||||
else inv.Quantity += 1;
|
||||
else
|
||||
{
|
||||
inv.Quantity += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark redeemed
|
||||
var pm = await _uow.PlayerMissions.Query(pm => pm.PlayerId == playerId && pm.MissionId == missionId).FirstOrDefaultAsync();
|
||||
if (pm != null && pm.RewardsRedeemed == null)
|
||||
{
|
||||
@@ -82,11 +100,17 @@ public class RewardService : IRewardService
|
||||
{
|
||||
try
|
||||
{
|
||||
// Interpret rewardId as missionId; claim if mission completed and rewards not yet redeemed
|
||||
var pm = await _uow.PlayerMissions.Query(pm => pm.PlayerId == playerId && pm.MissionId == rewardId).FirstOrDefaultAsync();
|
||||
if (pm == null || pm.Completed == null) return false;
|
||||
if (pm == null || pm.Completed == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return pm.RewardsRedeemed == null;
|
||||
}
|
||||
catch (Exception ex) { Log.Error(ex, "CanClaimRewardAsync failed {RewardId} {PlayerId}", rewardId, playerId); throw; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "CanClaimRewardAsync failed {RewardId} {PlayerId}", rewardId, playerId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,35 @@ namespace LctMonolith.Services;
|
||||
public class RuleValidationService : IRuleValidationService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public RuleValidationService(IUnitOfWork uow) => _uow = uow;
|
||||
|
||||
public RuleValidationService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateMissionRankRulesAsync(Guid missionId, Guid playerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = await _uow.Players.GetByIdAsync(playerId);
|
||||
if (player == null) return false;
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var rankRules = await _uow.MissionRankRules.Query(r => r.MissionId == missionId).Select(r => r.RankId).ToListAsync();
|
||||
if (rankRules.Count == 0) return true; // no restriction
|
||||
if (rankRules.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return rankRules.Contains(player.RankId);
|
||||
}
|
||||
catch (Exception ex) { Log.Error(ex, "ValidateMissionRankRulesAsync failed {MissionId} {PlayerId}", missionId, playerId); throw; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "ValidateMissionRankRulesAsync failed {MissionId} {PlayerId}", missionId, playerId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateRankAdvancementRulesAsync(Guid playerId, Guid targetRankId)
|
||||
@@ -29,18 +45,32 @@ public class RuleValidationService : IRuleValidationService
|
||||
try
|
||||
{
|
||||
var player = await _uow.Players.GetByIdAsync(playerId);
|
||||
if (player == null) return false;
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var rank = await _uow.Ranks.GetByIdAsync(targetRankId);
|
||||
if (rank == null) return false;
|
||||
if (player.Experience < rank.ExpNeeded) return false;
|
||||
// required missions
|
||||
if (rank == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (player.Experience < rank.ExpNeeded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var missionReqs = await _uow.RankMissionRules.Query(r => r.RankId == targetRankId).Select(r => r.MissionId).ToListAsync();
|
||||
if (missionReqs.Count > 0)
|
||||
{
|
||||
var completed = await _uow.PlayerMissions.Query(pm => pm.PlayerId == playerId && pm.Completed != null).Select(pm => pm.MissionId).ToListAsync();
|
||||
if (missionReqs.Except(completed).Any()) return false;
|
||||
if (missionReqs.Except(completed).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// required skills
|
||||
|
||||
var skillReqs = await _uow.RankSkillRules.Query(r => r.RankId == targetRankId).ToListAsync();
|
||||
if (skillReqs.Count > 0)
|
||||
{
|
||||
@@ -48,17 +78,32 @@ public class RuleValidationService : IRuleValidationService
|
||||
foreach (var req in skillReqs)
|
||||
{
|
||||
var ps = playerSkills.FirstOrDefault(s => s.SkillId == req.SkillId);
|
||||
if (ps == null || ps.Score < req.Min) return false;
|
||||
if (ps == null || ps.Score < req.Min)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) { Log.Error(ex, "ValidateRankAdvancementRulesAsync failed {PlayerId}->{RankId}", playerId, targetRankId); throw; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "ValidateRankAdvancementRulesAsync failed {PlayerId}->{RankId}", playerId, targetRankId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MissionRankRule>> GetApplicableRankRulesAsync(Guid missionId)
|
||||
{
|
||||
try { return await _uow.MissionRankRules.Query(r => r.MissionId == missionId, null, r => r.Rank).ToListAsync(); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetApplicableRankRulesAsync failed {MissionId}", missionId); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.MissionRankRules.Query(r => r.MissionId == missionId, null, r => r.Rank).ToListAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetApplicableRankRulesAsync failed {MissionId}", missionId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace LctMonolith.Services;
|
||||
public class SkillService : ISkillService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
public SkillService(IUnitOfWork uow) => _uow = uow;
|
||||
public SkillService(IUnitOfWork uow) { _uow = uow; }
|
||||
|
||||
public async Task<Skill?> GetSkillByIdAsync(Guid skillId)
|
||||
{
|
||||
@@ -38,7 +38,7 @@ public class SkillService : ISkillService
|
||||
}
|
||||
public async Task<bool> DeleteSkillAsync(Guid skillId)
|
||||
{
|
||||
try { var skill = await _uow.Skills.GetByIdAsync(skillId); if (skill == null) return false; _uow.Skills.Remove(skill); await _uow.SaveChangesAsync(); return true; }
|
||||
try { var skill = await _uow.Skills.GetByIdAsync(skillId); if (skill == null) { return false; } _uow.Skills.Remove(skill); await _uow.SaveChangesAsync(); return true; }
|
||||
catch (Exception ex) { Log.Error(ex, "DeleteSkillAsync failed {SkillId}", skillId); throw; }
|
||||
}
|
||||
public async Task<PlayerSkill> UpdatePlayerSkillAsync(Guid playerId, Guid skillId, int level)
|
||||
|
||||
@@ -7,9 +7,6 @@ using LctMonolith.Services.Contracts;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Store purchase operations and inventory management.
|
||||
/// </summary>
|
||||
public class StoreService : IStoreService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
@@ -21,8 +18,15 @@ public class StoreService : IStoreService
|
||||
|
||||
public async Task<IEnumerable<StoreItem>> GetActiveItemsAsync(CancellationToken ct = default)
|
||||
{
|
||||
try { return await _uow.StoreItems.Query(i => i.IsActive).ToListAsync(ct); }
|
||||
catch (Exception ex) { Log.Error(ex, "GetActiveItemsAsync failed"); throw; }
|
||||
try
|
||||
{
|
||||
return await _uow.StoreItems.Query(i => i.IsActive).ToListAsync(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "GetActiveItemsAsync failed");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<UserInventoryItem> PurchaseAsync(Guid userId, Guid itemId, int quantity, CancellationToken ct = default)
|
||||
@@ -45,7 +49,10 @@ public class StoreService : IStoreService
|
||||
inv = new UserInventoryItem { UserId = userId, StoreItemId = itemId, Quantity = quantity, AcquiredAt = DateTime.UtcNow };
|
||||
await _uow.UserInventoryItems.AddAsync(inv, ct);
|
||||
}
|
||||
else inv.Quantity += quantity;
|
||||
else
|
||||
{
|
||||
inv.Quantity += quantity;
|
||||
}
|
||||
|
||||
await _uow.Transactions.AddAsync(new Transaction { UserId = userId, StoreItemId = itemId, Type = TransactionType.Purchase, ManaAmount = -totalPrice }, ct);
|
||||
await _uow.EventLogs.AddAsync(new EventLog { Type = EventType.ItemPurchased, UserId = userId, Data = JsonSerializer.Serialize(new { itemId, quantity, totalPrice }) }, ct);
|
||||
|
||||
Reference in New Issue
Block a user