Validation: Sum up disabled tribe quests instead of showing each one individually

pull/14/head v1.19
Liza 2024-07-27 01:51:21 +02:00
parent ec3a0eb82f
commit 3483d07ff2
Signed by: liza
GPG Key ID: 7199F8D727D55F67
13 changed files with 100 additions and 7 deletions

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
namespace Questionable.Model;
[SuppressMessage("Design", "CA1028", Justification = "Game type")]
[UsedImplicitly(ImplicitUseTargetFlags.Members)]
public enum EBeastTribe : byte
{
None = 0,
Amaljaa = 1,
Sylphs = 2,
Kobolds = 3,
Sahagin = 4,
Ixal = 5,
VanuVanu = 6,
Vath = 7,
Moogles = 8,
Kojin = 9,
Ananta = 10,
Namazu = 11,
Pixies = 12,
Qitari = 13,
Dwarves = 14,
Arkasodara = 15,
Omicrons = 16,
Loporrits = 17,
}

View File

@ -27,6 +27,7 @@ internal sealed class QuestInfo
PreviousInstanceContent = quest.InstanceContent.Select(x => (ushort)x.Row).Where(x => x != 0).ToList();
PreviousInstanceContentJoin = (QuestJoin)quest.InstanceContentJoin;
GrandCompany = (GrandCompany)quest.GrandCompany.Row;
BeastTribe = (EBeastTribe)quest.BeastTribe.Row;
}
@ -44,6 +45,7 @@ internal sealed class QuestInfo
public bool IsMainScenarioQuest { get; }
public bool CompletesInstantly { get; }
public GrandCompany GrandCompany { get; }
public EBeastTribe BeastTribe { get; }
public string SimplifiedName => Name
.TrimStart(SeIconChar.QuestSync.ToIconChar(), SeIconChar.QuestRepeatable.ToIconChar(), ' ');

View File

@ -1,6 +1,6 @@
<Project Sdk="Dalamud.NET.Sdk/9.0.2">
<PropertyGroup>
<Version>1.18</Version>
<Version>1.19</Version>
<OutputPath>dist</OutputPath>
<PathMap Condition="$(SolutionDir) != ''">$(SolutionDir)=X:\</PathMap>
<Platforms>x64</Platforms>

View File

@ -0,0 +1,18 @@
namespace Questionable.Validation;
public enum EIssueType
{
None,
InvalidJsonSchema,
MissingSequence0,
MissingSequence,
DuplicateSequence,
MissingQuestAccept,
MissingQuestComplete,
InstantQuestWithMultipleSteps,
DuplicateCompletionFlags,
InvalidNextQuestId,
QuestDisabled,
UnexpectedAcceptQuestStep,
UnexpectedCompleteQuestStep,
}

View File

@ -41,6 +41,7 @@ internal sealed class QuestValidator
{
try
{
Dictionary<EBeastTribe, int> disabledTribeQuests = new();
foreach (var quest in quests)
{
foreach (var validator in _validators)
@ -53,7 +54,13 @@ internal sealed class QuestValidator
_logger.Log(level,
"Validation failed: {QuestId} ({QuestName}) / {QuestSequence} / {QuestStep} - {Description}",
issue.QuestId, quest.Info.Name, issue.Sequence, issue.Step, issue.Description);
_validationIssues.Add(issue);
if (issue.Type == EIssueType.QuestDisabled && quest.Info.BeastTribe != EBeastTribe.None)
{
disabledTribeQuests.TryAdd(quest.Info.BeastTribe, 0);
disabledTribeQuests[quest.Info.BeastTribe]++;
}
else
_validationIssues.Add(issue);
}
}
}
@ -62,6 +69,7 @@ internal sealed class QuestValidator
.ThenBy(x => x.Sequence)
.ThenBy(x => x.Step)
.ThenBy(x => x.Description)
.Concat(DisabledTribesAsIssues(disabledTribeQuests))
.ToList();
}
catch (Exception e)
@ -70,4 +78,20 @@ internal sealed class QuestValidator
}
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
private static IEnumerable<ValidationIssue> DisabledTribesAsIssues(Dictionary<EBeastTribe, int> disabledTribeQuests)
{
return disabledTribeQuests
.OrderBy(x => x.Key)
.Select(x => new ValidationIssue
{
QuestId = null,
Sequence = null,
Step = null,
BeastTribe = x.Key,
Type = EIssueType.QuestDisabled,
Severity = EIssueSeverity.None,
Description = $"{x.Value} disabled quest(s)",
});
}
}

View File

@ -1,10 +1,14 @@
namespace Questionable.Validation;
using Questionable.Model;
namespace Questionable.Validation;
internal sealed record ValidationIssue
{
public required ushort QuestId { get; init; }
public required ushort? QuestId { get; init; }
public required byte? Sequence { get; init; }
public required int? Step { get; init; }
public EBeastTribe BeastTribe { get; init; } = EBeastTribe.None;
public required EIssueType Type { get; init; }
public required EIssueSeverity Severity { get; init; }
public required string Description { get; init; }
}

View File

@ -21,6 +21,7 @@ internal sealed class BasicSequenceValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = 0,
Step = null,
Type = EIssueType.MissingSequence0,
Severity = EIssueSeverity.Error,
Description = "Missing quest start",
};
@ -39,6 +40,7 @@ internal sealed class BasicSequenceValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)sequence.Sequence,
Step = null,
Type = EIssueType.InstantQuestWithMultipleSteps,
Severity = EIssueSeverity.Error,
Description = "Instant quest should not have any sequences after the start",
};
@ -74,6 +76,7 @@ internal sealed class BasicSequenceValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)sequenceNo,
Step = null,
Type = EIssueType.MissingSequence,
Severity = EIssueSeverity.Error,
Description = "Missing sequence",
};
@ -85,6 +88,7 @@ internal sealed class BasicSequenceValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)sequenceNo,
Step = null,
Type = EIssueType.DuplicateSequence,
Severity = EIssueSeverity.Error,
Description = "Duplicate sequence",
};

View File

@ -44,6 +44,7 @@ internal sealed class CompletionFlagsValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)sequence.Sequence,
Step = i,
Type = EIssueType.DuplicateCompletionFlags,
Severity = EIssueSeverity.Error,
Description = $"Duplicate completion flags: {string.Join(", ", sequence.Steps[i].CompletionQuestVariablesFlags)}",
};

View File

@ -30,6 +30,7 @@ internal sealed class JsonSchemaValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = null,
Step = null,
Type = EIssueType.InvalidJsonSchema,
Severity = EIssueSeverity.Error,
Description = "JSON Validation failed"
};

View File

@ -15,6 +15,7 @@ internal sealed class NextQuestValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)invalidNextQuest.Sequence.Sequence,
Step = invalidNextQuest.StepId,
Type = EIssueType.InvalidNextQuestId,
Severity = EIssueSeverity.Error,
Description = "Next quest should not reference itself",
};

View File

@ -14,6 +14,7 @@ internal sealed class QuestDisabledValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = null,
Step = null,
Type = EIssueType.QuestDisabled,
Severity = EIssueSeverity.None,
Description = "Quest is disabled",
};

View File

@ -21,6 +21,7 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)accept.Sequence.Sequence,
Step = accept.StepId,
Type = EIssueType.UnexpectedAcceptQuestStep,
Severity = EIssueSeverity.Error,
Description = "Unexpected AcceptQuest step",
};
@ -34,6 +35,7 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = 0,
Step = null,
Type = EIssueType.MissingQuestAccept,
Severity = EIssueSeverity.Error,
Description = "No AcceptQuest step",
};
@ -51,6 +53,7 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = (byte)complete.Sequence.Sequence,
Step = complete.StepId,
Type = EIssueType.UnexpectedCompleteQuestStep,
Severity = EIssueSeverity.Error,
Description = "Unexpected CompleteQuest step",
};
@ -64,6 +67,7 @@ internal sealed class UniqueStartStopValidator : IQuestValidator
QuestId = quest.QuestId,
Sequence = 255,
Step = null,
Type = EIssueType.MissingQuestComplete,
Severity = EIssueSeverity.Error,
Description = "No CompleteQuest step",
};

View File

@ -19,7 +19,9 @@ internal sealed class QuestValidationWindow : LWindow
private readonly QuestData _questData;
private readonly IDalamudPluginInterface _pluginInterface;
public QuestValidationWindow(QuestValidator questValidator, QuestData questData, IDalamudPluginInterface pluginInterface) : base("Quest Validation###QuestionableValidator")
public QuestValidationWindow(QuestValidator questValidator, QuestData questData,
IDalamudPluginInterface pluginInterface)
: base("Quest Validation###QuestionableValidator")
{
_questValidator = questValidator;
_questData = questData;
@ -54,10 +56,12 @@ internal sealed class QuestValidationWindow : LWindow
ImGui.TableNextRow();
if (ImGui.TableNextColumn())
ImGui.TextUnformatted(validationIssue.QuestId.ToString(CultureInfo.InvariantCulture));
ImGui.TextUnformatted(validationIssue.QuestId?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
if (ImGui.TableNextColumn())
ImGui.TextUnformatted(_questData.GetQuestInfo(validationIssue.QuestId).Name);
ImGui.TextUnformatted(validationIssue.QuestId != null
? _questData.GetQuestInfo(validationIssue.QuestId.Value).Name
: validationIssue.BeastTribe.ToString());
if (ImGui.TableNextColumn())
ImGui.TextUnformatted(validationIssue.Sequence?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
@ -81,6 +85,7 @@ internal sealed class QuestValidationWindow : LWindow
ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
}
}
ImGui.SameLine();
ImGui.TextUnformatted(validationIssue.Description);
}