using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
-using System.Threading.Tasks;
using Dalamud.Plugin;
-using Json.Schema;
using Microsoft.Extensions.Logging;
using Questionable.Data;
using Questionable.Model;
using Questionable.Model.V1;
using Questionable.QuestPaths;
using Questionable.Validation;
+using Questionable.Validation.Validators;
namespace Questionable.Controller;
private readonly QuestData _questData;
private readonly QuestValidator _questValidator;
private readonly ILogger<QuestRegistry> _logger;
- private readonly JsonSchema _questSchema;
+ private readonly JsonSchemaValidator _jsonSchemaValidator;
private readonly Dictionary<ushort, Quest> _quests = new();
public QuestRegistry(IDalamudPluginInterface pluginInterface, QuestData questData,
- QuestValidator questValidator, ILogger<QuestRegistry> logger)
+ QuestValidator questValidator, JsonSchemaValidator jsonSchemaValidator,
+ ILogger<QuestRegistry> logger)
{
_pluginInterface = pluginInterface;
_questData = questData;
_questValidator = questValidator;
+ _jsonSchemaValidator = jsonSchemaValidator;
_logger = logger;
- _questSchema = JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result;
}
public IEnumerable<Quest> AllQuests => _quests.Values;
public void Reload()
{
- _questValidator.ClearIssues();
+ _questValidator.Reset();
_quests.Clear();
LoadQuestsFromAssembly();
if (questId == null)
return;
- var questNode = JsonNode.Parse(stream);
- Task.Run(() =>
- {
- var evaluationResult = _questSchema.Evaluate(questNode, new EvaluationOptions
- {
- Culture = CultureInfo.InvariantCulture,
- OutputFormat = OutputFormat.List
- });
- if (!evaluationResult.IsValid)
- {
- _questValidator.AddIssue(new ValidationIssue
- {
- QuestId = questId.Value,
- Sequence = null,
- Step = null,
- Severity = EIssueSeverity.Error,
- Description = "JSON Validation failed"
- });
- }
- });
+ var questNode = JsonNode.Parse(stream)!;
+ _jsonSchemaValidator.Enqueue(questId.Value, questNode);
Quest quest = new Quest
{
serviceCollection.AddSingleton(new WindowSystem(nameof(Questionable)));
serviceCollection.AddSingleton((Configuration?)pluginInterface.GetPluginConfig() ?? new Configuration());
+ AddBasicFunctionsAndData(serviceCollection);
+ AddTaskFactories(serviceCollection);
+ AddControllers(serviceCollection);
+ AddWindows(serviceCollection);
+ AddQuestValidators(serviceCollection);
+
+ serviceCollection.AddSingleton<CommandHandler>();
+ serviceCollection.AddSingleton<DalamudInitializer>();
+
+ _serviceProvider = serviceCollection.BuildServiceProvider();
+ _serviceProvider.GetRequiredService<QuestRegistry>().Reload();
+ _serviceProvider.GetRequiredService<CommandHandler>();
+ _serviceProvider.GetRequiredService<DalamudInitializer>();
+ }
+
+ private static void AddBasicFunctionsAndData(ServiceCollection serviceCollection)
+ {
serviceCollection.AddSingleton<GameFunctions>();
serviceCollection.AddSingleton<ChatFunctions>();
serviceCollection.AddSingleton<AetherCurrentData>();
serviceCollection.AddSingleton<NavmeshIpc>();
serviceCollection.AddSingleton<LifestreamIpc>();
serviceCollection.AddSingleton<YesAlreadyIpc>();
+ }
+ private static void AddTaskFactories(ServiceCollection serviceCollection)
+ {
// individual tasks
serviceCollection.AddTransient<MountTask>();
serviceCollection.AddTransient<UnmountTask>();
- // tasks with factories
+ // task factories
serviceCollection.AddTaskWithFactory<StepDisabled.Factory, StepDisabled.Task>();
serviceCollection.AddTaskWithFactory<AetheryteShortcut.Factory, AetheryteShortcut.UseAetheryteShortcut>();
serviceCollection.AddTaskWithFactory<SkipCondition.Factory, SkipCondition.CheckTask>();
WaitAtEnd.WaitObjectAtPosition>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestAccepted>();
serviceCollection.AddTransient<WaitAtEnd.WaitQuestCompleted>();
+ }
+ private static void AddControllers(ServiceCollection serviceCollection)
+ {
serviceCollection.AddSingleton<MovementController>();
serviceCollection.AddSingleton<MovementOverrideController>();
serviceCollection.AddSingleton<QuestRegistry>();
serviceCollection.AddSingleton<CombatController>();
serviceCollection.AddSingleton<ICombatModule, RotationSolverRebornModule>();
+ }
+ private static void AddWindows(ServiceCollection serviceCollection)
+ {
serviceCollection.AddSingleton<QuestWindow>();
serviceCollection.AddSingleton<ConfigWindow>();
serviceCollection.AddSingleton<DebugOverlay>();
serviceCollection.AddSingleton<QuestSelectionWindow>();
serviceCollection.AddSingleton<QuestValidationWindow>();
+ }
+ private static void AddQuestValidators(ServiceCollection serviceCollection)
+ {
serviceCollection.AddSingleton<QuestValidator>();
serviceCollection.AddSingleton<IQuestValidator, QuestDisabledValidator>();
serviceCollection.AddSingleton<IQuestValidator, BasicSequenceValidator>();
serviceCollection.AddSingleton<IQuestValidator, UniqueStartStopValidator>();
serviceCollection.AddSingleton<IQuestValidator, NextQuestValidator>();
serviceCollection.AddSingleton<IQuestValidator, CompletionFlagsValidator>();
-
- serviceCollection.AddSingleton<CommandHandler>();
- serviceCollection.AddSingleton<DalamudInitializer>();
-
- _serviceProvider = serviceCollection.BuildServiceProvider();
- _serviceProvider.GetRequiredService<QuestRegistry>().Reload();
- _serviceProvider.GetRequiredService<CommandHandler>();
- _serviceProvider.GetRequiredService<DalamudInitializer>();
+ serviceCollection.AddSingleton<JsonSchemaValidator>();
+ serviceCollection.AddSingleton<IQuestValidator>(sp => sp.GetRequiredService<JsonSchemaValidator>());
}
public void Dispose()
internal interface IQuestValidator
{
IEnumerable<ValidationIssue> Validate(Quest quest);
+
+ void Reset()
+ {
+ }
}
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Questionable.Model;
public int IssueCount => _validationIssues.Count;
public int ErrorCount => _validationIssues.Count(x => x.Severity == EIssueSeverity.Error);
- public void ClearIssues() => _validationIssues.Clear();
+ public void Reset()
+ {
+ foreach (var validator in _validators)
+ validator.Reset();
+ _validationIssues.Clear();
+ }
public void Validate(IEnumerable<Quest> quests)
{
- Task.Run(() =>
+ Task.Factory.StartNew(() =>
{
foreach (var quest in quests)
{
.ThenBy(x => x.Step)
.ThenBy(x => x.Description)
.ToList();
- });
+ }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
-
- public void AddIssue(ValidationIssue issue) => _validationIssues.Add(issue);
}
--- /dev/null
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text.Json.Nodes;
+using Json.Schema;
+using Questionable.Model;
+using Questionable.QuestPaths;
+
+namespace Questionable.Validation.Validators;
+
+internal sealed class JsonSchemaValidator : IQuestValidator
+{
+ private readonly Dictionary<ushort, JsonNode> _questNodes = new();
+ private JsonSchema? _questSchema;
+
+ public IEnumerable<ValidationIssue> Validate(Quest quest)
+ {
+ _questSchema ??= JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result;
+
+ if (_questNodes.TryGetValue(quest.QuestId, out JsonNode? questNode))
+ {
+ var evaluationResult = _questSchema.Evaluate(questNode, new EvaluationOptions
+ {
+ Culture = CultureInfo.InvariantCulture,
+ OutputFormat = OutputFormat.List
+ });
+ if (!evaluationResult.IsValid)
+ {
+ yield return new ValidationIssue
+ {
+ QuestId = quest.QuestId,
+ Sequence = null,
+ Step = null,
+ Severity = EIssueSeverity.Error,
+ Description = "JSON Validation failed"
+ };
+ }
+ }
+
+ }
+
+ public void Enqueue(ushort questId, JsonNode questNode) => _questNodes[questId] = questNode;
+
+ public void Reset() => _questNodes.Clear();
+}