Files
caliverse_server/UGQApiServer/Validation/UGQValidator.cs
2025-05-01 07:20:41 +09:00

479 lines
14 KiB
C#

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<ValidationError> Validate(QuestContentEntity questContent, List<QuestDialogEntity> questDialogs)
{
List<ValidationError> 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<ValidationError> 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<int> sequenceIds, int sequenceId, int actionIdex, DialogSequenceActionEntity sequenceAction, List<ValidationError> 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<int> sequenceIds, DialogSequenceEntity sequence, List<ValidationError> 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<ValidationError> errors)
{
var sequenceIds = questDialog.Sequences.Select(x => x.SequenceId).ToList();
List<int> 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);
}
}
}