using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UGQDataAccess.Repository; using UGQDataAccess.Repository.Models; using UGQDatabase.Models; using ServerCore; using ServerBase; using ServerCommon; using UGQDataAccess.Logs; using ServerCommon.BusinessLogDomain; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace UGQDataAccess.Service; public class AccountService { readonly QuestIdSequenceRepository _questIdSequenceRepository; readonly QuestContentRepository _questContentRepository; readonly QuestDialogRepository _questDialogRepository; readonly AccountRepository _accountRepository; readonly GameQuestDataRepository _gameQuestDataRepository; readonly CreatorPointHistoryRepository _creatorPointHistoryRepository; readonly NpcNameRepository _npcNameRepository; readonly UgqMetaGenerateService _ugqMetaGenerateService; readonly ReserveAccountGradeRepository _reserveAccountGradeRepository; public AccountService(QuestIdSequenceRepository questIdSequenceRepository, QuestContentRepository questContentRepository, QuestDialogRepository questDialogRepository, AccountRepository accountRepository, GameQuestDataRepository gameQuestDataRepository, CreatorPointHistoryRepository creatorPointHistoryRepository, NpcNameRepository npcNameRepository, UgqMetaGenerateService ugqMetaGenerateService, ReserveAccountGradeRepository reserveAccountGradeRepository) { _questIdSequenceRepository = questIdSequenceRepository; _questContentRepository = questContentRepository; _questDialogRepository = questDialogRepository; _accountRepository = accountRepository; _gameQuestDataRepository = gameQuestDataRepository; _creatorPointHistoryRepository = creatorPointHistoryRepository; _npcNameRepository = npcNameRepository; _ugqMetaGenerateService = ugqMetaGenerateService; _reserveAccountGradeRepository = reserveAccountGradeRepository; } public async Task getAccounts(int pageNumber, int pageSize, string? searchText, AccountSortType sortType) { return await _accountRepository.getAccounts(pageNumber, pageSize, searchText, sortType); } public async Task getAllAccountCount() { return await _accountRepository.getAllCount(); } public async Task getAccount(string userGuid) { return await _accountRepository.get(userGuid); } public async Task getAccountByAccountId(string accountId) { return await _accountRepository.getByAccountId(accountId); } public async Task getOrInsertAccount(string userGuid, string nickname, string accountId) { return await _accountRepository.getOrInsert(userGuid, nickname, accountId); } public async Task saveRefreshToken(string userGuid, string refreshToken, DateTime? refreshTokenExpryTime) { return await _accountRepository.saveRefreshToken(userGuid, refreshToken, refreshTokenExpryTime); } public async Task deleteRefreshToken(string userGuid) { return await _accountRepository.deleteRefreshToken(userGuid); } public async Task<(ServerErrorCode, AccountEntity?)> addSlotCount(string userGuid, int count, int? slotCountVersion) { if(count < 1) return (ServerErrorCode.UgqServerException, null); // 슬롯 증가는 재시도 없이 변경 못했으면 실패 리턴 var updated = await _accountRepository.addSlotCount(userGuid, slotCountVersion, count); if (updated == null) return (ServerErrorCode.UgqExceedTransactionRetry, null); return (ServerErrorCode.Success, updated); } public async Task<(ServerErrorCode, AccountEntity?)> modifySlotCount(string userGuid, int count, string adminUsername) { int retryCount = 0; while (retryCount < UGQConstants.MAX_UPDATE_RETRY_COUNT) { var entity = await _accountRepository.get(userGuid); if (entity == null) return (ServerErrorCode.UgqNullEntity, null); int haveCount = ServerCommon.MetaHelper.GameConfigMeta.UGQDefaultSlot + entity.AdditionalSlotCount + count; if (haveCount < 0 || haveCount > ServerCommon.MetaHelper.GameConfigMeta.UGQMaximumSlot) return (ServerErrorCode.UgqSlotLimit, null); var updated = await _accountRepository.addSlotCount(userGuid, entity.SlotCountVersion, count); if (updated == null) { retryCount++; Log.getLogger().warn($"slotCount version missmatch. retryCount: {retryCount}"); continue; } List business_logs = [ new UgqApiAddSlotBusinessLog(updated.AdditionalSlotCount, adminUsername), ]; var log_action = new LogActionEx(LogActionType.UgqApiAddSlot); UgqApiBusinessLogger.collectLogs(log_action, updated.UserGuid, business_logs); return (ServerErrorCode.Success, updated); } return (ServerErrorCode.UgqExceedTransactionRetry, null); } public async Task addCreatorPoint(string userGuid, long questId, long revision, double amount, UgqCreatorPointReason reason) { int retryCount = 0; while (retryCount < UGQConstants.MAX_UPDATE_RETRY_COUNT) { var entity = await _accountRepository.getOrInsertForGameUser(userGuid); if (entity == null) return ServerErrorCode.UgqNullEntity; var updated = await _accountRepository.incCreatorPoint(userGuid, entity.CreatorPointVersion, amount); if (updated == null) { retryCount++; Log.getLogger().warn($"creatorPoint version missmatch. retryCount: {retryCount}"); continue; } CreatorPointHistoryEntity historyEntity = new CreatorPointHistoryEntity { UserGuid = userGuid, QuestId = questId, Revision = revision, Kind = CreatorPointHistoryKind.QuestProfit, DetailReason = "Development", Amount = amount, TotalAmount = updated.CreatorPoint, CreatedAt = DateTime.UtcNow }; await _creatorPointHistoryRepository.insert(historyEntity); List business_logs = [ new UgqApiCreatorPointBusinessLog(amount, questId, revision, "", reason, ""), ]; var log_action = new LogActionEx(LogActionType.UgqApiCreatorPoint); UgqApiBusinessLogger.collectLogs(log_action, userGuid, business_logs); return ServerErrorCode.Success; } return ServerErrorCode.UgqExceedTransactionRetry; } public async Task decCreatorPoint(string userGuid, int amount, UgqCreatorPointReason reason) { int retryCount = 0; while (retryCount < UGQConstants.MAX_UPDATE_RETRY_COUNT) { var entity = await _accountRepository.get(userGuid); if (entity == null) return ServerErrorCode.UgqNullEntity; // 포인트가 0보다 작아지지 않게 처리해야 한다 if (entity.CreatorPoint < amount) return ServerErrorCode.UgqNotEnoughCreatorPoint; int creatorPointVersion = entity.CreatorPointVersion ?? 1; var updated = await _accountRepository.incCreatorPoint(userGuid, creatorPointVersion, -amount); if (updated == null) { retryCount++; Log.getLogger().warn($"creatorPoint version missmatch. retryCount: {retryCount}"); continue; } CreatorPointHistoryEntity historyEntity = new CreatorPointHistoryEntity { UserGuid = userGuid, QuestId = 0, Revision = 0, Kind = CreatorPointHistoryKind.SettleUp, DetailReason = "Development", Amount = -amount, TotalAmount = updated.CreatorPoint, CreatedAt = DateTime.UtcNow }; await _creatorPointHistoryRepository.insert(historyEntity); List business_logs = [ new UgqApiCreatorPointBusinessLog(-amount, 0, 0, "", reason, ""), ]; var log_action = new LogActionEx(LogActionType.UgqApiCreatorPoint); UgqApiBusinessLogger.collectLogs(log_action, userGuid, business_logs); return ServerErrorCode.Success; } return ServerErrorCode.UgqExceedTransactionRetry; } public async Task modifyAccountGrade(string userGuid, UgqGradeType grade) { return await _accountRepository.modifyAccountGrade(userGuid, grade); } public async Task promoteAccountGrade(string userGuid, UgqGradeType before, UgqGradeType after) { return await _accountRepository.promoteAccountGrade(userGuid, before, after); } public async Task<(ServerErrorCode, AccountEntity?)> modifyCreatorPoint(string userGuid, int amount, string reason, string adminUsername) { int retryCount = 0; while (retryCount < UGQConstants.MAX_UPDATE_RETRY_COUNT) { var entity = await _accountRepository.get(userGuid); if (entity == null) return (ServerErrorCode.UgqNullEntity, null); // 포인트가 0보다 작아지지 않게 처리해야 한다 if (amount < 0 && entity.CreatorPoint < -amount) return (ServerErrorCode.UgqNotEnoughCreatorPoint, null); int? creatorPointVersion = entity.CreatorPointVersion; var updated = await _accountRepository.incCreatorPoint(userGuid, creatorPointVersion, amount); if (updated == null) { retryCount++; Log.getLogger().warn($"creatorPoint version missmatch. retryCount: {retryCount}"); continue; } CreatorPointHistoryEntity historyEntity = new CreatorPointHistoryEntity { UserGuid = userGuid, QuestId = 0, Revision = 0, Kind = CreatorPointHistoryKind.Admin, DetailReason = reason, Amount = amount, TotalAmount = updated.CreatorPoint, CreatedAt = DateTime.UtcNow }; await _creatorPointHistoryRepository.insert(historyEntity); List business_logs = [ new UgqApiCreatorPointBusinessLog(amount, 0, 0, adminUsername, UgqCreatorPointReason.Admin, reason), ]; var log_action = new LogActionEx(LogActionType.UgqApiCreatorPoint); UgqApiBusinessLogger.collectLogs(log_action, userGuid, business_logs); return (ServerErrorCode.Success, updated); } return (ServerErrorCode.UgqExceedTransactionRetry, null); } public async Task getReserveAccountGrades(int pageNumber, int pageSize, AccountGradeSortType sortType, AccountGradeProcessType processType, string userGuid) { return await _reserveAccountGradeRepository.getAccounts(pageNumber, pageSize, sortType, processType, userGuid); } public async Task getAllReserveAccountGradeCount() { return await _reserveAccountGradeRepository.getAllCount(); } public async Task getReserveAccountGrade(string userGuid) { return await _reserveAccountGradeRepository.get(userGuid); } public async Task> getReserveAccountGrade(string userGuid, AccountGradeProcessType processType) { return await _reserveAccountGradeRepository.get(userGuid, processType); } public async Task reserveAccountGrade(string userGuid, UgqGradeType beforeGrade, UgqGradeType grade, DateTime reserveTime) { return await _reserveAccountGradeRepository.reserveAccountGrade(userGuid, beforeGrade, grade, reserveTime); } public async Task modifyReserveAccountGrade(string reserveId, UgqGradeType grade, DateTime reserveTime) { return await _reserveAccountGradeRepository.modifyReserveAccountGrade(reserveId, grade, reserveTime); } public async Task> completeReserveAccountGrade() { return await _reserveAccountGradeRepository.completeReserveAccountGrade(); } public async Task deleteReserveAccountGrade(string reserveId) { return await _reserveAccountGradeRepository.deleteReserveAccountGrade(reserveId); } }