using System; using System.Globalization; using Microsoft.IdentityModel.Tokens; using Pipelines.Sockets.Unofficial.Arenas; using ServerCommon; using UGQDataAccess; using UGQDatabase.Models; using UGQApiServer.Converter; using UGQApiServer.Models; using UGQApiServer.UGQData; namespace UGQApiServer.Validation; public enum ValidationErrorKind { Success, RequireBeaconId, // ºñÄÁ ÀÔ·Â ÇÊ¿ä NotFoundBeaconId, // ÀÔ·ÂµÈ ºñÄÁÀº À߸øµÈ ¾ÆÀ̵ð FirstTaskIsNotTalkAction, // ù¹ø¤Š ŽºÅ© ´ëÈ­ ¾×¼ÇÀÌ ¾Æ´Ô FirstTaskIsNotSameBeacon, // ù¹ø¤Š ŽºÅ©ÀÇ ºñÄÁÀÌ ½ÃÀÛ ºñÄÁ°ú ´Ù¸§ InvalidCostAmount, // °¡°Ý ¿À·ù InvalidDialogType, // ÀÔ·Â À¯Çü ¿À·ù InvalidDialogConditionId, // Á¶°Ç Á¾·ù ¿À·ù InvalidDialogConditionValue, // Á¶°Ç °ª ¿À·ù InvalidDialogNextSequence, // ´ÙÀ½ ½ÃÄö½º °ª ¿À·ù InvalidSequenceCount, // ½ÃÄö½º °³¼ö´Â 3~30°³ °¡´É DontHaveEndSequence, // ½ºÄö½º Á¾·á°¡ ¾øÀ½ NotSetPlayerTalker, // Player Talker°¡ ¼¼ÆÃµÇ¾î ÀÖÁö ¾ÊÀ½ InvalidTalkerOrder, // Npc µÚ¿¡ Player°¡ ¿Ã ¼ö ¾øÀ½ InvalidTaskActionId, // Task ¾×¼Ç ŸÀÔ ¿À·ù InvalidTaskActionValue, // Task ¾×¼Ç °ª ¿À·ù InvalidTaskCount, // Task °³¼ö´Â 3~20°³ °¡´É DontHaveTitleImage, // ŸÀÌÆ² À̹ÌÁö ¾øÀ½ DontHaveBannerImage, // ¹è³Ê À̹ÌÁö ¾øÀ½ InvalidNpcActionId, // Npc ¾×¼Ç ŸÀÔ ¿À·ù } public class ValidationError { public ValidationErrorKind Kind { get; set; } public override string ToString() { return ""; } } public class QuestDialogValidatorError : ValidationError { public int TaskIndex { get; set; } = -1; public int SequenceId { get; set; } = -1; // ¿¡·¯°¡ ¹ß»ýÇÑ SequenceId. public int SequenceActionIndex { get; set; } = -1; // ¿¡·¯°¡ ¹ß»ýÇÑ SequenceAction À§Ä¡. 0 ºÎÅÍ ½ÃÀÛ. -1Àº ¾×¼Ç ¿À·ù ¾Æ´Ô. public override string ToString() { // Kind¿¡ µû¶ó ¿¡·¯¸Þ½ÃÁö »ý¼ºÇؼ­ ¸®ÅÏ LangEnum langEnum = Culture.ToLangEnum(CultureInfo.CurrentCulture.Name); string position = ""; if (SequenceActionIndex != -1) { position = $"[TaskIndex: {TaskIndex}, SequenceId: {SequenceId}, SequenceActionIndex: {SequenceActionIndex}] "; } else if (SequenceId != -1) { position = $"[TaskIndex: {TaskIndex}, SequenceId: {SequenceId}] "; } else { position = $"[TaskIndex: {TaskIndex}] "; } var textId = $"UGQ_Validator_Error_{Kind.ToString()}"; var message = UGQDataHelper.getText(langEnum, textId); return $"{position}{message}"; } } public class QuestContentValidatorError : ValidationError { public int TaskIndex { get; set; } = -1; // ¿¡·¯°¡ ¹ß»ýÇÑ Task À§Ä¡. 0 ºÎÅÍ ½ÃÀÛ public override string ToString() { // Kind¿¡ µû¶ó ¿¡·¯¸Þ½ÃÁö »ý¼ºÇؼ­ ¸®ÅÏ LangEnum langEnum = Culture.ToLangEnum(CultureInfo.CurrentCulture.Name); string position = ""; if (TaskIndex != -1) { position = $"[TaskIndex: {TaskIndex}] "; } else { position = ""; } var textId = $"UGQ_Validator_Error_{Kind.ToString()}"; var message = UGQDataHelper.getText(langEnum, textId); return $"{position}{message ?? "Unkonwn"}"; } } public class UGQValidator { UGQMetaData _ugqMetadata; int MIN_SEQUENCE = 3; int MAX_SEQUENCE = 30; int MIN_TASK = 3; int MAX_TASK = 20; public UGQValidator(UGQMetaData ugqMetadata) { _ugqMetadata = ugqMetadata; } public List Validate(QuestContentEntity questContent, List questDialogs) { List errors = new(); ValidateQuestContent(questContent, errors); // ´ÙÀ̾ó·Î±× üũ foreach (var (index, task) in questContent.Tasks.Select((task, index) => (index, task))) { var dialogIndex = questDialogs.FindIndex(x => x.Id == task.DialogId); if (task.ActionId == UGQMetaData.TALK_ACTION_ID) { if (dialogIndex == -1) { // Talk ¾×¼ÇÀÎ °æ¿ì Dialog°¡ ¾øÀ¸¸é ¿¡·¯ QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.InvalidSequenceCount, TaskIndex = index, }; errors.Add(error); continue; } var questDialog = questDialogs[dialogIndex]; // sequence °³¼ö üũ if (questDialog.Sequences.Count < MIN_SEQUENCE || questDialog.Sequences.Count >= MAX_SEQUENCE) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.InvalidSequenceCount, TaskIndex = index, }; errors.Add(error); } ValidateQuestDialog(index, questDialog, errors); } } return errors; } int getCost(UgqGradeType gradeType) { switch (gradeType) { case UgqGradeType.Amature: return MetaHelper.GameConfigMeta.UgqUsageFeeAmateur; case UgqGradeType.RisingStar: return MetaHelper.GameConfigMeta.UgqUsageFeeRisingStar; case UgqGradeType.Master1: return MetaHelper.GameConfigMeta.UgqUsageFeeMaster1; case UgqGradeType.Master2: return MetaHelper.GameConfigMeta.UgqUsageFeeMaster2; case UgqGradeType.Master3: return MetaHelper.GameConfigMeta.UgqUsageFeeMaster3; } return 0; } void ValidateQuestContent(QuestContentEntity questContent, List errors) { if(questContent.BeaconId == 0 && string.IsNullOrEmpty(questContent.UgcBeaconGuid) == true) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.RequireBeaconId, }; errors.Add(error); } if(questContent.BeaconId != 0) { var errorKind = _ugqMetadata.isValidNpcId(questContent.BeaconId); if (errorKind != ValidationErrorKind.Success) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = errorKind, }; errors.Add(error); } } if (questContent.Tasks.Count < MIN_TASK || questContent.Tasks.Count >= MAX_TASK) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.InvalidTaskCount, }; errors.Add(error); } if (string.IsNullOrEmpty(questContent.TitleImagePath) == true) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.DontHaveTitleImage, }; errors.Add(error); } if (string.IsNullOrEmpty(questContent.BannerImagePath) == true) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.DontHaveBannerImage, }; errors.Add(error); } //if (questContent.Cost != getCost(questContent.GradeType)) //{ // QuestContentValidatorError error = new QuestContentValidatorError // { // Kind = ValidationErrorKind.InvalidCostAmount, // }; // errors.Add(error); //} if (questContent.Tasks[0].ActionId != 1) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.FirstTaskIsNotTalkAction, TaskIndex = 0, }; errors.Add(error); } bool validTalkBeacon = false; if (questContent.BeaconId != 0 && questContent.Tasks[0].ActionValue == questContent.BeaconId) validTalkBeacon = true; if (string.IsNullOrEmpty(questContent.UgcBeaconGuid) == false && questContent.Tasks[0].UgcActionValueGuid == questContent.UgcBeaconGuid) validTalkBeacon = true; if(validTalkBeacon == false) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = ValidationErrorKind.FirstTaskIsNotSameBeacon, TaskIndex = 0, }; errors.Add(error); } foreach (var (index, task) in questContent.Tasks.Select((task, index) => (index, task))) { if (string.IsNullOrEmpty(task.UgcActionValueGuid) == false) { var errorKind = _ugqMetadata.isValidTackActionId(task.ActionId); if (errorKind != ValidationErrorKind.Success) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = errorKind, TaskIndex = index, }; errors.Add(error); } } else { var errorKind = _ugqMetadata.isValidTackActionValue(task.ActionId, task.ActionValue); if (errorKind != ValidationErrorKind.Success) { QuestContentValidatorError error = new QuestContentValidatorError { Kind = errorKind, TaskIndex = index, }; errors.Add(error); } } } } void ValidateQuestDialogSequenceAction(int taskIndex, List sequenceIds, int sequenceId, int actionIdex, DialogSequenceActionEntity sequenceAction, List errors) { if (sequenceAction.Talker == DialogTalker.Player) { // Talker°¡ Ç÷¹À̾î ÀÏ ¶§¿¡¸¸ µ¥ÀÌÅÍ Ã¼Å© var errorKind = _ugqMetadata.isValidDialogActionValue(sequenceAction.Type, sequenceAction.Condition, sequenceAction.ConditionValue); if (errorKind != ValidationErrorKind.Success) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = errorKind, SequenceId = sequenceId, SequenceActionIndex = actionIdex, }; errors.Add(error); } } else if(sequenceAction.Talker == DialogTalker.Npc && sequenceAction.NpcAction != 0) { var errorKind = _ugqMetadata.isValidNpcActionId(sequenceAction.NpcAction); if (errorKind != ValidationErrorKind.Success) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = errorKind, SequenceId = sequenceId, SequenceActionIndex = actionIdex, }; errors.Add(error); } } if (sequenceId != -1) { if (sequenceIds.Any(x => x == sequenceId) == false) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = ValidationErrorKind.InvalidDialogNextSequence, SequenceId = sequenceId, SequenceActionIndex = actionIdex, }; errors.Add(error); } } } void ValidateQuestDialogSequence(int taskIndex, List sequenceIds, DialogSequenceEntity sequence, List errors) { foreach (var (index, action) in sequence.Actions.Select((action, index) => (index, action))) { ValidateQuestDialogSequenceAction(taskIndex, sequenceIds, sequence.SequenceId, index, action, errors); } int playerTalkerCount = 0; int npcTalkerCount = 0; bool invalidTalkerOrder = false; foreach (var (index, action) in sequence.Actions.Select((action, index) => (index, action))) { if (action.Talker == DialogTalker.Player) { playerTalkerCount++; } else if (action.Talker == DialogTalker.Npc) { // NpcÀε¥, playerTalkerCount°¡ 0º¸´Ù Å©´Ù¸é, PlayerµÚ¿¡ Npc°¡ ³ª¿Ô´Ù´Â °ÍÀ¸·Î ¿¡·¯ ó¸® if (playerTalkerCount > 0) invalidTalkerOrder = true; npcTalkerCount++; } } if (playerTalkerCount < 1) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = ValidationErrorKind.NotSetPlayerTalker, SequenceId = sequence.SequenceId, }; } if (invalidTalkerOrder == true) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = ValidationErrorKind.InvalidTalkerOrder, SequenceId = sequence.SequenceId, }; } } void ValidateQuestDialog(int taskIndex, QuestDialogEntity questDialog, List errors) { var sequenceIds = questDialog.Sequences.Select(x => x.SequenceId).ToList(); List npcActionIds = new(); var dialogActions = questDialog.Sequences.Select(x => x.Actions).ToList(); foreach(var item in dialogActions) npcActionIds.AddRange(item.Select(x => x.NpcAction).ToList()); bool hasEnd = false; foreach (var sequence in questDialog.Sequences) { ValidateQuestDialogSequence(taskIndex, sequenceIds, sequence, errors); foreach (var action in sequence.Actions) { if(action.NextSequence == -1) hasEnd = true; } } if (hasEnd == false) { QuestDialogValidatorError error = new QuestDialogValidatorError { TaskIndex = taskIndex, Kind = ValidationErrorKind.DontHaveEndSequence, }; errors.Add(error); } } }