forked from aly/qstbak
182 lines
5.8 KiB
C#
182 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Model;
|
|
using Questionable.Model.Questing;
|
|
using Questionable.Validation.Validators;
|
|
|
|
namespace Questionable.Validation;
|
|
|
|
internal sealed class QuestValidator
|
|
{
|
|
private readonly IReadOnlyList<IQuestValidator> _validators;
|
|
|
|
private readonly ILogger<QuestValidator> _logger;
|
|
|
|
private readonly object _lock = new object();
|
|
|
|
private List<ValidationIssue> _validationIssues = new List<ValidationIssue>();
|
|
|
|
public IReadOnlyList<ValidationIssue> Issues => _validationIssues;
|
|
|
|
public int IssueCount => _validationIssues.Count;
|
|
|
|
public int ErrorCount => _validationIssues.Count((ValidationIssue x) => x.Severity == EIssueSeverity.Error);
|
|
|
|
public int WarningCount => _validationIssues.Count((ValidationIssue x) => x.Severity == EIssueSeverity.Warning);
|
|
|
|
public QuestValidator(IEnumerable<IQuestValidator> validators, ILogger<QuestValidator> logger)
|
|
{
|
|
_validators = validators.ToList();
|
|
_logger = logger;
|
|
_logger.LogDebug("Validators: {Validators}", string.Join(", ", _validators.Select((IQuestValidator x) => x.GetType().Name)));
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
foreach (IQuestValidator validator in _validators)
|
|
{
|
|
validator.Reset();
|
|
}
|
|
lock (_lock)
|
|
{
|
|
_validationIssues = new List<ValidationIssue>();
|
|
}
|
|
}
|
|
|
|
public void AddValidationIssue(ValidationIssue issue)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
List<ValidationIssue> validationIssues = _validationIssues;
|
|
int num = 1 + validationIssues.Count;
|
|
List<ValidationIssue> list = new List<ValidationIssue>(num);
|
|
CollectionsMarshal.SetCount(list, num);
|
|
Span<ValidationIssue> span = CollectionsMarshal.AsSpan(list);
|
|
int num2 = 0;
|
|
Span<ValidationIssue> span2 = CollectionsMarshal.AsSpan(validationIssues);
|
|
span2.CopyTo(span.Slice(num2, span2.Length));
|
|
num2 += span2.Length;
|
|
span[num2] = issue;
|
|
_validationIssues = list;
|
|
}
|
|
}
|
|
|
|
public void Validate(IEnumerable<Quest> quests)
|
|
{
|
|
Task.Factory.StartNew(delegate
|
|
{
|
|
try
|
|
{
|
|
List<ValidationIssue> validationIssues;
|
|
lock (_lock)
|
|
{
|
|
validationIssues = _validationIssues;
|
|
}
|
|
List<ValidationIssue> list = new List<ValidationIssue>();
|
|
Dictionary<EAlliedSociety, List<ElementId>> dictionary = new Dictionary<EAlliedSociety, List<ElementId>>();
|
|
foreach (Quest quest in quests)
|
|
{
|
|
foreach (IQuestValidator validator in _validators)
|
|
{
|
|
foreach (ValidationIssue item in validator.Validate(quest))
|
|
{
|
|
if (item.Type == EIssueType.QuestDisabled && quest.Info.AlliedSociety != EAlliedSociety.None)
|
|
{
|
|
if (!dictionary.TryGetValue(quest.Info.AlliedSociety, out var value))
|
|
{
|
|
value = new List<ElementId>();
|
|
dictionary[quest.Info.AlliedSociety] = value;
|
|
}
|
|
value.Add(quest.Id);
|
|
}
|
|
else
|
|
{
|
|
list.Add(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
List<string> disabledQuests = (from x in list
|
|
where x.Type == EIssueType.QuestDisabled
|
|
select x.Id).ToList();
|
|
List<ValidationIssue> list2 = (from x in validationIssues.Concat(list.Where((ValidationIssue x) => !disabledQuests.Contains(x.Id) || x.Type == EIssueType.QuestDisabled)).Concat(DisabledTribesAsIssues(dictionary))
|
|
orderby x.PathType, x.Id, x.Location, x.Description
|
|
select x).ToList();
|
|
lock (_lock)
|
|
{
|
|
if (_validationIssues.Count > validationIssues.Count)
|
|
{
|
|
list2.AddRange(_validationIssues.Skip(validationIssues.Count));
|
|
}
|
|
_validationIssues = list2;
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_logger.LogError(exception, "Unable to validate quests");
|
|
}
|
|
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
|
}
|
|
|
|
public List<ValidationIssue> GetIssues(EPathType pathType, string id)
|
|
{
|
|
return _validationIssues.Where((ValidationIssue x) => x.PathType == pathType && x.Id == id).ToList();
|
|
}
|
|
|
|
private static IEnumerable<ValidationIssue> DisabledTribesAsIssues(Dictionary<EAlliedSociety, List<ElementId>> disabledTribeQuests)
|
|
{
|
|
return disabledTribeQuests.OrderBy<KeyValuePair<EAlliedSociety, List<ElementId>>, EAlliedSociety>((KeyValuePair<EAlliedSociety, List<ElementId>> x) => x.Key).Select(delegate(KeyValuePair<EAlliedSociety, List<ElementId>> x)
|
|
{
|
|
string value = ((x.Value.Count > 0) ? string.Join(", ", x.Value.Select((ElementId id) => id.ToString())) : "(none)");
|
|
return new ValidationIssue
|
|
{
|
|
PathType = EPathType.Quest,
|
|
Id = null,
|
|
Location = null,
|
|
Type = EIssueType.QuestDisabled,
|
|
Severity = EIssueSeverity.None,
|
|
Description = $"[{x.Key}] {x.Value.Count} disabled {((x.Value.Count == 1) ? "quest" : "quests")}: {value}"
|
|
};
|
|
});
|
|
}
|
|
|
|
public List<ValidationIssue> ValidateQuestSync(Quest quest)
|
|
{
|
|
List<ValidationIssue> list = new List<ValidationIssue>();
|
|
foreach (IQuestValidator validator in _validators)
|
|
{
|
|
foreach (ValidationIssue item in (validator is JsonSchemaValidator jsonSchemaValidator) ? jsonSchemaValidator.ValidateFromQuestRoot(quest) : validator.Validate(quest))
|
|
{
|
|
list.Add(item);
|
|
}
|
|
}
|
|
return (from x in list
|
|
orderby x.Sequence, x.Step, x.Description
|
|
select x).ToList();
|
|
}
|
|
|
|
public List<ValidationIssue> ValidateSchemaSync(ElementId questId, QuestRoot questRoot)
|
|
{
|
|
JsonSchemaValidator jsonSchemaValidator = _validators.OfType<JsonSchemaValidator>().FirstOrDefault();
|
|
if (jsonSchemaValidator == null)
|
|
{
|
|
return new List<ValidationIssue>();
|
|
}
|
|
return (from x in jsonSchemaValidator.ValidateFromQuestRoot(questId, questRoot)
|
|
orderby x.Sequence, x.Step, x.Description
|
|
select x).ToList();
|
|
}
|
|
|
|
public void ClearIssuesForQuest(ElementId questId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_validationIssues = _validationIssues.Where((ValidationIssue issue) => issue.ElementId != questId).ToList();
|
|
}
|
|
}
|
|
}
|