diff --git a/QuestPathGenerator/QuestPathGenerator.csproj b/QuestPathGenerator/QuestPathGenerator.csproj
index b62d2878..ffeca7c1 100644
--- a/QuestPathGenerator/QuestPathGenerator.csproj
+++ b/QuestPathGenerator/QuestPathGenerator.csproj
@@ -16,6 +16,9 @@
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -29,9 +32,16 @@
+
+ $(GetTargetPathDependsOn);GetDependencyTargetPaths
+
+
+
+
+
diff --git a/QuestPathGenerator/QuestSourceGenerator.cs b/QuestPathGenerator/QuestSourceGenerator.cs
index 8d2f37ed..9a647cf4 100644
--- a/QuestPathGenerator/QuestSourceGenerator.cs
+++ b/QuestPathGenerator/QuestSourceGenerator.cs
@@ -1,8 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
+using System.Text.Json.Nodes;
+using Json.Schema;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -17,8 +21,16 @@ namespace Questionable.QuestPathGenerator;
/// When using a simple text file as a baseline, we can create a non-incremental source generator.
///
[Generator]
+[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008")]
public class QuestSourceGenerator : ISourceGenerator
{
+ private static readonly DiagnosticDescriptor InvalidJson = new("QSG0001",
+ "Invalid JSON",
+ "Invalid quest file {0}",
+ nameof(QuestSourceGenerator),
+ DiagnosticSeverity.Error,
+ true);
+
public void Initialize(GeneratorInitializationContext context)
{
// No initialization required for this generator.
@@ -28,10 +40,15 @@ public class QuestSourceGenerator : ISourceGenerator
{
List<(ushort, QuestData)> quests = [];
+ // Find schema definition
+ AdditionalText jsonSchemaFile =
+ context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "quest-v1.json");
+ var questSchema = JsonSchema.FromText(jsonSchemaFile.GetText()!.ToString());
+
// Go through all files marked as an Additional File in file properties.
foreach (var additionalFile in context.AdditionalFiles)
{
- if (additionalFile == null)
+ if (additionalFile == null || additionalFile == jsonSchemaFile)
continue;
if (Path.GetExtension(additionalFile.Path) != ".json")
@@ -44,7 +61,21 @@ public class QuestSourceGenerator : ISourceGenerator
if (text == null)
continue;
- var quest = JsonSerializer.Deserialize(text.ToString())!;
+ var questNode = JsonNode.Parse(text.ToString());
+ var evaluationResult = questSchema.Evaluate(questNode, new EvaluationOptions()
+ {
+ Culture = CultureInfo.InvariantCulture,
+ OutputFormat = OutputFormat.List
+ });
+ if (!evaluationResult.IsValid)
+ {
+ var error = Diagnostic.Create(InvalidJson,
+ null,
+ Path.GetFileName(additionalFile.Path));
+ context.ReportDiagnostic(error);
+ }
+
+ var quest = questNode.Deserialize()!;
quests.Add((id, quest));
}
diff --git a/QuestPathGenerator/packages.lock.json b/QuestPathGenerator/packages.lock.json
index a9d05083..c47bf119 100644
--- a/QuestPathGenerator/packages.lock.json
+++ b/QuestPathGenerator/packages.lock.json
@@ -2,6 +2,34 @@
"version": 1,
"dependencies": {
".NETStandard,Version=v2.0": {
+ "Json.More.Net": {
+ "type": "Direct",
+ "requested": "[2.0.1.2, )",
+ "resolved": "2.0.1.2",
+ "contentHash": "uF3QeiaXEfH92emz0/BWUiNtMSfxIIvgynuB0Bf1vF4s8eWTcZitBx9l+g/FDaJk5XxqBv9buQXizXKQcXFG1w==",
+ "dependencies": {
+ "System.Text.Json": "8.0.0"
+ }
+ },
+ "JsonPointer.Net": {
+ "type": "Direct",
+ "requested": "[5.0.0, )",
+ "resolved": "5.0.0",
+ "contentHash": "fm4T5w20AY6C+p5/pJr0vrXRNGgtSfHl34I1LxC9zdPwS9S3j0GiR1Mz/CVPWKDXXGDpCt1APHpCq7kn5adCfA==",
+ "dependencies": {
+ "Humanizer.Core": "2.14.1",
+ "Json.More.Net": "2.0.1.2"
+ }
+ },
+ "JsonSchema.Net": {
+ "type": "Direct",
+ "requested": "[7.0.4, )",
+ "resolved": "7.0.4",
+ "contentHash": "R0Hk2Tr/np4Q1NO8CBjyQsoiD1iFJyEQP20Sw7JnZCNGJoaSBe+g4b+nZqnBXPQhiqY5LGZ8JZwZkRh/eKZhEQ==",
+ "dependencies": {
+ "JsonPointer.Net": "5.0.0"
+ }
+ },
"Microsoft.CodeAnalysis.Analyzers": {
"type": "Direct",
"requested": "[3.3.4, )",
diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj
index 2a204647..e4e034f3 100644
--- a/QuestPaths/QuestPaths.csproj
+++ b/QuestPaths/QuestPaths.csproj
@@ -22,8 +22,10 @@
+
+
diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json
index 9ad2c19b..ac01f715 100644
--- a/QuestPaths/quest-v1.json
+++ b/QuestPaths/quest-v1.json
@@ -400,7 +400,14 @@
"if": {
"properties": {
"InteractionType": {
- "const": "Interact"
+ "anyOf": [
+ {
+ "const": "Interact"
+ },
+ {
+ "const": "SinglePlayerDuty"
+ }
+ ]
}
}
},