From: Liza Carvelli Date: Fri, 2 Aug 2024 16:30:21 +0000 (+0200) Subject: Schema update X-Git-Tag: v2.0~4^2~4 X-Git-Url: https://git.jacobcasper.com/?a=commitdiff_plain;h=ae87b4ccc5772913006b43d4477633119cd96b30;p=Questionable.git Schema update --- diff --git a/GatheringPathRenderer/GatheringPathRenderer.csproj b/GatheringPathRenderer/GatheringPathRenderer.csproj new file mode 100644 index 00000000..5d22cd3f --- /dev/null +++ b/GatheringPathRenderer/GatheringPathRenderer.csproj @@ -0,0 +1,3 @@ + + + diff --git a/GatheringPathRenderer/RendererPlugin.cs b/GatheringPathRenderer/RendererPlugin.cs new file mode 100644 index 00000000..d33eae96 --- /dev/null +++ b/GatheringPathRenderer/RendererPlugin.cs @@ -0,0 +1,11 @@ +using Dalamud.Plugin; + +namespace GatheringPathRenderer; + +public sealed class RendererPlugin : IDalamudPlugin +{ + public void Dispose() + { + + } +} diff --git a/GatheringPathRenderer/packages.lock.json b/GatheringPathRenderer/packages.lock.json new file mode 100644 index 00000000..0c669ebf --- /dev/null +++ b/GatheringPathRenderer/packages.lock.json @@ -0,0 +1,81 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "DalamudPackager": { + "type": "Direct", + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "rMN1omGe8536f4xLMvx9NwfvpAc9YFFfeXJ1t4P4PE6Gu8WCIoFliR1sh07hM+bfODmesk/dvMbji7vNI+B/pQ==" + }, + "DotNet.ReproducibleBuilds": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "+H2t/t34h6mhEoUvHi8yGXyuZ2GjSovcGYehJrS2MDm2XgmPfZL2Sdxg+uL2lKgZ4M6tTwKHIlxOob2bgh0NRQ==", + "dependencies": { + "Microsoft.SourceLink.AzureRepos.Git": "1.1.1", + "Microsoft.SourceLink.Bitbucket.Git": "1.1.1", + "Microsoft.SourceLink.GitHub": "1.1.1", + "Microsoft.SourceLink.GitLab": "1.1.1" + } + }, + "Microsoft.SourceLink.Gitea": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "KOBodmDnlWGIqZt2hT47Q69TIoGhIApDVLCyyj9TT5ct8ju16AbHYcB4XeknoHX562wO1pMS/1DfBIZK+V+sxg==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "8.0.0", + "Microsoft.SourceLink.Common": "8.0.0" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" + }, + "Microsoft.SourceLink.AzureRepos.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "qB5urvw9LO2bG3eVAkuL+2ughxz2rR7aYgm2iyrB8Rlk9cp2ndvGRCvehk3rNIhRuNtQaeKwctOl1KvWiklv5w==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.Bitbucket.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "cDzxXwlyWpLWaH0em4Idj0H3AmVo3L/6xRXKssYemx+7W52iNskj/SQ4FOmfCb8YQt39otTDNMveCZzYtMoucQ==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" + }, + "Microsoft.SourceLink.GitHub": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.SourceLink.GitLab": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "tvsg47DDLqqedlPeYVE2lmiTpND8F0hkrealQ5hYltSmvruy/Gr5nHAKSsjyw5L3NeM/HLMI5ORv7on/M4qyZw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + } + } + } +} \ No newline at end of file diff --git a/GatheringPaths/2.x - A Realm Reborn/.gitkeep b/GatheringPaths/2.x - A Realm Reborn/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/3.x - Heavensward/.gitkeep b/GatheringPaths/3.x - Heavensward/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/4.x - Stormblood/.gitkeep b/GatheringPaths/4.x - Stormblood/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/5.x - Shadowbringers/.gitkeep b/GatheringPaths/5.x - Shadowbringers/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json new file mode 100644 index 00000000..425d77eb --- /dev/null +++ b/GatheringPaths/6.x - Endwalker/Thavnair/820_Pewter Ore.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "Author": "liza", + "TerritoryId": 957, + "AetheryteShortcut": "Thavnair - Great Work", + "Nodes": [ + { + "DataId": 33918, + "Position": { + "X": -582.5132, + "Y": 40.54578, + "Z": -426.0171 + } + }, + { + "DataId": 33919, + "Position": { + "X": -578.2101, + "Y": 41.27147, + "Z": -447.6376 + } + }, + { + "DataId": 33920, + "Position": { + "X": -488.2276, + "Y": 34.71221, + "Z": -359.6945 + } + }, + { + "DataId": 33921, + "Position": { + "X": -498.8687, + "Y": 31.08014, + "Z": -351.9397 + } + }, + { + "DataId": 33922, + "Position": { + "X": -304.0609, + "Y": 68.76999, + "Z": -479.1875 + } + }, + { + "DataId": 33923, + "Position": { + "X": -293.6989, + "Y": 68.77935, + "Z": -484.2256 + } + } + ] +} diff --git a/GatheringPaths/7.x - Dawntrail/.gitkeep b/GatheringPaths/7.x - Dawntrail/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/GatheringPaths/AssemblyGatheringLocationLoader.cs b/GatheringPaths/AssemblyGatheringLocationLoader.cs new file mode 100644 index 00000000..04176410 --- /dev/null +++ b/GatheringPaths/AssemblyGatheringLocationLoader.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using Questionable.Model.Gathering; + +namespace Questionable.GatheringPaths; + +[SuppressMessage("ReSharper", "PartialTypeWithSinglePart", Justification = "Required for RELEASE")] +public static partial class AssemblyGatheringLocationLoader +{ + private static Dictionary? _locations; + + public static IReadOnlyDictionary GetLocations() + { + if (_locations == null) + { + _locations = []; +#if RELEASE + LoadLocations(); +#endif + } + + return _locations ?? throw new InvalidOperationException("quest data is not initialized"); + } + + public static Stream QuestSchema => + typeof(AssemblyGatheringLocationLoader).Assembly.GetManifestResourceStream("Questionable.GatheringPaths.GatheringLocationSchema")!; + + [SuppressMessage("ReSharper", "UnusedMember.Local")] + private static void AddLocation(ushort questId, GatheringRoot root) => _locations![questId] = root; +} diff --git a/GatheringPaths/GatheringPaths.csproj b/GatheringPaths/GatheringPaths.csproj new file mode 100644 index 00000000..f9e9725f --- /dev/null +++ b/GatheringPaths/GatheringPaths.csproj @@ -0,0 +1,43 @@ + + + net8.0-windows + 12 + enable + Questionable.GatheringPaths + true + true + none + $(SolutionDir)=X:\ + true + x64 + + + + + + + + + + + Questionable.GatheringPaths.GatheringLocationSchema + + + + + + + + + + + + + + + + + + + + diff --git a/GatheringPaths/gatheringlocation-v1.json b/GatheringPaths/gatheringlocation-v1.json new file mode 100644 index 00000000..53b34f74 --- /dev/null +++ b/GatheringPaths/gatheringlocation-v1.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json", + "title": "Gathering Location V1", + "description": "A series of gathering locationsk", + "type": "object", + "properties": { + "$schema": { + "type": "string", + "const": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json" + }, + "Author": { + "description": "Author of the gathering location data", + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + } + }, + "TerritoryId": { + "type": "number" + }, + "AetheryteShortcut": { + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" + }, + "Nodes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "DataId": { + "type": "number", + "minimum": 30000, + "maximum": 50000 + }, + "Position": { + "$ref": "#/$defs/Vector3" + }, + "MinimumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MaximumAngle": { + "type": "number", + "minimum": -360, + "maximum": 360 + }, + "MinimumDistance": { + "type": "number", + "minimum": 0 + }, + "MaximumDistance": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "required": [ + "DataId", + "Position" + ], + "additionalProperties": false + } + } + }, + "required": [ + "$schema", + "Author", + "TerritoryId", + "AetheryteShortcut", + "Nodes" + ], + "additionalProperties": false, + "$defs": { + "Vector3": { + "type": "object", + "description": "Position to (typically) walk to", + "properties": { + "X": { + "type": "number" + }, + "Y": { + "type": "number" + }, + "Z": { + "type": "number" + } + }, + "required": [ + "X", + "Y", + "Z" + ] + } + } +} diff --git a/GatheringPaths/packages.lock.json b/GatheringPaths/packages.lock.json new file mode 100644 index 00000000..408e267a --- /dev/null +++ b/GatheringPaths/packages.lock.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "dependencies": { + "net8.0-windows7.0": { + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.4", + "contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.4, )" + } + } + } + } +} \ No newline at end of file diff --git a/QuestPathGenerator.Tests/QuestGeneratorTest.cs b/QuestPathGenerator.Tests/QuestGeneratorTest.cs index 55d4cd64..f08606c1 100644 --- a/QuestPathGenerator.Tests/QuestGeneratorTest.cs +++ b/QuestPathGenerator.Tests/QuestGeneratorTest.cs @@ -1,4 +1,4 @@ -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.QuestPathGenerator; using Xunit; diff --git a/QuestPathGenerator/GatheringSourceGenerator.cs b/QuestPathGenerator/GatheringSourceGenerator.cs new file mode 100644 index 00000000..a10acd0e --- /dev/null +++ b/QuestPathGenerator/GatheringSourceGenerator.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; +using System.Text.Json; +using Json.Schema; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Questionable.Model.Gathering; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Questionable.QuestPathGenerator.RoslynShortcuts; + +namespace Questionable.QuestPathGenerator; + +[Generator] +[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008")] +public class GatheringSourceGenerator : ISourceGenerator +{ + private static readonly DiagnosticDescriptor InvalidJson = new("GPG0001", + "Invalid JSON", + "Invalid gathering file: {0}", + nameof(GatheringSourceGenerator), + DiagnosticSeverity.Error, + true); + + public void Initialize(GeneratorInitializationContext context) + { + // No initialization required for this generator. + } + + public void Execute(GeneratorExecutionContext context) + { + // Find schema definition + AdditionalText? gatheringSchema = + context.AdditionalFiles.SingleOrDefault(x => Path.GetFileName(x.Path) == "gatheringlocation-v1.json"); + if (gatheringSchema != null) + GenerateGatheringSource(context, gatheringSchema); + } + + private void GenerateGatheringSource(GeneratorExecutionContext context, AdditionalText jsonSchemaFile) + { + var gatheringSchema = JsonSchema.FromText(jsonSchemaFile.GetText()!.ToString()); + + List<(ushort, GatheringRoot)> gatheringLocations = []; + foreach (var (id, node) in Utils.GetAdditionalFiles(context, jsonSchemaFile, gatheringSchema, InvalidJson)) + { + var gatheringLocation = node.Deserialize()!; + gatheringLocations.Add((id, gatheringLocation)); + } + + if (gatheringLocations.Count == 0) + return; + + var partitionedLocations = gatheringLocations + .OrderBy(x => x.Item1) + .GroupBy(x => $"LoadLocation{x.Item1 / 100}") + .ToList(); + + var methods = Utils.CreateMethods("LoadLocations", partitionedLocations, CreateInitializer); + + var code = + CompilationUnit() + .WithUsings( + List( + new[] + { + UsingDirective( + IdentifierName("System")), + UsingDirective( + QualifiedName( + IdentifierName("System"), + IdentifierName("Numerics"))), + UsingDirective( + QualifiedName( + IdentifierName("System"), + IdentifierName("IO"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("System"), IdentifierName("Collections")), + IdentifierName("Generic"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Gathering"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Common"))) + })) + .WithMembers( + SingletonList( + FileScopedNamespaceDeclaration( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("GatheringPaths"))) + .WithMembers( + SingletonList( + ClassDeclaration("AssemblyGatheringLocationLoader") + .WithModifiers( + TokenList(Token(SyntaxKind.PartialKeyword))) + .WithMembers(List(methods)))))) + .NormalizeWhitespace(); + + // Add the source code to the compilation. + context.AddSource("AssemblyGatheringLocationLoader.g.cs", code.ToFullString()); + } + + private static StatementSyntax[] CreateInitializer(List<(ushort QuestId, GatheringRoot Root)> quests) + { + List statements = []; + + foreach (var quest in quests) + { + statements.Add( + ExpressionStatement( + InvocationExpression( + IdentifierName("AddLocation")) + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Argument( + LiteralExpression(SyntaxKind.NumericLiteralExpression, + Literal(quest.QuestId))), + Token(SyntaxKind.CommaToken), + Argument(CreateGatheringRootExpression(quest.QuestId, quest.Root)) + }))))); + } + + return statements.ToArray(); + } + + private static ObjectCreationExpressionSyntax CreateGatheringRootExpression(ushort locationId, GatheringRoot root) + { + try + { + return ObjectCreationExpression( + IdentifierName(nameof(GatheringRoot))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + AssignmentList(nameof(GatheringRoot.Author), root.Author).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, default) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut, null), + AssignmentList(nameof(GatheringRoot.Nodes), root.Nodes).AsSyntaxNodeOrToken())))); + } + catch (Exception e) + { + throw new Exception($"GatheringGen[{locationId}]: {e.Message}", e); + } + } +} diff --git a/QuestPathGenerator/QuestSourceGenerator.cs b/QuestPathGenerator/QuestSourceGenerator.cs index 47d311f2..b6cccbab 100644 --- a/QuestPathGenerator/QuestSourceGenerator.cs +++ b/QuestPathGenerator/QuestSourceGenerator.cs @@ -1,16 +1,14 @@ 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; -using Questionable.Model.V1; +using Questionable.Model.Questing; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; using static Questionable.QuestPathGenerator.RoslynShortcuts; @@ -38,47 +36,21 @@ public class QuestSourceGenerator : ISourceGenerator public void Execute(GeneratorExecutionContext context) { - List<(ushort, QuestRoot)> quests = []; - // Find schema definition - AdditionalText jsonSchemaFile = - context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "quest-v1.json"); + AdditionalText? questSchema = + context.AdditionalFiles.SingleOrDefault(x => Path.GetFileName(x.Path) == "quest-v1.json"); + if (questSchema != null) + GenerateQuestSource(context, questSchema); + } + + private void GenerateQuestSource(GeneratorExecutionContext context, AdditionalText jsonSchemaFile) + { 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) + List<(ushort, QuestRoot)> quests = []; + foreach (var (id, node) in Utils.GetAdditionalFiles(context, jsonSchemaFile, questSchema, InvalidJson)) { - if (additionalFile == null || additionalFile == jsonSchemaFile) - continue; - - if (Path.GetExtension(additionalFile.Path) != ".json") - continue; - - string name = Path.GetFileName(additionalFile.Path); - if (!name.Contains('_')) - continue; - - ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_'))); - - var text = additionalFile.GetText(); - if (text == null) - continue; - - 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()!; + var quest = node.Deserialize()!; if (quest.Disabled) { quest.Author = []; @@ -97,38 +69,7 @@ public class QuestSourceGenerator : ISourceGenerator .GroupBy(x => $"LoadQuests{x.Item1 / 50}") .ToList(); - List methods = - [ - MethodDeclaration( - PredefinedType( - Token(SyntaxKind.VoidKeyword)), - Identifier("LoadQuests")) - .WithModifiers( - TokenList( - Token(SyntaxKind.PrivateKeyword), - Token(SyntaxKind.StaticKeyword))) - .WithBody( - Block( - partitionedQuests - .Select(x => - ExpressionStatement( - InvocationExpression( - IdentifierName(x.Key)))))) - ]; - - foreach (var partition in partitionedQuests) - { - methods.Add(MethodDeclaration( - PredefinedType( - Token(SyntaxKind.VoidKeyword)), - Identifier(partition.Key)) - .WithModifiers( - TokenList( - Token(SyntaxKind.PrivateKeyword), - Token(SyntaxKind.StaticKeyword))) - .WithBody( - Block(CreateInitializer(partition.ToList())))); - } + var methods = Utils.CreateMethods("LoadQuests", partitionedQuests, CreateInitializer); var code = CompilationUnit() @@ -156,7 +97,13 @@ public class QuestSourceGenerator : ISourceGenerator QualifiedName( IdentifierName("Questionable"), IdentifierName("Model")), - IdentifierName("V1"))) + IdentifierName("Questing"))), + UsingDirective( + QualifiedName( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("Model")), + IdentifierName("Common"))) })) .WithMembers( SingletonList( diff --git a/QuestPathGenerator/RoslynShortcuts.cs b/QuestPathGenerator/RoslynShortcuts.cs index 2bacaba4..4f5a8fb0 100644 --- a/QuestPathGenerator/RoslynShortcuts.cs +++ b/QuestPathGenerator/RoslynShortcuts.cs @@ -6,7 +6,9 @@ using System.Numerics; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Gathering; +using Questionable.Model.Questing; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace Questionable.QuestPathGenerator; @@ -312,6 +314,32 @@ public static class RoslynShortcuts Assignment(nameof(SkipAetheryteCondition.InSameTerritory), skipAetheryteCondition.InSameTerritory, emptyAetheryte.InSameTerritory))))); } + else if (value is GatheringNodeLocation nodeLocation) + { + var emptyLocation = new GatheringNodeLocation(); + return ObjectCreationExpression( + IdentifierName(nameof(GatheringNodeLocation))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(GatheringNodeLocation.DataId), nodeLocation.DataId, + emptyLocation.DataId) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.Position), nodeLocation.Position, + emptyLocation.Position).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MinimumAngle), nodeLocation.MinimumAngle, + emptyLocation.MinimumAngle).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MaximumAngle), nodeLocation.MaximumAngle, + emptyLocation.MaximumAngle).AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MinimumDistance), + nodeLocation.MinimumDistance, emptyLocation.MinimumDistance) + .AsSyntaxNodeOrToken(), + Assignment(nameof(GatheringNodeLocation.MaximumDistance), + nodeLocation.MaximumDistance, emptyLocation.MaximumDistance) + .AsSyntaxNodeOrToken())))); + } else if (value is null) return LiteralExpression(SyntaxKind.NullLiteralExpression); } diff --git a/QuestPathGenerator/Utils.cs b/QuestPathGenerator/Utils.cs new file mode 100644 index 00000000..12873a71 --- /dev/null +++ b/QuestPathGenerator/Utils.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.Json.Nodes; +using Json.Schema; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Questionable.QuestPathGenerator; + +public static class Utils +{ + public static IEnumerable<(ushort, JsonNode)> GetAdditionalFiles(GeneratorExecutionContext context, + AdditionalText jsonSchemaFile, JsonSchema jsonSchema, DiagnosticDescriptor invalidJson) + { + var commonSchemaFile = context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "common-schema.json"); + List jsonSchemaFiles = [jsonSchemaFile, commonSchemaFile]; + + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json"), + JsonSchema.FromText(commonSchemaFile.GetText()!.ToString())); + + foreach (var additionalFile in context.AdditionalFiles) + { + if (additionalFile == null || jsonSchemaFiles.Contains(additionalFile)) + continue; + + if (Path.GetExtension(additionalFile.Path) != ".json") + continue; + + string name = Path.GetFileName(additionalFile.Path); + if (!name.Contains("_")) + continue; + + ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_'))); + + var text = additionalFile.GetText(); + if (text == null) + continue; + + var node = JsonNode.Parse(text.ToString()); + if (node == null) + continue; + + string? schemaLocation = node["$schema"]?.GetValue(); + if (schemaLocation == null || new Uri(schemaLocation) != jsonSchema.GetId()) + continue; + + var evaluationResult = jsonSchema.Evaluate(node, new EvaluationOptions + { + Culture = CultureInfo.InvariantCulture, + OutputFormat = OutputFormat.List, + }); + if (!evaluationResult.IsValid) + { + var error = Diagnostic.Create(invalidJson, + null, + Path.GetFileName(additionalFile.Path)); + context.ReportDiagnostic(error); + } + + yield return (id, node); + } + } + + public static List CreateMethods(string prefix, + List> partitions, + Func, StatementSyntax[]> toInitializers) + { + List methods = + [ + MethodDeclaration( + PredefinedType( + Token(SyntaxKind.VoidKeyword)), + Identifier(prefix)) + .WithModifiers( + TokenList( + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword))) + .WithBody( + Block( + partitions + .Select(x => + ExpressionStatement( + InvocationExpression( + IdentifierName(x.Key)))))) + ]; + + foreach (var partition in partitions) + { + methods.Add(MethodDeclaration( + PredefinedType( + Token(SyntaxKind.VoidKeyword)), + Identifier(partition.Key)) + .WithModifiers( + TokenList( + Token(SyntaxKind.PrivateKeyword), + Token(SyntaxKind.StaticKeyword))) + .WithBody( + Block(toInitializers(partition.ToList())))); + } + + return methods; + } +} diff --git a/QuestPaths/AssemblyQuestLoader.cs b/QuestPaths/AssemblyQuestLoader.cs index 90ba89a1..3ef7df15 100644 --- a/QuestPaths/AssemblyQuestLoader.cs +++ b/QuestPaths/AssemblyQuestLoader.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Reflection; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.QuestPaths; diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj index e914b62d..5d91a016 100644 --- a/QuestPaths/QuestPaths.csproj +++ b/QuestPaths/QuestPaths.csproj @@ -23,6 +23,7 @@ Questionable.QuestPaths.QuestSchema + diff --git a/QuestPaths/quest-v1.json b/QuestPaths/quest-v1.json index 751e4730..a11a610c 100644 --- a/QuestPaths/quest-v1.json +++ b/QuestPaths/quest-v1.json @@ -154,7 +154,7 @@ }, "AetheryteShortcut": { "description": "The Aetheryte to teleport to (before moving)", - "$ref": "#/$defs/Aetheryte" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" }, "AethernetShortcut": { "type": "array", @@ -162,7 +162,7 @@ "minItems": 2, "maxItems": 2, "items": { - "$ref": "#/$defs/AethernetShard" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard" } }, "ItemId": { @@ -183,7 +183,7 @@ "type": "boolean" }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "Flying": { "type": "string", @@ -271,7 +271,7 @@ "additionalProperties": false }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "RequiredQuestVariables": { "type": "array", @@ -383,7 +383,7 @@ "then": { "properties": { "Aetheryte": { - "$ref": "#/$defs/Aetheryte" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" }, "DataId": { "type": "null" @@ -415,7 +415,7 @@ "then": { "properties": { "AethernetShard": { - "$ref": "#/$defs/AethernetShard" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/AethernetShard" }, "DataId": { "type": "null" @@ -507,7 +507,7 @@ "type": "integer" }, "CompletionQuestVariablesFlags": { - "$ref": "#/$defs/CompletionFlags" + "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/CompletionFlags" }, "IgnoreQuestMarker": { "type": "boolean" @@ -1073,300 +1073,5 @@ "QuestSequence", "Author" ], - "additionalProperties": false, - "$defs": { - "Aetheryte": { - "type": "string", - "enum": [ - "Gridania", - "Central Shroud - Bentbranch Meadows", - "East Shroud - Hawthorne Hut", - "South Shroud - Quarrymill", - "South Shroud - Camp Tranquil", - "North Shroud - Fallgourd Float", - "Ul'dah", - "Western Thanalan - Horizon", - "Central Thanalan - Black Brush Station", - "Eastern Thanalan - Camp Drybone", - "Southern Thanalan - Little Ala Mhigo", - "Southern Thanalan - Forgotten Springs", - "Northern Thanalan - Camp Bluefog", - "Northern Thanalan - Ceruleum Processing Plant", - "Limsa Lominsa", - "Middle La Noscea - Summerford Farms", - "Lower La Noscea - Moraby Drydocks", - "Eastern La Noscea - Costa Del Sol", - "Eastern La Noscea - Wineport", - "Western La Noscea - Swiftperch", - "Western La Noscea - Aleport", - "Upper La Noscea - Camp Bronze Lake", - "Outer La Noscea - Camp Overlook", - "Coerthas Central Highlands - Camp Dragonhead", - "Mor Dhona", - "Gold Saucer", - "Wolves' Den Pier", - "Ishgard", - "Idyllshire", - "Coerthas Western Highlands - Falcon's Nest", - "The Sea of Clouds - Camp Cloudtop", - "The Sea of Clouds - Ok' Zundu", - "Azys Lla - Helix", - "The Dravanian Forelands - Tailfeather", - "The Dravanian Forelands - Anyx Trine", - "The Churning Mists - Moghome", - "The Churning Mists - Zenith", - "Rhalgr's Reach", - "Fringes - Castrum Oriens", - "Fringes - Peering Stones", - "Peaks - Ala Gannha", - "Peaks - Ala Ghiri", - "Lochs - Porta Praetoria", - "Lochs - Ala Mhigan Quarter", - "Kugane", - "Ruby Sea - Tamamizu", - "Ruby Sea - Onokoro", - "Yanxia - Namai", - "Yanxia - House of the Fierce", - "Azim Steppe - Reunion", - "Azim Steppe - Dawn Throne", - "Azim Steppe - Dhoro Iloh", - "Doman Enclave", - "Crystarium", - "Eulmore", - "Lakeland - Fort Jobb", - "Lakeland - Ostall Imperative", - "Kholusia - Stilltide", - "Kholusia - Wright", - "Kholusia - Tomra", - "Amh Araeng - Mord Souq", - "Amh Araeng - Inn at Journey's Head", - "Amh Araeng - Twine", - "Rak'tika - Slitherbough", - "Rak'tika - Fanow", - "Il Mheg - Lydha Lran", - "Il Mheg - Pia Enni", - "Il Mheg - Wolekdorf", - "Tempest - Ondo Cups", - "Tempest - Macarenses Angle", - "Old Sharlayan", - "Radz-at-Han", - "Labyrinthos - Archeion", - "Labyrinthos - Sharlayan Hamlet", - "Labyrinthos - Aporia", - "Thavnair - Yedlihmad", - "Thavnair - Great Work", - "Thavnair - Palaka's Stand", - "Garlemald - Camp Broken Glass", - "Garlemald - Tertium", - "Mare Lamentorum - Sinus Lacrimarum", - "Mare Lamentorum - Bestways Burrow", - "Elpis - Anagnorisis", - "Elpis - Twelve Wonders", - "Elpis - Poieten Oikos", - "Ultima Thule - Reah Tahra", - "Ultima Thule - Abode of the Ea", - "Ultima Thule - Base Omicron", - "Tuliyollal", - "Solution Nine", - "Urqopacha - Wachunpelo", - "Urqopacha - Worlar's Echo", - "Kozama'uka - Ok'hanu", - "Kozama'uka - Many Fires", - "Kozama'uka - Earthenshire", - "Yak T'el - Iq Br'aax", - "Yak T'el - Mamook", - "Shaaloani - Hhusatahwi", - "Shaaloani - Sheshenewezi Springs", - "Shaaloani - Mehwahhetsoan", - "Heritage Found - Yyasulani Station", - "Heritage Found - The Outskirts", - "Heritage Found - Electrope Strike", - "Living Memory - Leynode Mnemo", - "Living Memory - Leynode Pyro", - "Living Memory - Leynode Aero" - ] - }, - "AethernetShard": { - "type": "string", - "enum": [ - "[Gridania] Aetheryte Plaza", - "[Gridania] Archers' Guild", - "[Gridania] Leatherworkers' Guild & Shaded Bower", - "[Gridania] Lancers' Guild", - "[Gridania] Conjurers' Guild", - "[Gridania] Botanists' Guild", - "[Gridania] Mih Khetto's Amphitheatre", - "[Gridania] Blue Badger Gate (Central Shroud)", - "[Gridania] Yellow Serpent Gate (North Shroud)", - "[Gridania] White Wolf Gate (Central Shroud)", - "[Gridania] Airship Landing", - "[Ul'dah] Aetheryte Plaza", - "[Ul'dah] Adventurers' Guild", - "[Ul'dah] Thaumaturges' Guild", - "[Ul'dah] Gladiators' Guild", - "[Ul'dah] Miners' Guild", - "[Ul'dah] Weavers' Guild", - "[Ul'dah] Goldsmiths' Guild", - "[Ul'dah] Sapphire Avenue Exchange", - "[Ul'dah] Alchemists' Guild", - "[Ul'dah] Gate of the Sultana (Western Thanalan)", - "[Ul'dah] Gate of Nald (Central Thanalan)", - "[Ul'dah] Gate of Thal (Central Thanalan)", - "[Ul'dah] The Chamber of Rule", - "[Ul'dah] Airship Landing", - "[Limsa Lominsa] Aetheryte Plaza", - "[Limsa Lominsa] Arcanists' Guild", - "[Limsa Lominsa] Fishermens' Guild", - "[Limsa Lominsa] Hawkers' Alley", - "[Limsa Lominsa] The Aftcastle", - "[Limsa Lominsa] Culinarians' Guild", - "[Limsa Lominsa] Marauders' Guild", - "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)", - "[Limsa Lominsa] Tempest Gate (Lower La Noscea)", - "[Limsa Lominsa] Airship Landing", - "[Ishgard] Aetheryte Plaza", - "[Ishgard] The Forgotten Knight", - "[Ishgard] Skysteel Manufactory", - "[Ishgard] The Brume", - "[Ishgard] Athenaeum Astrologicum", - "[Ishgard] The Jeweled Crozier", - "[Ishgard] Saint Reymanaud's Cathedral", - "[Ishgard] The Tribunal", - "[Ishgard] The Last Vigil", - "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)", - "[Idyllshire] Aetheryte Plaza", - "[Idyllshire] West Idyllshire", - "[Idyllshire] Prologue Gate (Western Hinterlands)", - "[Idyllshire] Epilogue Gate (Eastern Hinterlands)", - "[Rhalgr's Reach] Aetheryte Plaza", - "[Rhalgr's Reach] Western Rhalgr's Reach", - "[Rhalgr's Reach] Northeastern Rhalgr's Reach", - "[Rhalgr's Reach] Fringes Gate", - "[Rhalgr's Reach] Peaks Gate", - "[Kugane] Aetheryte Plaza", - "[Kugane] Shiokaze Hostelry", - "[Kugane] Pier #1", - "[Kugane] Thavnairian Consulate", - "[Kugane] Kogane Dori Markets", - "[Kugane] Bokairo Inn", - "[Kugane] The Ruby Bazaar", - "[Kugane] Sekiseigumi Barracks", - "[Kugane] Rakuza District", - "[Kugane] The Ruby Price", - "[Kugane] Airship Landing", - "[Crystarium] Aetheryte Plaza", - "[Crystarium] Musica Universalis Markets", - "[Crystarium] Temenos Rookery", - "[Crystarium] The Dossal Gate", - "[Crystarium] The Pendants", - "[Crystarium] The Amaro Launch", - "[Crystarium] The Crystalline Mean", - "[Crystarium] The Cabinet of Curiosity", - "[Crystarium] Tessellation (Lakeland)", - "[Eulmore] Aetheryte Plaza", - "[Eulmore] Southeast Derelicts", - "[Eulmore] Nightsoil Pots", - "[Eulmore] The Glory Gate", - "[Eulmore] The Mainstay", - "[Eulmore] The Path to Glory (Kholusia)", - "[Old Sharlayan] Aetheryte Plaza", - "[Old Sharlayan] The Studium", - "[Old Sharlayan] The Baldesion Annex", - "[Old Sharlayan] The Rostra", - "[Old Sharlayan] The Leveilleur Estate", - "[Old Sharlayan] Journey's End", - "[Old Sharlayan] Scholar's Harbor", - "[Old Sharlayan] The Hall of Artifice (Labyrinthos)", - "[Radz-at-Han] Aetheryte Plaza", - "[Radz-at-Han] Meghaduta", - "[Radz-at-Han] Ruveydah Fibers", - "[Radz-at-Han] Airship Landing", - "[Radz-at-Han] Alzadaal's Peace", - "[Radz-at-Han] Hall of the Radiant Host", - "[Radz-at-Han] Mehryde's Meyhane", - "[Radz-at-Han] Kama", - "[Radz-at-Han] The High Crucible of Al-Kimiya", - "[Radz-at-Han] The Gate of First Sight (Thavnair)", - "[Tuliyollal] Aetheryte Plaza", - "[Tuliyollal] Dirigible Landing", - "[Tuliyollal] The Resplendent Quarter", - "[Tuliyollal] The For'ard Cabins", - "[Tuliyollal] Bayside Bevy Marketplace", - "[Tuliyollal] Vollok Shoonsa", - "[Tuliyollal] Wachumeqimeqi", - "[Tuliyollal] Brightploom Post", - "[Tuliyollal] Arch of the Dawn (Urqopacha)", - "[Tuliyollal] Arch of the Dawn (Kozama'uka)", - "[Tuliyollal] Ihuykatumu (Kozama'uka)", - "[Tuliyollal] Dirigible Landing (Yak T'el)", - "[Tuliyollal] Xak Tural Skygate (Shaaloani)", - "[Solution Nine] Aetheryte Plaza", - "[Solution Nine] Information Center", - "[Solution Nine] True Vue", - "[Solution Nine] Neon Stein", - "[Solution Nine] The Arcadion", - "[Solution Nine] Resolution", - "[Solution Nine] Nexus Arcade", - "[Solution Nine] Residential Sector", - "[Solution Nine] Scanning Port Nine (Heritage Found)" - ] - }, - "CompletionFlags": { - "type": "array", - "description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset", - "items": { - "oneOf": [ - { - "type": "object", - "properties": { - "High": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "maximum": 15 - }, - "Low": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "maximum": 15 - }, - "Negative": { - "type": "boolean" - }, - "Mode": { - "type": "string", - "enum": [ - "Bitwise", - "Exact" - ] - } - } - }, - { - "type": "number", - "enum": [ - 1, - 2, - 4, - 8, - 16, - 32, - 64, - 128 - ] - }, - { - "type": "null" - } - ] - }, - "minItems": 6, - "maxItems": 6 - } - } + "additionalProperties": false } diff --git a/Questionable.Model/AssemblyModelLoader.cs b/Questionable.Model/AssemblyModelLoader.cs new file mode 100644 index 00000000..d167cb25 --- /dev/null +++ b/Questionable.Model/AssemblyModelLoader.cs @@ -0,0 +1,9 @@ +using System.IO; + +namespace Questionable.Model; + +public static class AssemblyModelLoader +{ + public static Stream CommonSchema => + typeof(AssemblyModelLoader).Assembly.GetManifestResourceStream("Questionable.Model.CommonSchema")!; +} diff --git a/Questionable.Model/Common/Converter/AetheryteConverter.cs b/Questionable.Model/Common/Converter/AetheryteConverter.cs new file mode 100644 index 00000000..3887305e --- /dev/null +++ b/Questionable.Model/Common/Converter/AetheryteConverter.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Common.Converter; + +public sealed class AetheryteConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EAetheryteLocation.Gridania, "Gridania" }, + { EAetheryteLocation.CentralShroudBentbranchMeadows, "Central Shroud - Bentbranch Meadows" }, + { EAetheryteLocation.EastShroudHawthorneHut, "East Shroud - Hawthorne Hut" }, + { EAetheryteLocation.SouthShroudQuarrymill, "South Shroud - Quarrymill" }, + { EAetheryteLocation.SouthShroudCampTranquil, "South Shroud - Camp Tranquil" }, + { EAetheryteLocation.NorthShroudFallgourdFloat, "North Shroud - Fallgourd Float" }, + + { EAetheryteLocation.Uldah, "Ul'dah" }, + { EAetheryteLocation.WesternThanalanHorizon, "Western Thanalan - Horizon" }, + { EAetheryteLocation.CentralThanalanBlackBrushStation, "Central Thanalan - Black Brush Station" }, + { EAetheryteLocation.EasternThanalanCampDrybone, "Eastern Thanalan - Camp Drybone" }, + { EAetheryteLocation.SouthernThanalanLittleAlaMhigo, "Southern Thanalan - Little Ala Mhigo" }, + { EAetheryteLocation.SouthernThanalanForgottenSprings, "Southern Thanalan - Forgotten Springs" }, + { EAetheryteLocation.NorthernThanalanCampBluefog, "Northern Thanalan - Camp Bluefog" }, + { EAetheryteLocation.NorthernThanalanCeruleumProcessingPlant, "Northern Thanalan - Ceruleum Processing Plant" }, + + { EAetheryteLocation.Limsa, "Limsa Lominsa" }, + { EAetheryteLocation.MiddleLaNosceaSummerfordFarms, "Middle La Noscea - Summerford Farms" }, + { EAetheryteLocation.LowerLaNosceaMorabyDrydocks, "Lower La Noscea - Moraby Drydocks" }, + { EAetheryteLocation.EasternLaNosceaCostaDelSol, "Eastern La Noscea - Costa Del Sol" }, + { EAetheryteLocation.EasternLaNosceaWineport, "Eastern La Noscea - Wineport" }, + { EAetheryteLocation.WesternLaNosceaSwiftperch, "Western La Noscea - Swiftperch" }, + { EAetheryteLocation.WesternLaNosceaAleport, "Western La Noscea - Aleport" }, + { EAetheryteLocation.UpperLaNosceaCampBronzeLake, "Upper La Noscea - Camp Bronze Lake" }, + { EAetheryteLocation.OuterLaNosceaCampOverlook, "Outer La Noscea - Camp Overlook" }, + + { EAetheryteLocation.CoerthasCentralHighlandsCampDragonhead, "Coerthas Central Highlands - Camp Dragonhead" }, + { EAetheryteLocation.MorDhona, "Mor Dhona" }, + { EAetheryteLocation.GoldSaucer, "Gold Saucer" }, + { EAetheryteLocation.WolvesDenPier, "Wolves' Den Pier" }, + + { EAetheryteLocation.Ishgard, "Ishgard" }, + { EAetheryteLocation.Idyllshire, "Idyllshire" }, + { EAetheryteLocation.CoerthasWesternHighlandsFalconsNest, "Coerthas Western Highlands - Falcon's Nest" }, + { EAetheryteLocation.SeaOfCloudsCampCloudtop, "The Sea of Clouds - Camp Cloudtop" }, + { EAetheryteLocation.SeaOfCloudsOkZundu, "The Sea of Clouds - Ok' Zundu" }, + { EAetheryteLocation.AzysLlaHelix, "Azys Lla - Helix" }, + { EAetheryteLocation.DravanianForelandsTailfeather, "The Dravanian Forelands - Tailfeather" }, + { EAetheryteLocation.DravanianForelandsAnyxTrine, "The Dravanian Forelands - Anyx Trine" }, + { EAetheryteLocation.ChurningMistsMoghome, "The Churning Mists - Moghome" }, + { EAetheryteLocation.ChurningMistsZenith, "The Churning Mists - Zenith" }, + + { EAetheryteLocation.RhalgrsReach, "Rhalgr's Reach" }, + { EAetheryteLocation.FringesCastrumOriens, "Fringes - Castrum Oriens" }, + { EAetheryteLocation.FringesPeeringStones, "Fringes - Peering Stones" }, + { EAetheryteLocation.PeaksAlaGannha, "Peaks - Ala Gannha" }, + { EAetheryteLocation.PeaksAlaGhiri, "Peaks - Ala Ghiri" }, + { EAetheryteLocation.LochsPortaPraetoria, "Lochs - Porta Praetoria" }, + { EAetheryteLocation.LochsAlaMhiganQuarter, "Lochs - Ala Mhigan Quarter" }, + { EAetheryteLocation.Kugane, "Kugane" }, + { EAetheryteLocation.RubySeaTamamizu, "Ruby Sea - Tamamizu" }, + { EAetheryteLocation.RubySeaOnokoro, "Ruby Sea - Onokoro" }, + { EAetheryteLocation.YanxiaNamai, "Yanxia - Namai" }, + { EAetheryteLocation.YanxiaHouseOfTheFierce, "Yanxia - House of the Fierce" }, + { EAetheryteLocation.AzimSteppeReunion, "Azim Steppe - Reunion" }, + { EAetheryteLocation.AzimSteppeDawnThrone, "Azim Steppe - Dawn Throne" }, + { EAetheryteLocation.AzimSteppeDhoroIloh, "Azim Steppe - Dhoro Iloh" }, + { EAetheryteLocation.DomanEnclave, "Doman Enclave" }, + + { EAetheryteLocation.Crystarium, "Crystarium" }, + { EAetheryteLocation.Eulmore, "Eulmore" }, + { EAetheryteLocation.LakelandFortJobb, "Lakeland - Fort Jobb" }, + { EAetheryteLocation.LakelandOstallImperative, "Lakeland - Ostall Imperative" }, + { EAetheryteLocation.KholusiaStilltide, "Kholusia - Stilltide" }, + { EAetheryteLocation.KholusiaWright, "Kholusia - Wright" }, + { EAetheryteLocation.KholusiaTomra, "Kholusia - Tomra" }, + { EAetheryteLocation.AmhAraengMordSouq, "Amh Araeng - Mord Souq" }, + { EAetheryteLocation.AmhAraengInnAtJourneysHead, "Amh Araeng - Inn at Journey's Head" }, + { EAetheryteLocation.AmhAraengTwine, "Amh Araeng - Twine" }, + { EAetheryteLocation.RaktikaSlitherbough, "Rak'tika - Slitherbough" }, + { EAetheryteLocation.RaktikaFanow, "Rak'tika - Fanow" }, + { EAetheryteLocation.IlMhegLydhaLran, "Il Mheg - Lydha Lran" }, + { EAetheryteLocation.IlMhegPiaEnni, "Il Mheg - Pia Enni" }, + { EAetheryteLocation.IlMhegWolekdorf, "Il Mheg - Wolekdorf" }, + { EAetheryteLocation.TempestOndoCups, "Tempest - Ondo Cups" }, + { EAetheryteLocation.TempestMacarensesAngle, "Tempest - Macarenses Angle" }, + + { EAetheryteLocation.OldSharlayan, "Old Sharlayan" }, + { EAetheryteLocation.RadzAtHan, "Radz-at-Han" }, + { EAetheryteLocation.LabyrinthosArcheion, "Labyrinthos - Archeion" }, + { EAetheryteLocation.LabyrinthosSharlayanHamlet, "Labyrinthos - Sharlayan Hamlet" }, + { EAetheryteLocation.LabyrinthosAporia, "Labyrinthos - Aporia" }, + { EAetheryteLocation.ThavnairYedlihmad, "Thavnair - Yedlihmad" }, + { EAetheryteLocation.ThavnairGreatWork, "Thavnair - Great Work" }, + { EAetheryteLocation.ThavnairPalakasStand, "Thavnair - Palaka's Stand" }, + { EAetheryteLocation.GarlemaldCampBrokenGlass, "Garlemald - Camp Broken Glass" }, + { EAetheryteLocation.GarlemaldTertium, "Garlemald - Tertium" }, + { EAetheryteLocation.MareLamentorumSinusLacrimarum, "Mare Lamentorum - Sinus Lacrimarum" }, + { EAetheryteLocation.MareLamentorumBestwaysBurrow, "Mare Lamentorum - Bestways Burrow" }, + { EAetheryteLocation.ElpisAnagnorisis, "Elpis - Anagnorisis" }, + { EAetheryteLocation.ElpisTwelveWonders, "Elpis - Twelve Wonders" }, + { EAetheryteLocation.ElpisPoietenOikos, "Elpis - Poieten Oikos" }, + { EAetheryteLocation.UltimaThuleReahTahra, "Ultima Thule - Reah Tahra" }, + { EAetheryteLocation.UltimaThuleAbodeOfTheEa, "Ultima Thule - Abode of the Ea" }, + { EAetheryteLocation.UltimaThuleBaseOmicron, "Ultima Thule - Base Omicron" }, + + { EAetheryteLocation.Tuliyollal, "Tuliyollal" }, + { EAetheryteLocation.SolutionNine, "Solution Nine" }, + { EAetheryteLocation.UrqopachaWachunpelo, "Urqopacha - Wachunpelo" }, + { EAetheryteLocation.UrqopachaWorlarsEcho, "Urqopacha - Worlar's Echo" }, + { EAetheryteLocation.KozamaukaOkHanu, "Kozama'uka - Ok'hanu" }, + { EAetheryteLocation.KozamaukaManyFires, "Kozama'uka - Many Fires" }, + { EAetheryteLocation.KozamaukaEarthenshire, "Kozama'uka - Earthenshire" }, + { EAetheryteLocation.YakTelIqBraax, "Yak T'el - Iq Br'aax" }, + { EAetheryteLocation.YakTelMamook, "Yak T'el - Mamook" }, + { EAetheryteLocation.ShaaloaniHhusatahwi, "Shaaloani - Hhusatahwi" }, + { EAetheryteLocation.ShaaloaniShesheneweziSprings, "Shaaloani - Sheshenewezi Springs" }, + { EAetheryteLocation.ShaaloaniMehwahhetsoan, "Shaaloani - Mehwahhetsoan" }, + { EAetheryteLocation.HeritageFoundYyasulaniStation, "Heritage Found - Yyasulani Station" }, + { EAetheryteLocation.HeritageFoundTheOutskirts, "Heritage Found - The Outskirts" }, + { EAetheryteLocation.HeritageFoundElectropeStrike, "Heritage Found - Electrope Strike" }, + { EAetheryteLocation.LivingMemoryLeynodeMnemo, "Living Memory - Leynode Mnemo" }, + { EAetheryteLocation.LivingMemoryLeynodePyro, "Living Memory - Leynode Pyro" }, + { EAetheryteLocation.LivingMemoryLeynodeAero, "Living Memory - Leynode Aero" }, + }; + + public static bool IsLargeAetheryte(EAetheryteLocation aetheryte) => Values.ContainsKey(aetheryte); +} diff --git a/Questionable.Model/Common/Converter/EnumConverter.cs b/Questionable.Model/Common/Converter/EnumConverter.cs new file mode 100644 index 00000000..3708e28c --- /dev/null +++ b/Questionable.Model/Common/Converter/EnumConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Questionable.Model.Common.Converter; + +public abstract class EnumConverter : JsonConverter + where T : Enum +{ + private readonly ReadOnlyDictionary _enumToString; + private readonly ReadOnlyDictionary _stringToEnum; + + protected EnumConverter(IReadOnlyDictionary values) + { + _enumToString = values is IDictionary dict + ? new ReadOnlyDictionary(dict) + : new ReadOnlyDictionary(values.ToDictionary(x => x.Key, x => x.Value)); + _stringToEnum = new ReadOnlyDictionary(_enumToString.ToDictionary(x => x.Value, x => x.Key)); + } + + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, + JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.String) + throw new JsonException(); + + string? str = reader.GetString(); + if (str == null) + throw new JsonException(); + + return _stringToEnum.TryGetValue(str, out T? value) ? value : throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + writer.WriteStringValue(_enumToString[value]); + } +} diff --git a/Questionable.Model/Common/Converter/StringListOrValueConverter.cs b/Questionable.Model/Common/Converter/StringListOrValueConverter.cs new file mode 100644 index 00000000..ebdec1cf --- /dev/null +++ b/Questionable.Model/Common/Converter/StringListOrValueConverter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Questionable.Model.Common.Converter; + +public sealed class StringListOrValueConverter : JsonConverter> +{ + public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.String) + return [reader.GetString()!]; + + if (reader.TokenType != JsonTokenType.StartArray) + throw new JsonException(); + reader.Read(); + + List value = []; + while (reader.TokenType != JsonTokenType.EndArray) + { + value.Add(reader.GetString()!); + reader.Read(); + } + + return value; + } + + public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) + { + if (value == null) + writer.WriteNullValue(); + else if (value.Count == 1) + writer.WriteStringValue(value[0]); + else + { + writer.WriteStartArray(); + foreach (var v in value) + writer.WriteStringValue(v); + writer.WriteEndArray(); + } + } +} diff --git a/Questionable.Model/Common/Converter/VectorConverter.cs b/Questionable.Model/Common/Converter/VectorConverter.cs new file mode 100644 index 00000000..7b4833ef --- /dev/null +++ b/Questionable.Model/Common/Converter/VectorConverter.cs @@ -0,0 +1,64 @@ +using System; +using System.Numerics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Questionable.Model.Common.Converter; + +public sealed class VectorConverter : JsonConverter +{ + public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + throw new JsonException(); + + Vector3 vec = new Vector3(); + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.PropertyName: + string? propertyName = reader.GetString(); + if (propertyName == null || !reader.Read()) + throw new JsonException(); + + switch (propertyName) + { + case nameof(Vector3.X): + vec.X = reader.GetSingle(); + break; + + case nameof(Vector3.Y): + vec.Y = reader.GetSingle(); + break; + + case nameof(Vector3.Z): + vec.Z = reader.GetSingle(); + break; + + default: + throw new JsonException(); + } + + break; + + case JsonTokenType.EndObject: + return vec; + + default: + throw new JsonException(); + } + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WriteNumber(nameof(Vector3.X), value.X); + writer.WriteNumber(nameof(Vector3.Y), value.X); + writer.WriteNumber(nameof(Vector3.Z), value.X); + writer.WriteEndObject(); + } +} diff --git a/Questionable.Model/Common/EAetheryteLocation.cs b/Questionable.Model/Common/EAetheryteLocation.cs new file mode 100644 index 00000000..a00f7b51 --- /dev/null +++ b/Questionable.Model/Common/EAetheryteLocation.cs @@ -0,0 +1,252 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Common; + +[JsonConverter(typeof(AetheryteConverter))] +public enum EAetheryteLocation +{ + None = 0, + + Gridania = 2, + GridaniaArcher = 25, + GridaniaLeatherworker = 26, + GridaniaLancer = 27, + GridaniaConjurer = 28, + GridaniaBotanist = 29, + GridaniaAmphitheatre = 30, + GridaniaBlueBadgerGate = 31, + GridaniaYellowSerpentGate = 32, + GridaniaWhiteWolfGate = 54, + GridaniaAirship = 94, + + CentralShroudBentbranchMeadows = 3, + EastShroudHawthorneHut = 4, + SouthShroudQuarrymill = 5, + SouthShroudCampTranquil = 6, + NorthShroudFallgourdFloat = 7, + + Uldah = 9, + UldahAdventurers = 33, + UldahThaumaturge = 34, + UldahGladiator = 35, + UldahMiner = 36, + UldahAlchemist = 37, + UldahWeaver = 47, + UldahGoldsmith = 50, + UldahChamberOfRule = 51, + UldahAirship = 95, + UldahGateOfTheSultana = 38, + UldahGateOfNald = 39, + UldahGateOfThal = 40, + UldahSapphireAvenue = 125, + + WesternThanalanHorizon = 17, + EasternThanalanCampDrybone = 18, + SouthernThanalanLittleAlaMhigo = 19, + SouthernThanalanForgottenSprings = 20, + NorthernThanalanCampBluefog = 21, + NorthernThanalanCeruleumProcessingPlant = 22, + CentralThanalanBlackBrushStation = 53, + + Limsa = 8, + LimsaAftcastle = 41, + LimsaCulinarian = 42, + LimsaArcanist = 43, + LimsaFisher = 44, + LimsaMarauder = 48, + LimsaHawkersAlley = 49, + LimsaZephyrGate = 45, + LimsaTempestGate = 46, + LimsaAirship = 93, + + LowerLaNosceaMorabyDrydocks = 10, + EasternLaNosceaCostaDelSol = 11, + EasternLaNosceaWineport = 12, + WesternLaNosceaSwiftperch = 13, + WesternLaNosceaAleport = 14, + UpperLaNosceaCampBronzeLake = 15, + OuterLaNosceaCampOverlook = 16, + MiddleLaNosceaSummerfordFarms = 52, + + CoerthasCentralHighlandsCampDragonhead = 23, + MorDhona = 24, + GoldSaucer = 62, + WolvesDenPier = 55, + + Ishgard = 70, + IshgardForgottenKnight = 80, + IshgardSkysteelManufactory = 81, + IshgardBrume = 82, + IshgardAthenaeumAstrologicum = 83, + IshgardJeweledCrozier = 84, + IshgardSaintReymanaudsCathedral = 85, + IshgardTribunal = 86, + IshgardLastVigil = 87, + IshgardGatesOfJudgement = 88, + + Idyllshire = 75, + IdyllshireWest = 90, + IdyllshirePrologueGate = 91, + IdyllshireEpilogueGate = 92, + + CoerthasWesternHighlandsFalconsNest = 71, + SeaOfCloudsCampCloudtop = 72, + SeaOfCloudsOkZundu = 73, + AzysLlaHelix = 74, + DravanianForelandsTailfeather = 76, + DravanianForelandsAnyxTrine = 77, + ChurningMistsMoghome = 78, + ChurningMistsZenith = 79, + + RhalgrsReach = 104, + RhalgrsReachWest = 121, + RhalgrsReachNorthEast = 122, + RhalgrsReachFringesGate = 123, + RhalgrsReachPeaksGate = 124, + + Kugane = 111, + KuganeShiokazeHostelry = 112, + KuganePier1 = 113, + KuganeThavnairianConsulate = 114, + KuganeMarkets = 115, + KuganeBokairoInn = 116, + KuganeRubyBazaar = 117, + KuganeSekiseigumiBarracks = 118, + KuganeRakuzaDistrict = 119, + KuganeRubyPrice = 120, + KuganeAirship = 126, + + FringesCastrumOriens = 98, + FringesPeeringStones = 99, + PeaksAlaGannha = 100, + PeaksAlaGhiri = 101, + LochsPortaPraetoria = 102, + LochsAlaMhiganQuarter = 103, + RubySeaTamamizu = 105, + RubySeaOnokoro = 106, + YanxiaNamai = 107, + YanxiaHouseOfTheFierce = 108, + AzimSteppeReunion = 109, + AzimSteppeDawnThrone = 110, + AzimSteppeDhoroIloh = 128, + + DomanEnclave = 127, + DomanEnclaveNorthern = 129, + DomanEnclaveSouthern = 130, + DomanEnclaveOneRiver = 131, + DomanEnclaveDocks = 162, + + Crystarium = 133, + CrystariumMarkets = 149, + CrystariumTemenosRookery = 150, + CrystariumDossalGate = 151, + CrystariumPendants = 152, + CrystariumAmaroLaunch = 153, + CrystariumCrystallineMean = 154, + CrystariumCabinetOfCuriosity = 155, + CrystariumTessellation = 156, + + Eulmore = 134, + EulmoreMainstay = 157, + EulmoreNightsoilPots = 158, + EulmoreGloryGate = 159, + EulmoreSoutheastDerelict = 135, + EulmorePathToGlory = 160, + + LakelandFortJobb = 132, + LakelandOstallImperative = 136, + KholusiaStilltide = 137, + KholusiaWright = 138, + KholusiaTomra = 139, + AmhAraengMordSouq = 140, + AmhAraengInnAtJourneysHead = 161, + AmhAraengTwine = 141, + RaktikaSlitherbough = 142, + RaktikaFanow = 143, + IlMhegLydhaLran = 144, + IlMhegPiaEnni = 145, + IlMhegWolekdorf = 146, + TempestOndoCups = 147, + TempestMacarensesAngle = 148, + + OldSharlayan = 182, + OldSharlayanStudium = 184, + OldSharlayanBaldesionAnnex = 185, + OldSharlayanRostra = 186, + OldSharlayanLeveilleurEstate = 187, + OldSharlayanJourneysEnd = 188, + OldSharlayanScholarsHarbor = 189, + OldSharlayanHallOfArtifice = 190, + + RadzAtHan = 183, + RadzAtHanMeghaduta = 191, + RadzAtHanRuveydahFibers = 192, + RadzAtHanAirship = 193, + RadzAtHanAlzadaalsPeace = 194, + RadzAtHanHallOfTheRadiantHost = 195, + RadzAtHanMehrydesMeyhane = 196, + RadzAtHanKama = 198, + RadzAtHanHighCrucible = 199, + RadzAtHanGateOfFirstSight = 197, + + LabyrinthosArcheion = 166, + LabyrinthosSharlayanHamlet = 167, + LabyrinthosAporia = 168, + ThavnairYedlihmad = 169, + ThavnairGreatWork = 170, + ThavnairPalakasStand = 171, + GarlemaldCampBrokenGlass = 172, + GarlemaldTertium = 173, + MareLamentorumSinusLacrimarum = 174, + MareLamentorumBestwaysBurrow = 175, + ElpisAnagnorisis = 176, + ElpisTwelveWonders = 177, + ElpisPoietenOikos = 178, + UltimaThuleReahTahra = 179, + UltimaThuleAbodeOfTheEa = 180, + UltimaThuleBaseOmicron = 181, + + Tuliyollal = 216, + + TuliyollalDirigibleLanding = 218, + TuliyollalTheResplendentQuarter = 219, + TuliyollalTheForardCabins = 220, + TuliyollalBaysideBevyMarketplace = 221, + TuliyollalVollokShoonsa = 222, + TuliyollalWachumeqimeqi = 223, + TuliyollalBrightploomPost = 224, + TuliyollalArchOfTheDawnUrqopacha = 225, + TuliyollalArchOfTheDawnKozamauka = 226, + TuliyollalIhuykatumu = 227, + TuliyollalDirigibleLandingYakTel = 228, + TuliyollalXakTuralSkygate = 229, + + SolutionNine = 217, + SolutionNineInformationCenter = 230, + SolutionNineTrueVue = 231, + SolutionNineNeonStein = 232, + SolutionNineTheArcadion = 233, + SolutionNineResolution = 234, + SolutionNineNexusArcade = 235, + SolutionNineResidentialSector = 236, + SolutionNineScanningPortNine = 237, + + UrqopachaWachunpelo = 200, + UrqopachaWorlarsEcho = 201, + KozamaukaOkHanu = 202, + KozamaukaManyFires = 203, + KozamaukaEarthenshire = 204, + YakTelIqBraax = 205, + YakTelMamook = 206, + ShaaloaniHhusatahwi = 207, + ShaaloaniShesheneweziSprings = 208, + ShaaloaniMehwahhetsoan = 209, + HeritageFoundYyasulaniStation = 210, + HeritageFoundTheOutskirts = 211, + HeritageFoundElectropeStrike = 212, + LivingMemoryLeynodeMnemo = 213, + LivingMemoryLeynodePyro = 214, + LivingMemoryLeynodeAero = 215, +} diff --git a/Questionable.Model/Gathering/GatheringNodeLocation.cs b/Questionable.Model/Gathering/GatheringNodeLocation.cs new file mode 100644 index 00000000..49a5e640 --- /dev/null +++ b/Questionable.Model/Gathering/GatheringNodeLocation.cs @@ -0,0 +1,13 @@ +using System.Numerics; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringNodeLocation +{ + public uint DataId { get; set; } + public Vector3 Position { get; set; } + public float? MinimumAngle { get; set; } + public float? MaximumAngle { get; set; } + public float? MinimumDistance { get; set; } = 0.5f; + public float? MaximumDistance { get; set; } = 3f; +} diff --git a/Questionable.Model/Gathering/GatheringRoot.cs b/Questionable.Model/Gathering/GatheringRoot.cs new file mode 100644 index 00000000..c572faab --- /dev/null +++ b/Questionable.Model/Gathering/GatheringRoot.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Gathering; + +public sealed class GatheringRoot +{ + [JsonConverter(typeof(StringListOrValueConverter))] + public List Author { get; set; } = []; + public ushort TerritoryId { get; set; } + + [JsonConverter(typeof(AetheryteConverter))] + public EAetheryteLocation? AetheryteShortcut { get; set; } + + public List Nodes { get; set; } = []; +} diff --git a/Questionable.Model/Questing/AethernetShortcut.cs b/Questionable.Model/Questing/AethernetShortcut.cs new file mode 100644 index 00000000..3d046c44 --- /dev/null +++ b/Questionable.Model/Questing/AethernetShortcut.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Common; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(AethernetShortcutConverter))] +public sealed class AethernetShortcut +{ + public EAetheryteLocation From { get; set; } + public EAetheryteLocation To { get; set; } +} diff --git a/Questionable.Model/Questing/ChatMessage.cs b/Questionable.Model/Questing/ChatMessage.cs new file mode 100644 index 00000000..b0272135 --- /dev/null +++ b/Questionable.Model/Questing/ChatMessage.cs @@ -0,0 +1,7 @@ +namespace Questionable.Model.Questing; + +public sealed class ChatMessage +{ + public string? ExcelSheet { get; set; } + public string Key { get; set; } = null!; +} diff --git a/Questionable.Model/Questing/ComplexCombatData.cs b/Questionable.Model/Questing/ComplexCombatData.cs new file mode 100644 index 00000000..5f85c243 --- /dev/null +++ b/Questionable.Model/Questing/ComplexCombatData.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace Questionable.Model.Questing; + +public sealed class ComplexCombatData +{ + public uint DataId { get; set; } + + // TODO Use this + public uint? MinimumKillCount { get; set; } + + /// + /// If a reward item has been set, this is (ping allowing) given to the player before the dead enemy despawns. + /// + public uint? RewardItemId { get; set; } + public int? RewardItemCount { get; set; } + public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public bool IgnoreQuestMarker { get; set; } +} diff --git a/Questionable.Model/Questing/Converter/ActionConverter.cs b/Questionable.Model/Questing/Converter/ActionConverter.cs new file mode 100644 index 00000000..7e62c011 --- /dev/null +++ b/Questionable.Model/Questing/Converter/ActionConverter.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class ActionConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EAction.Cure, "Cure" }, + { EAction.Esuna, "Esuna" }, + { EAction.Physick, "Physick" }, + { EAction.Buffet, "Buffet" }, + { EAction.Fumigate, "Fumigate" }, + { EAction.SiphonSnout, "Siphon Snout" }, + { EAction.RedGulal, "Red Gulal" }, + { EAction.YellowGulal, "Yellow Gulal" }, + { EAction.BlueGulal, "Blue Gulal" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/AethernetShardConverter.cs b/Questionable.Model/Questing/Converter/AethernetShardConverter.cs new file mode 100644 index 00000000..bd07bc39 --- /dev/null +++ b/Questionable.Model/Questing/Converter/AethernetShardConverter.cs @@ -0,0 +1,144 @@ +using System.Collections.Generic; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class AethernetShardConverter() : EnumConverter(Values) +{ + public static readonly Dictionary Values = new() + { + { EAetheryteLocation.Gridania, "[Gridania] Aetheryte Plaza" }, + { EAetheryteLocation.GridaniaArcher, "[Gridania] Archers' Guild" }, + { EAetheryteLocation.GridaniaLeatherworker, "[Gridania] Leatherworkers' Guild & Shaded Bower" }, + { EAetheryteLocation.GridaniaLancer, "[Gridania] Lancers' Guild" }, + { EAetheryteLocation.GridaniaConjurer, "[Gridania] Conjurers' Guild" }, + { EAetheryteLocation.GridaniaBotanist, "[Gridania] Botanists' Guild" }, + { EAetheryteLocation.GridaniaAmphitheatre, "[Gridania] Mih Khetto's Amphitheatre" }, + { EAetheryteLocation.GridaniaBlueBadgerGate, "[Gridania] Blue Badger Gate (Central Shroud)" }, + { EAetheryteLocation.GridaniaYellowSerpentGate, "[Gridania] Yellow Serpent Gate (North Shroud)" }, + { EAetheryteLocation.GridaniaWhiteWolfGate, "[Gridania] White Wolf Gate (Central Shroud)" }, + { EAetheryteLocation.GridaniaAirship, "[Gridania] Airship Landing" }, + + { EAetheryteLocation.Uldah, "[Ul'dah] Aetheryte Plaza" }, + { EAetheryteLocation.UldahAdventurers, "[Ul'dah] Adventurers' Guild" }, + { EAetheryteLocation.UldahThaumaturge, "[Ul'dah] Thaumaturges' Guild" }, + { EAetheryteLocation.UldahGladiator, "[Ul'dah] Gladiators' Guild" }, + { EAetheryteLocation.UldahMiner, "[Ul'dah] Miners' Guild" }, + { EAetheryteLocation.UldahWeaver, "[Ul'dah] Weavers' Guild" }, + { EAetheryteLocation.UldahGoldsmith, "[Ul'dah] Goldsmiths' Guild" }, + { EAetheryteLocation.UldahSapphireAvenue, "[Ul'dah] Sapphire Avenue Exchange" }, + { EAetheryteLocation.UldahAlchemist, "[Ul'dah] Alchemists' Guild" }, + { EAetheryteLocation.UldahChamberOfRule, "[Ul'dah] The Chamber of Rule" }, + { EAetheryteLocation.UldahGateOfTheSultana, "[Ul'dah] Gate of the Sultana (Western Thanalan)" }, + { EAetheryteLocation.UldahGateOfNald, "[Ul'dah] Gate of Nald (Central Thanalan)" }, + { EAetheryteLocation.UldahGateOfThal, "[Ul'dah] Gate of Thal (Central Thanalan)" }, + { EAetheryteLocation.UldahAirship, "[Ul'dah] Airship Landing" }, + + { EAetheryteLocation.Limsa, "[Limsa Lominsa] Aetheryte Plaza" }, + { EAetheryteLocation.LimsaArcanist, "[Limsa Lominsa] Arcanists' Guild" }, + { EAetheryteLocation.LimsaFisher, "[Limsa Lominsa] Fishermens' Guild" }, + { EAetheryteLocation.LimsaHawkersAlley, "[Limsa Lominsa] Hawkers' Alley" }, + { EAetheryteLocation.LimsaAftcastle, "[Limsa Lominsa] The Aftcastle" }, + { EAetheryteLocation.LimsaCulinarian, "[Limsa Lominsa] Culinarians' Guild" }, + { EAetheryteLocation.LimsaMarauder, "[Limsa Lominsa] Marauders' Guild" }, + { EAetheryteLocation.LimsaZephyrGate, "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)" }, + { EAetheryteLocation.LimsaTempestGate, "[Limsa Lominsa] Tempest Gate (Lower La Noscea)" }, + { EAetheryteLocation.LimsaAirship, "[Limsa Lominsa] Airship Landing" }, + + { EAetheryteLocation.Ishgard, "[Ishgard] Aetheryte Plaza" }, + { EAetheryteLocation.IshgardForgottenKnight, "[Ishgard] The Forgotten Knight" }, + { EAetheryteLocation.IshgardSkysteelManufactory, "[Ishgard] Skysteel Manufactory" }, + { EAetheryteLocation.IshgardBrume, "[Ishgard] The Brume" }, + { EAetheryteLocation.IshgardAthenaeumAstrologicum, "[Ishgard] Athenaeum Astrologicum" }, + { EAetheryteLocation.IshgardJeweledCrozier, "[Ishgard] The Jeweled Crozier" }, + { EAetheryteLocation.IshgardSaintReymanaudsCathedral, "[Ishgard] Saint Reymanaud's Cathedral" }, + { EAetheryteLocation.IshgardTribunal, "[Ishgard] The Tribunal" }, + { EAetheryteLocation.IshgardLastVigil, "[Ishgard] The Last Vigil" }, + { EAetheryteLocation.IshgardGatesOfJudgement, "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)" }, + + { EAetheryteLocation.Idyllshire, "[Idyllshire] Aetheryte Plaza" }, + { EAetheryteLocation.IdyllshireWest, "[Idyllshire] West Idyllshire" }, + { EAetheryteLocation.IdyllshirePrologueGate, "[Idyllshire] Prologue Gate (Western Hinterlands)" }, + { EAetheryteLocation.IdyllshireEpilogueGate, "[Idyllshire] Epilogue Gate (Eastern Hinterlands)" }, + + { EAetheryteLocation.RhalgrsReach, "[Rhalgr's Reach] Aetheryte Plaza" }, + { EAetheryteLocation.RhalgrsReachWest, "[Rhalgr's Reach] Western Rhalgr's Reach" }, + { EAetheryteLocation.RhalgrsReachNorthEast, "[Rhalgr's Reach] Northeastern Rhalgr's Reach" }, + { EAetheryteLocation.RhalgrsReachFringesGate, "[Rhalgr's Reach] Fringes Gate" }, + { EAetheryteLocation.RhalgrsReachPeaksGate, "[Rhalgr's Reach] Peaks Gate" }, + + { EAetheryteLocation.Kugane, "[Kugane] Aetheryte Plaza" }, + { EAetheryteLocation.KuganeShiokazeHostelry, "[Kugane] Shiokaze Hostelry" }, + { EAetheryteLocation.KuganePier1, "[Kugane] Pier #1" }, + { EAetheryteLocation.KuganeThavnairianConsulate, "[Kugane] Thavnairian Consulate" }, + { EAetheryteLocation.KuganeMarkets, "[Kugane] Kogane Dori Markets" }, + { EAetheryteLocation.KuganeBokairoInn, "[Kugane] Bokairo Inn" }, + { EAetheryteLocation.KuganeRubyBazaar, "[Kugane] The Ruby Bazaar" }, + { EAetheryteLocation.KuganeSekiseigumiBarracks, "[Kugane] Sekiseigumi Barracks" }, + { EAetheryteLocation.KuganeRakuzaDistrict, "[Kugane] Rakuza District" }, + { EAetheryteLocation.KuganeRubyPrice, "[Kugane] The Ruby Price" }, + { EAetheryteLocation.KuganeAirship, "[Kugane] Airship Landing" }, + + { EAetheryteLocation.Crystarium, "[Crystarium] Aetheryte Plaza" }, + { EAetheryteLocation.CrystariumMarkets, "[Crystarium] Musica Universalis Markets" }, + { EAetheryteLocation.CrystariumTemenosRookery, "[Crystarium] Temenos Rookery" }, + { EAetheryteLocation.CrystariumDossalGate, "[Crystarium] The Dossal Gate" }, + { EAetheryteLocation.CrystariumPendants, "[Crystarium] The Pendants" }, + { EAetheryteLocation.CrystariumAmaroLaunch, "[Crystarium] The Amaro Launch" }, + { EAetheryteLocation.CrystariumCrystallineMean, "[Crystarium] The Crystalline Mean" }, + { EAetheryteLocation.CrystariumCabinetOfCuriosity, "[Crystarium] The Cabinet of Curiosity" }, + { EAetheryteLocation.CrystariumTessellation, "[Crystarium] Tessellation (Lakeland)" }, + + { EAetheryteLocation.Eulmore, "[Eulmore] Aetheryte Plaza" }, + { EAetheryteLocation.EulmoreSoutheastDerelict, "[Eulmore] Southeast Derelicts" }, + { EAetheryteLocation.EulmoreNightsoilPots, "[Eulmore] Nightsoil Pots" }, + { EAetheryteLocation.EulmoreGloryGate, "[Eulmore] The Glory Gate" }, + { EAetheryteLocation.EulmoreMainstay, "[Eulmore] The Mainstay" }, + { EAetheryteLocation.EulmorePathToGlory, "[Eulmore] The Path to Glory (Kholusia)" }, + + { EAetheryteLocation.OldSharlayan, "[Old Sharlayan] Aetheryte Plaza" }, + { EAetheryteLocation.OldSharlayanStudium, "[Old Sharlayan] The Studium" }, + { EAetheryteLocation.OldSharlayanBaldesionAnnex, "[Old Sharlayan] The Baldesion Annex" }, + { EAetheryteLocation.OldSharlayanRostra, "[Old Sharlayan] The Rostra" }, + { EAetheryteLocation.OldSharlayanLeveilleurEstate, "[Old Sharlayan] The Leveilleur Estate" }, + { EAetheryteLocation.OldSharlayanJourneysEnd, "[Old Sharlayan] Journey's End" }, + { EAetheryteLocation.OldSharlayanScholarsHarbor, "[Old Sharlayan] Scholar's Harbor" }, + { EAetheryteLocation.OldSharlayanHallOfArtifice, "[Old Sharlayan] The Hall of Artifice (Labyrinthos)" }, + + { EAetheryteLocation.RadzAtHan, "[Radz-at-Han] Aetheryte Plaza" }, + { EAetheryteLocation.RadzAtHanMeghaduta, "[Radz-at-Han] Meghaduta" }, + { EAetheryteLocation.RadzAtHanRuveydahFibers, "[Radz-at-Han] Ruveydah Fibers" }, + { EAetheryteLocation.RadzAtHanAirship, "[Radz-at-Han] Airship Landing" }, + { EAetheryteLocation.RadzAtHanAlzadaalsPeace, "[Radz-at-Han] Alzadaal's Peace" }, + { EAetheryteLocation.RadzAtHanHallOfTheRadiantHost, "[Radz-at-Han] Hall of the Radiant Host" }, + { EAetheryteLocation.RadzAtHanMehrydesMeyhane, "[Radz-at-Han] Mehryde's Meyhane" }, + { EAetheryteLocation.RadzAtHanKama, "[Radz-at-Han] Kama" }, + { EAetheryteLocation.RadzAtHanHighCrucible, "[Radz-at-Han] The High Crucible of Al-Kimiya" }, + { EAetheryteLocation.RadzAtHanGateOfFirstSight, "[Radz-at-Han] The Gate of First Sight (Thavnair)" }, + + { EAetheryteLocation.Tuliyollal, "[Tuliyollal] Aetheryte Plaza" }, + { EAetheryteLocation.TuliyollalDirigibleLanding, "[Tuliyollal] Dirigible Landing" }, + { EAetheryteLocation.TuliyollalTheResplendentQuarter, "[Tuliyollal] The Resplendent Quarter" }, + { EAetheryteLocation.TuliyollalTheForardCabins, "[Tuliyollal] The For'ard Cabins" }, + { EAetheryteLocation.TuliyollalBaysideBevyMarketplace, "[Tuliyollal] Bayside Bevy Marketplace" }, + { EAetheryteLocation.TuliyollalVollokShoonsa, "[Tuliyollal] Vollok Shoonsa" }, + { EAetheryteLocation.TuliyollalWachumeqimeqi, "[Tuliyollal] Wachumeqimeqi" }, + { EAetheryteLocation.TuliyollalBrightploomPost, "[Tuliyollal] Brightploom Post" }, + { EAetheryteLocation.TuliyollalArchOfTheDawnUrqopacha, "[Tuliyollal] Arch of the Dawn (Urqopacha)" }, + { EAetheryteLocation.TuliyollalArchOfTheDawnKozamauka, "[Tuliyollal] Arch of the Dawn (Kozama'uka)" }, + { EAetheryteLocation.TuliyollalIhuykatumu, "[Tuliyollal] Ihuykatumu (Kozama'uka)" }, + { EAetheryteLocation.TuliyollalDirigibleLandingYakTel, "[Tuliyollal] Dirigible Landing (Yak T'el)" }, + { EAetheryteLocation.TuliyollalXakTuralSkygate, "[Tuliyollal] Xak Tural Skygate (Shaaloani)" }, + + { EAetheryteLocation.SolutionNine, "[Solution Nine] Aetheryte Plaza" }, + { EAetheryteLocation.SolutionNineInformationCenter, "[Solution Nine] Information Center" }, + { EAetheryteLocation.SolutionNineTrueVue, "[Solution Nine] True Vue" }, + { EAetheryteLocation.SolutionNineNeonStein, "[Solution Nine] Neon Stein" }, + { EAetheryteLocation.SolutionNineTheArcadion, "[Solution Nine] The Arcadion" }, + { EAetheryteLocation.SolutionNineResolution, "[Solution Nine] Resolution" }, + { EAetheryteLocation.SolutionNineNexusArcade, "[Solution Nine] Nexus Arcade" }, + { EAetheryteLocation.SolutionNineResidentialSector, "[Solution Nine] Residential Sector" }, + { EAetheryteLocation.SolutionNineScanningPortNine, "[Solution Nine] Scanning Port Nine (Heritage Found)" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs b/Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs new file mode 100644 index 00000000..d920d882 --- /dev/null +++ b/Questionable.Model/Questing/Converter/AethernetShortcutConverter.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Questionable.Model.Common; + +namespace Questionable.Model.Questing.Converter; + +public sealed class AethernetShortcutConverter : JsonConverter +{ + private static readonly Dictionary EnumToString = AethernetShardConverter.Values; + private static readonly Dictionary StringToEnum = + EnumToString.ToDictionary(x => x.Value, x => x.Key); + + public override AethernetShortcut Read(ref Utf8JsonReader reader, Type typeToConvert, + JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartArray) + throw new JsonException(); + + if (!reader.Read() || reader.TokenType != JsonTokenType.String) + throw new JsonException(); + + string from = reader.GetString() ?? throw new JsonException(); + + if (!reader.Read() || reader.TokenType != JsonTokenType.String) + throw new JsonException(); + + string to = reader.GetString() ?? throw new JsonException(); + + if (!reader.Read() || reader.TokenType != JsonTokenType.EndArray) + throw new JsonException(); + + return new AethernetShortcut + { + From = StringToEnum.TryGetValue(from, out var fromEnum) ? fromEnum : throw new JsonException(), + To = StringToEnum.TryGetValue(to, out var toEnum) ? toEnum : throw new JsonException() + }; + } + + public override void Write(Utf8JsonWriter writer, AethernetShortcut value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + writer.WriteStringValue(EnumToString[value.From]); + writer.WriteStringValue(EnumToString[value.To]); + writer.WriteEndArray(); + } +} diff --git a/Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs b/Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs new file mode 100644 index 00000000..cd66ca9b --- /dev/null +++ b/Questionable.Model/Questing/Converter/DialogueChoiceTypeConverter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class DialogueChoiceTypeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EDialogChoiceType.YesNo, "YesNo" }, + { EDialogChoiceType.List, "List" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/EmoteConverter.cs b/Questionable.Model/Questing/Converter/EmoteConverter.cs new file mode 100644 index 00000000..20c97694 --- /dev/null +++ b/Questionable.Model/Questing/Converter/EmoteConverter.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class EmoteConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EEmote.Stretch, "stretch" }, + { EEmote.Wave, "wave" }, + { EEmote.Rally, "rally" }, + { EEmote.Deny, "deny" }, + { EEmote.Pray, "pray" }, + { EEmote.Slap, "slap" }, + { EEmote.Doubt, "doubt" }, + { EEmote.Psych, "psych" }, + { EEmote.Cheer, "cheer" }, + { EEmote.Happy, "happy" }, + { EEmote.Poke, "poke" }, + { EEmote.Flex, "flex" }, + { EEmote.Soothe, "soothe" }, + { EEmote.Me, "me" }, + { EEmote.Welcome, "welcome" }, + { EEmote.ImperialSalute, "imperialsalute" }, + { EEmote.Pet, "pet" }, + { EEmote.Dance, "dance" }, + { EEmote.Respect, "respect" }, + { EEmote.Lookout, "lookout" }, + { EEmote.Kneel, "kneel" }, + { EEmote.Bow, "bow" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs b/Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs new file mode 100644 index 00000000..e97faa4f --- /dev/null +++ b/Questionable.Model/Questing/Converter/EnemySpawnTypeConverter.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class EnemySpawnTypeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EEnemySpawnType.AfterInteraction, "AfterInteraction" }, + { EEnemySpawnType.AfterItemUse, "AfterItemUse" }, + { EEnemySpawnType.AutoOnEnterArea, "AutoOnEnterArea" }, + { EEnemySpawnType.OverworldEnemies, "OverworldEnemies" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/ExcelRefConverter.cs b/Questionable.Model/Questing/Converter/ExcelRefConverter.cs new file mode 100644 index 00000000..03a8168e --- /dev/null +++ b/Questionable.Model/Questing/Converter/ExcelRefConverter.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Questionable.Model.Questing.Converter; + +public sealed class ExcelRefConverter : JsonConverter +{ + public override ExcelRef? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.TokenType switch + { + JsonTokenType.String => ExcelRef.FromKey(reader.GetString()!), + JsonTokenType.Number => ExcelRef.FromRowId(reader.GetUInt32()), + _ => null + }; + } + + public override void Write(Utf8JsonWriter writer, ExcelRef? value, JsonSerializerOptions options) + { + if (value == null) + writer.WriteNullValue(); + else if (value.Type == ExcelRef.EType.Key) + writer.WriteStringValue(value.AsKey()); + else if (value.Type == ExcelRef.EType.RowId) + writer.WriteNumberValue(value.AsRowId()); + else + throw new JsonException(); + } +} diff --git a/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs new file mode 100644 index 00000000..23f0366e --- /dev/null +++ b/Questionable.Model/Questing/Converter/InteractionTypeConverter.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class InteractionTypeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EInteractionType.Interact, "Interact" }, + { EInteractionType.WalkTo, "WalkTo" }, + { EInteractionType.AttuneAethernetShard, "AttuneAethernetShard" }, + { EInteractionType.AttuneAetheryte, "AttuneAetheryte" }, + { EInteractionType.AttuneAetherCurrent, "AttuneAetherCurrent" }, + { EInteractionType.Combat, "Combat" }, + { EInteractionType.UseItem, "UseItem" }, + { EInteractionType.EquipItem, "EquipItem" }, + { EInteractionType.Say, "Say" }, + { EInteractionType.Emote, "Emote" }, + { EInteractionType.Action, "Action" }, + { EInteractionType.WaitForObjectAtPosition, "WaitForNpcAtPosition" }, + { EInteractionType.WaitForManualProgress, "WaitForManualProgress" }, + { EInteractionType.Duty, "Duty" }, + { EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" }, + { EInteractionType.Jump, "Jump" }, + { EInteractionType.Dive, "Dive" }, + { EInteractionType.Instruction, "Instruction" }, + { EInteractionType.AcceptQuest, "AcceptQuest" }, + { EInteractionType.CompleteQuest, "CompleteQuest" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/JumpTypeConverter.cs b/Questionable.Model/Questing/Converter/JumpTypeConverter.cs new file mode 100644 index 00000000..95bb0846 --- /dev/null +++ b/Questionable.Model/Questing/Converter/JumpTypeConverter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class JumpTypeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EJumpType.SingleJump, "SingleJump" }, + { EJumpType.RepeatedJumps, "RepeatedJumps" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs b/Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs new file mode 100644 index 00000000..72eb9dec --- /dev/null +++ b/Questionable.Model/Questing/Converter/LockedSkipConditionConverter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class LockedSkipConditionConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { ELockedSkipCondition.Locked, "Locked" }, + { ELockedSkipCondition.Unlocked, "Unlocked" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs b/Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs new file mode 100644 index 00000000..b6cccc46 --- /dev/null +++ b/Questionable.Model/Questing/Converter/QuestWorkConfigConverter.cs @@ -0,0 +1,63 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Questionable.Model.Questing.Converter; + +public sealed class QuestWorkConfigConverter : JsonConverter +{ + public override QuestWorkValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Number) + return new QuestWorkValue(reader.GetByte()); + + if (reader.TokenType != JsonTokenType.StartObject) + throw new JsonException(); + + byte? high = null, low = null; + EQuestWorkMode mode = EQuestWorkMode.Bitwise; + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.PropertyName: + string? propertyName = reader.GetString(); + if (propertyName == null || !reader.Read()) + throw new JsonException(); + + switch (propertyName) + { + case nameof(QuestWorkValue.High): + high = reader.GetByte(); + break; + + case nameof(QuestWorkValue.Low): + low = reader.GetByte(); + break; + + case nameof(QuestWorkValue.Mode): + mode = new QuestWorkModeConverter().Read(ref reader, typeof(EQuestWorkMode), options); + break; + + default: + throw new JsonException(); + } + + break; + + case JsonTokenType.EndObject: + return new QuestWorkValue(high, low, mode); + + default: + throw new JsonException(); + } + } + + throw new JsonException(); + } + + public override void Write(Utf8JsonWriter writer, QuestWorkValue value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} diff --git a/Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs b/Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs new file mode 100644 index 00000000..322d6a19 --- /dev/null +++ b/Questionable.Model/Questing/Converter/QuestWorkModeConverter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class QuestWorkModeConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EQuestWorkMode.Bitwise, "Bitwise" }, + { EQuestWorkMode.Exact, "Exact" }, + }; +} diff --git a/Questionable.Model/Questing/Converter/SkipConditionConverter.cs b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs new file mode 100644 index 00000000..eadd84b1 --- /dev/null +++ b/Questionable.Model/Questing/Converter/SkipConditionConverter.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using Questionable.Model.Common.Converter; + +namespace Questionable.Model.Questing.Converter; + +public sealed class SkipConditionConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { EExtraSkipCondition.WakingSandsMainArea, "WakingSandsMainArea" }, + }; +} diff --git a/Questionable.Model/Questing/DialogueChoice.cs b/Questionable.Model/Questing/DialogueChoice.cs new file mode 100644 index 00000000..91370f5d --- /dev/null +++ b/Questionable.Model/Questing/DialogueChoice.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +public sealed class DialogueChoice +{ + [JsonConverter(typeof(DialogueChoiceTypeConverter))] + public EDialogChoiceType Type { get; set; } + public string? ExcelSheet { get; set; } + + [JsonConverter(typeof(ExcelRefConverter))] + public ExcelRef? Prompt { get; set; } + + public bool Yes { get; set; } = true; + + [JsonConverter(typeof(ExcelRefConverter))] + public ExcelRef? Answer { get; set; } + + /// + /// If set, only applies when focusing the given target id. + /// + public uint? DataId { get; set; } +} diff --git a/Questionable.Model/Questing/EAction.cs b/Questionable.Model/Questing/EAction.cs new file mode 100644 index 00000000..4b24dee1 --- /dev/null +++ b/Questionable.Model/Questing/EAction.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(ActionConverter))] +public enum EAction +{ + Cure = 120, + Esuna = 7568, + Physick = 190, + Buffet = 4931, + Fumigate = 5872, + SiphonSnout = 18187, + RedGulal = 29382, + YellowGulal = 29383, + BlueGulal = 29384, +} + +public static class EActionExtensions +{ + public static bool RequiresMount(this EAction action) + { + return action + is EAction.Buffet + or EAction.Fumigate + or EAction.SiphonSnout + or EAction.RedGulal + or EAction.YellowGulal + or EAction.BlueGulal; + } +} diff --git a/Questionable.Model/Questing/EDialogChoiceType.cs b/Questionable.Model/Questing/EDialogChoiceType.cs new file mode 100644 index 00000000..9b537471 --- /dev/null +++ b/Questionable.Model/Questing/EDialogChoiceType.cs @@ -0,0 +1,8 @@ +namespace Questionable.Model.Questing; + +public enum EDialogChoiceType +{ + None, + YesNo, + List, +} diff --git a/Questionable.Model/Questing/EEmote.cs b/Questionable.Model/Questing/EEmote.cs new file mode 100644 index 00000000..022930e9 --- /dev/null +++ b/Questionable.Model/Questing/EEmote.cs @@ -0,0 +1,33 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(EmoteConverter))] +public enum EEmote +{ + None = 0, + + Stretch = 37, + Wave = 16, + Rally = 34, + Deny = 25, + Pray = 58, + Slap = 111, + Doubt = 12, + Psych = 30, + Cheer = 6, + Happy = 48, + Poke = 28, + Flex = 139, + Soothe = 35, + Me = 23, + Welcome = 41, + ImperialSalute = 59, + Pet = 105, + Dance = 11, + Respect = 140, + Lookout = 22, + Kneel = 19, + Bow = 5, +} diff --git a/Questionable.Model/Questing/EEnemySpawnType.cs b/Questionable.Model/Questing/EEnemySpawnType.cs new file mode 100644 index 00000000..3c42b9f4 --- /dev/null +++ b/Questionable.Model/Questing/EEnemySpawnType.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(EnemySpawnTypeConverter))] +public enum EEnemySpawnType +{ + None = 0, + AfterInteraction, + AfterItemUse, + AutoOnEnterArea, + OverworldEnemies, +} diff --git a/Questionable.Model/Questing/EExtraSkipCondition.cs b/Questionable.Model/Questing/EExtraSkipCondition.cs new file mode 100644 index 00000000..3f2836a9 --- /dev/null +++ b/Questionable.Model/Questing/EExtraSkipCondition.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(SkipConditionConverter))] +public enum EExtraSkipCondition +{ + None, + WakingSandsMainArea, +} diff --git a/Questionable.Model/Questing/EInteractionType.cs b/Questionable.Model/Questing/EInteractionType.cs new file mode 100644 index 00000000..5080714a --- /dev/null +++ b/Questionable.Model/Questing/EInteractionType.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(InteractionTypeConverter))] +public enum EInteractionType +{ + Interact, + WalkTo, + AttuneAethernetShard, + AttuneAetheryte, + AttuneAetherCurrent, + Combat, + UseItem, + EquipItem, + Say, + Emote, + Action, + WaitForObjectAtPosition, + WaitForManualProgress, + Duty, + SinglePlayerDuty, + Jump, + Dive, + + /// + /// Needs to be manually continued. + /// + Instruction, + + AcceptQuest, + CompleteQuest, +} diff --git a/Questionable.Model/Questing/EJumpType.cs b/Questionable.Model/Questing/EJumpType.cs new file mode 100644 index 00000000..e89931ac --- /dev/null +++ b/Questionable.Model/Questing/EJumpType.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(JumpTypeConverter))] +public enum EJumpType +{ + SingleJump, + RepeatedJumps, +} diff --git a/Questionable.Model/Questing/ELockedSkipCondition.cs b/Questionable.Model/Questing/ELockedSkipCondition.cs new file mode 100644 index 00000000..7755b129 --- /dev/null +++ b/Questionable.Model/Questing/ELockedSkipCondition.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(LockedSkipConditionConverter))] +public enum ELockedSkipCondition +{ + Locked, + Unlocked, +} diff --git a/Questionable.Model/Questing/EQuestWorkMode.cs b/Questionable.Model/Questing/EQuestWorkMode.cs new file mode 100644 index 00000000..3d835225 --- /dev/null +++ b/Questionable.Model/Questing/EQuestWorkMode.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(QuestWorkModeConverter))] +public enum EQuestWorkMode +{ + Bitwise, + Exact, +} diff --git a/Questionable.Model/Questing/ExcelRef.cs b/Questionable.Model/Questing/ExcelRef.cs new file mode 100644 index 00000000..cdb55014 --- /dev/null +++ b/Questionable.Model/Questing/ExcelRef.cs @@ -0,0 +1,68 @@ +using System; + +namespace Questionable.Model.Questing; + +public class ExcelRef +{ + private readonly string? _stringValue; + private readonly uint? _rowIdValue; + + public ExcelRef(string value) + { + _stringValue = value; + _rowIdValue = null; + Type = EType.Key; + } + + public ExcelRef(uint value) + { + _stringValue = null; + _rowIdValue = value; + Type = EType.RowId; + } + + private ExcelRef(string? stringValue, uint? rowIdValue, EType type) + { + _stringValue = stringValue; + _rowIdValue = rowIdValue; + Type = type; + } + + public static ExcelRef FromKey(string value) => new(value, null, EType.Key); + public static ExcelRef FromRowId(uint rowId) => new(null, rowId, EType.RowId); + public static ExcelRef FromSheetValue(string value) => new(value, null, EType.RawString); + + public EType Type { get; } + + public string AsKey() + { + if (Type != EType.Key) + throw new InvalidOperationException(); + + return _stringValue!; + } + + public uint AsRowId() + { + if (Type != EType.RowId) + throw new InvalidOperationException(); + + return _rowIdValue!.Value; + } + + public string AsRawString() + { + if (Type != EType.RawString) + throw new InvalidOperationException(); + + return _stringValue!; + } + + public enum EType + { + None, + Key, + RowId, + RawString, + } +} diff --git a/Questionable.Model/Questing/JumpDestination.cs b/Questionable.Model/Questing/JumpDestination.cs new file mode 100644 index 00000000..9682e21e --- /dev/null +++ b/Questionable.Model/Questing/JumpDestination.cs @@ -0,0 +1,18 @@ +using System.Numerics; +using System.Text.Json.Serialization; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +public sealed class JumpDestination +{ + [JsonConverter(typeof(VectorConverter))] + public Vector3 Position { get; set; } + + public float? StopDistance { get; set; } + public float? DelaySeconds { get; set; } + public EJumpType Type { get; set; } = EJumpType.SingleJump; + + public float CalculateStopDistance() => StopDistance ?? 1f; +} diff --git a/Questionable.Model/Questing/QuestRoot.cs b/Questionable.Model/Questing/QuestRoot.cs new file mode 100644 index 00000000..e1158fc8 --- /dev/null +++ b/Questionable.Model/Questing/QuestRoot.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +public sealed class QuestRoot +{ + [JsonConverter(typeof(StringListOrValueConverter))] + public List Author { get; set; } = new(); + + /// + /// This is only relevant for release builds. + /// + public bool Disabled { get; set; } + + public string? Comment { get; set; } + public List TerritoryBlacklist { get; set; } = new(); + public List QuestSequence { get; set; } = new(); +} diff --git a/Questionable.Model/Questing/QuestSequence.cs b/Questionable.Model/Questing/QuestSequence.cs new file mode 100644 index 00000000..3e42e098 --- /dev/null +++ b/Questionable.Model/Questing/QuestSequence.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Questionable.Model.Questing; + +public sealed class QuestSequence +{ + public int Sequence { get; set; } + public string? Comment { get; set; } + public List Steps { get; set; } = new(); + + public QuestStep? FindStep(int step) + { + if (step < 0 || step >= Steps.Count) + return null; + + return Steps[step]; + } + + public QuestStep? LastStep() => Steps.LastOrDefault(); +} diff --git a/Questionable.Model/Questing/QuestStep.cs b/Questionable.Model/Questing/QuestStep.cs new file mode 100644 index 00000000..53ed7ced --- /dev/null +++ b/Questionable.Model/Questing/QuestStep.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Numerics; +using System.Text.Json.Serialization; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +public sealed class QuestStep +{ + public const float DefaultStopDistance = 3f; + + public EInteractionType InteractionType { get; set; } + + public uint? DataId { get; set; } + + [JsonConverter(typeof(VectorConverter))] + public Vector3? Position { get; set; } + + public float? StopDistance { get; set; } + public float? NpcWaitDistance { get; set; } + public ushort TerritoryId { get; set; } + public ushort? TargetTerritoryId { get; set; } + public float? DelaySecondsAtStart { get; set; } + + public bool Disabled { get; set; } + public bool DisableNavmesh { get; set; } + public bool? Mount { get; set; } + public bool? Fly { get; set; } + public bool? Land { get; set; } + public bool? Sprint { get; set; } + public bool? IgnoreDistanceToObject { get; set; } + public string? Comment { get; set; } + + /// + /// Only used when attuning to an aetheryte. + /// + public EAetheryteLocation? Aetheryte { get; set; } + + /// + /// Only used when attuning to an aethernet shard. + /// + [JsonConverter(typeof(AethernetShardConverter))] + public EAetheryteLocation? AethernetShard { get; set; } + + public EAetheryteLocation? AetheryteShortcut { get; set; } + + public AethernetShortcut? AethernetShortcut { get; set; } + public uint? AetherCurrentId { get; set; } + + public uint? ItemId { get; set; } + public bool? GroundTarget { get; set; } + + public EEmote? Emote { get; set; } + public ChatMessage? ChatMessage { get; set; } + public EAction? Action { get; set; } + + public EEnemySpawnType? EnemySpawnType { get; set; } + public IList KillEnemyDataIds { get; set; } = new List(); + public IList ComplexCombatData { get; set; } = new List(); + public float? CombatDelaySecondsAtStart { get; set; } + + public JumpDestination? JumpDestination { get; set; } + public uint? ContentFinderConditionId { get; set; } + public SkipConditions? SkipConditions { get; set; } + + public List?> RequiredQuestVariables { get; set; } = new(); + public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public IList DialogueChoices { get; set; } = new List(); + public IList PointMenuChoices { get; set; } = new List(); + + // TODO: Not implemented + public ushort? PickUpQuestId { get; set; } + + public ushort? TurnInQuestId { get; set; } + public ushort? NextQuestId { get; set; } + + [JsonConstructor] + public QuestStep() + { + } + + public QuestStep(EInteractionType interactionType, uint? dataId, Vector3? position, ushort territoryId) + { + InteractionType = interactionType; + DataId = dataId; + Position = position; + TerritoryId = territoryId; + } + + public float CalculateActualStopDistance() + { + if (InteractionType == EInteractionType.WalkTo) + return StopDistance ?? 0.25f; + if (InteractionType == EInteractionType.AttuneAetheryte) + return StopDistance ?? 10f; + else + return StopDistance ?? DefaultStopDistance; + } +} diff --git a/Questionable.Model/Questing/QuestWorkValue.cs b/Questionable.Model/Questing/QuestWorkValue.cs new file mode 100644 index 00000000..d4db77ef --- /dev/null +++ b/Questionable.Model/Questing/QuestWorkValue.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.Json.Serialization; +using Questionable.Model.Questing.Converter; + +namespace Questionable.Model.Questing; + +[JsonConverter(typeof(QuestWorkConfigConverter))] +public sealed class QuestWorkValue(byte? high, byte? low, EQuestWorkMode mode) +{ + public QuestWorkValue(byte value) + : this((byte)(value >> 4), (byte)(value & 0xF), EQuestWorkMode.Bitwise) + { + } + + public byte? High { get; set; } = high; + public byte? Low { get; set; } = low; + public EQuestWorkMode Mode { get; set; } = mode; + + public override string ToString() + { + if (High != null && Low != null) + return ((byte)(High << 4) + Low).ToString(); + else if (High != null) + return High + "H"; + else if (Low != null) + return Low + "L"; + else + return "-"; + } +} diff --git a/Questionable.Model/Questing/SkipAetheryteCondition.cs b/Questionable.Model/Questing/SkipAetheryteCondition.cs new file mode 100644 index 00000000..0109e4de --- /dev/null +++ b/Questionable.Model/Questing/SkipAetheryteCondition.cs @@ -0,0 +1,7 @@ +namespace Questionable.Model.Questing; + +public sealed class SkipAetheryteCondition +{ + public bool Never { get; set; } + public bool InSameTerritory { get; set; } +} diff --git a/Questionable.Model/Questing/SkipConditions.cs b/Questionable.Model/Questing/SkipConditions.cs new file mode 100644 index 00000000..6525ec0f --- /dev/null +++ b/Questionable.Model/Questing/SkipConditions.cs @@ -0,0 +1,8 @@ +namespace Questionable.Model.Questing; + +public sealed class SkipConditions +{ + public SkipStepConditions? StepIf { get; set; } + public SkipAetheryteCondition? AetheryteShortcutIf { get; set; } + public SkipAetheryteCondition? AethernetShortcutIf { get; set; } +} diff --git a/Questionable.Model/Questing/SkipItemConditions.cs b/Questionable.Model/Questing/SkipItemConditions.cs new file mode 100644 index 00000000..04c38f6e --- /dev/null +++ b/Questionable.Model/Questing/SkipItemConditions.cs @@ -0,0 +1,6 @@ +namespace Questionable.Model.Questing; + +public sealed class SkipItemConditions +{ + public bool NotInInventory { get; set; } +} diff --git a/Questionable.Model/Questing/SkipStepConditions.cs b/Questionable.Model/Questing/SkipStepConditions.cs new file mode 100644 index 00000000..ee7e7dcf --- /dev/null +++ b/Questionable.Model/Questing/SkipStepConditions.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Questionable.Model.Questing; + +public sealed class SkipStepConditions +{ + public bool Never { get; set; } + public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public ELockedSkipCondition? Flying { get; set; } + public ELockedSkipCondition? Chocobo { get; set; } + public bool NotTargetable { get; set; } + public List InTerritory { get; set; } = new(); + public List NotInTerritory { get; set; } = new(); + public SkipItemConditions? Item { get; set; } + public List QuestsAccepted { get; set; } = new(); + public List QuestsCompleted { get; set; } = new(); + public EExtraSkipCondition? ExtraCondition { get; set; } + + public bool HasSkipConditions() + { + if (Never) + return false; + return (CompletionQuestVariablesFlags.Count > 0 && CompletionQuestVariablesFlags.Any(x => x != null)) || + Flying != null || + Chocobo != null || + NotTargetable || + InTerritory.Count > 0 || + NotInTerritory.Count > 0 || + Item != null || + QuestsAccepted.Count > 0 || + QuestsCompleted.Count > 0 || + ExtraCondition != null; + } + + public override string ToString() + { + return + $"{nameof(Never)}: {Never}, {nameof(CompletionQuestVariablesFlags)}: {CompletionQuestVariablesFlags}, {nameof(Flying)}: {Flying}, {nameof(Chocobo)}: {Chocobo}, {nameof(NotTargetable)}: {NotTargetable}, {nameof(InTerritory)}: {string.Join(" ", InTerritory)}, {nameof(NotInTerritory)}: {string.Join(" ", NotInTerritory)}, {nameof(Item)}: {Item}, {nameof(QuestsAccepted)}: {string.Join(" ", QuestsAccepted)}, {nameof(QuestsCompleted)}: {string.Join(" ", QuestsCompleted)}, {nameof(ExtraCondition)}: {ExtraCondition}"; + } +} diff --git a/Questionable.Model/Questionable.Model.csproj b/Questionable.Model/Questionable.Model.csproj index cb320ec5..54301430 100644 --- a/Questionable.Model/Questionable.Model.csproj +++ b/Questionable.Model/Questionable.Model.csproj @@ -13,4 +13,12 @@ + + + + + + Questionable.Model.CommonSchema + + diff --git a/Questionable.Model/V1/AethernetShortcut.cs b/Questionable.Model/V1/AethernetShortcut.cs deleted file mode 100644 index 40514b58..00000000 --- a/Questionable.Model/V1/AethernetShortcut.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(AethernetShortcutConverter))] -public sealed class AethernetShortcut -{ - public EAetheryteLocation From { get; set; } - public EAetheryteLocation To { get; set; } -} diff --git a/Questionable.Model/V1/ChatMessage.cs b/Questionable.Model/V1/ChatMessage.cs deleted file mode 100644 index 71721380..00000000 --- a/Questionable.Model/V1/ChatMessage.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Questionable.Model.V1; - -public sealed class ChatMessage -{ - public string? ExcelSheet { get; set; } - public string Key { get; set; } = null!; -} diff --git a/Questionable.Model/V1/ComplexCombatData.cs b/Questionable.Model/V1/ComplexCombatData.cs deleted file mode 100644 index d31de7e2..00000000 --- a/Questionable.Model/V1/ComplexCombatData.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1; - -public sealed class ComplexCombatData -{ - public uint DataId { get; set; } - - // TODO Use this - public uint? MinimumKillCount { get; set; } - - /// - /// If a reward item has been set, this is (ping allowing) given to the player before the dead enemy despawns. - /// - public uint? RewardItemId { get; set; } - public int? RewardItemCount { get; set; } - public IList CompletionQuestVariablesFlags { get; set; } = new List(); - public bool IgnoreQuestMarker { get; set; } -} diff --git a/Questionable.Model/V1/Converter/ActionConverter.cs b/Questionable.Model/V1/Converter/ActionConverter.cs deleted file mode 100644 index eaf5baac..00000000 --- a/Questionable.Model/V1/Converter/ActionConverter.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class ActionConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EAction.Cure, "Cure" }, - { EAction.Esuna, "Esuna" }, - { EAction.Physick, "Physick" }, - { EAction.Buffet, "Buffet" }, - { EAction.Fumigate, "Fumigate" }, - { EAction.SiphonSnout, "Siphon Snout" }, - { EAction.RedGulal, "Red Gulal" }, - { EAction.YellowGulal, "Yellow Gulal" }, - { EAction.BlueGulal, "Blue Gulal" }, - }; -} diff --git a/Questionable.Model/V1/Converter/AethernetShardConverter.cs b/Questionable.Model/V1/Converter/AethernetShardConverter.cs deleted file mode 100644 index bfb259c2..00000000 --- a/Questionable.Model/V1/Converter/AethernetShardConverter.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class AethernetShardConverter() : EnumConverter(Values) -{ - public static readonly Dictionary Values = new() - { - { EAetheryteLocation.Gridania, "[Gridania] Aetheryte Plaza" }, - { EAetheryteLocation.GridaniaArcher, "[Gridania] Archers' Guild" }, - { EAetheryteLocation.GridaniaLeatherworker, "[Gridania] Leatherworkers' Guild & Shaded Bower" }, - { EAetheryteLocation.GridaniaLancer, "[Gridania] Lancers' Guild" }, - { EAetheryteLocation.GridaniaConjurer, "[Gridania] Conjurers' Guild" }, - { EAetheryteLocation.GridaniaBotanist, "[Gridania] Botanists' Guild" }, - { EAetheryteLocation.GridaniaAmphitheatre, "[Gridania] Mih Khetto's Amphitheatre" }, - { EAetheryteLocation.GridaniaBlueBadgerGate, "[Gridania] Blue Badger Gate (Central Shroud)" }, - { EAetheryteLocation.GridaniaYellowSerpentGate, "[Gridania] Yellow Serpent Gate (North Shroud)" }, - { EAetheryteLocation.GridaniaWhiteWolfGate, "[Gridania] White Wolf Gate (Central Shroud)" }, - { EAetheryteLocation.GridaniaAirship, "[Gridania] Airship Landing" }, - - { EAetheryteLocation.Uldah, "[Ul'dah] Aetheryte Plaza" }, - { EAetheryteLocation.UldahAdventurers, "[Ul'dah] Adventurers' Guild" }, - { EAetheryteLocation.UldahThaumaturge, "[Ul'dah] Thaumaturges' Guild" }, - { EAetheryteLocation.UldahGladiator, "[Ul'dah] Gladiators' Guild" }, - { EAetheryteLocation.UldahMiner, "[Ul'dah] Miners' Guild" }, - { EAetheryteLocation.UldahWeaver, "[Ul'dah] Weavers' Guild" }, - { EAetheryteLocation.UldahGoldsmith, "[Ul'dah] Goldsmiths' Guild" }, - { EAetheryteLocation.UldahSapphireAvenue, "[Ul'dah] Sapphire Avenue Exchange" }, - { EAetheryteLocation.UldahAlchemist, "[Ul'dah] Alchemists' Guild" }, - { EAetheryteLocation.UldahChamberOfRule, "[Ul'dah] The Chamber of Rule" }, - { EAetheryteLocation.UldahGateOfTheSultana, "[Ul'dah] Gate of the Sultana (Western Thanalan)" }, - { EAetheryteLocation.UldahGateOfNald, "[Ul'dah] Gate of Nald (Central Thanalan)" }, - { EAetheryteLocation.UldahGateOfThal, "[Ul'dah] Gate of Thal (Central Thanalan)" }, - { EAetheryteLocation.UldahAirship, "[Ul'dah] Airship Landing" }, - - { EAetheryteLocation.Limsa, "[Limsa Lominsa] Aetheryte Plaza" }, - { EAetheryteLocation.LimsaArcanist, "[Limsa Lominsa] Arcanists' Guild" }, - { EAetheryteLocation.LimsaFisher, "[Limsa Lominsa] Fishermens' Guild" }, - { EAetheryteLocation.LimsaHawkersAlley, "[Limsa Lominsa] Hawkers' Alley" }, - { EAetheryteLocation.LimsaAftcastle, "[Limsa Lominsa] The Aftcastle" }, - { EAetheryteLocation.LimsaCulinarian, "[Limsa Lominsa] Culinarians' Guild" }, - { EAetheryteLocation.LimsaMarauder, "[Limsa Lominsa] Marauders' Guild" }, - { EAetheryteLocation.LimsaZephyrGate, "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)" }, - { EAetheryteLocation.LimsaTempestGate, "[Limsa Lominsa] Tempest Gate (Lower La Noscea)" }, - { EAetheryteLocation.LimsaAirship, "[Limsa Lominsa] Airship Landing" }, - - { EAetheryteLocation.Ishgard, "[Ishgard] Aetheryte Plaza" }, - { EAetheryteLocation.IshgardForgottenKnight, "[Ishgard] The Forgotten Knight" }, - { EAetheryteLocation.IshgardSkysteelManufactory, "[Ishgard] Skysteel Manufactory" }, - { EAetheryteLocation.IshgardBrume, "[Ishgard] The Brume" }, - { EAetheryteLocation.IshgardAthenaeumAstrologicum, "[Ishgard] Athenaeum Astrologicum" }, - { EAetheryteLocation.IshgardJeweledCrozier, "[Ishgard] The Jeweled Crozier" }, - { EAetheryteLocation.IshgardSaintReymanaudsCathedral, "[Ishgard] Saint Reymanaud's Cathedral" }, - { EAetheryteLocation.IshgardTribunal, "[Ishgard] The Tribunal" }, - { EAetheryteLocation.IshgardLastVigil, "[Ishgard] The Last Vigil" }, - { EAetheryteLocation.IshgardGatesOfJudgement, "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)" }, - - { EAetheryteLocation.Idyllshire, "[Idyllshire] Aetheryte Plaza" }, - { EAetheryteLocation.IdyllshireWest, "[Idyllshire] West Idyllshire" }, - { EAetheryteLocation.IdyllshirePrologueGate, "[Idyllshire] Prologue Gate (Western Hinterlands)" }, - { EAetheryteLocation.IdyllshireEpilogueGate, "[Idyllshire] Epilogue Gate (Eastern Hinterlands)" }, - - { EAetheryteLocation.RhalgrsReach, "[Rhalgr's Reach] Aetheryte Plaza" }, - { EAetheryteLocation.RhalgrsReachWest, "[Rhalgr's Reach] Western Rhalgr's Reach" }, - { EAetheryteLocation.RhalgrsReachNorthEast, "[Rhalgr's Reach] Northeastern Rhalgr's Reach" }, - { EAetheryteLocation.RhalgrsReachFringesGate, "[Rhalgr's Reach] Fringes Gate" }, - { EAetheryteLocation.RhalgrsReachPeaksGate, "[Rhalgr's Reach] Peaks Gate" }, - - { EAetheryteLocation.Kugane, "[Kugane] Aetheryte Plaza" }, - { EAetheryteLocation.KuganeShiokazeHostelry, "[Kugane] Shiokaze Hostelry" }, - { EAetheryteLocation.KuganePier1, "[Kugane] Pier #1" }, - { EAetheryteLocation.KuganeThavnairianConsulate, "[Kugane] Thavnairian Consulate" }, - { EAetheryteLocation.KuganeMarkets, "[Kugane] Kogane Dori Markets" }, - { EAetheryteLocation.KuganeBokairoInn, "[Kugane] Bokairo Inn" }, - { EAetheryteLocation.KuganeRubyBazaar, "[Kugane] The Ruby Bazaar" }, - { EAetheryteLocation.KuganeSekiseigumiBarracks, "[Kugane] Sekiseigumi Barracks" }, - { EAetheryteLocation.KuganeRakuzaDistrict, "[Kugane] Rakuza District" }, - { EAetheryteLocation.KuganeRubyPrice, "[Kugane] The Ruby Price" }, - { EAetheryteLocation.KuganeAirship, "[Kugane] Airship Landing" }, - - { EAetheryteLocation.Crystarium, "[Crystarium] Aetheryte Plaza" }, - { EAetheryteLocation.CrystariumMarkets, "[Crystarium] Musica Universalis Markets" }, - { EAetheryteLocation.CrystariumTemenosRookery, "[Crystarium] Temenos Rookery" }, - { EAetheryteLocation.CrystariumDossalGate, "[Crystarium] The Dossal Gate" }, - { EAetheryteLocation.CrystariumPendants, "[Crystarium] The Pendants" }, - { EAetheryteLocation.CrystariumAmaroLaunch, "[Crystarium] The Amaro Launch" }, - { EAetheryteLocation.CrystariumCrystallineMean, "[Crystarium] The Crystalline Mean" }, - { EAetheryteLocation.CrystariumCabinetOfCuriosity, "[Crystarium] The Cabinet of Curiosity" }, - { EAetheryteLocation.CrystariumTessellation, "[Crystarium] Tessellation (Lakeland)" }, - - { EAetheryteLocation.Eulmore, "[Eulmore] Aetheryte Plaza" }, - { EAetheryteLocation.EulmoreSoutheastDerelict, "[Eulmore] Southeast Derelicts" }, - { EAetheryteLocation.EulmoreNightsoilPots, "[Eulmore] Nightsoil Pots" }, - { EAetheryteLocation.EulmoreGloryGate, "[Eulmore] The Glory Gate" }, - { EAetheryteLocation.EulmoreMainstay, "[Eulmore] The Mainstay" }, - { EAetheryteLocation.EulmorePathToGlory, "[Eulmore] The Path to Glory (Kholusia)" }, - - { EAetheryteLocation.OldSharlayan, "[Old Sharlayan] Aetheryte Plaza" }, - { EAetheryteLocation.OldSharlayanStudium, "[Old Sharlayan] The Studium" }, - { EAetheryteLocation.OldSharlayanBaldesionAnnex, "[Old Sharlayan] The Baldesion Annex" }, - { EAetheryteLocation.OldSharlayanRostra, "[Old Sharlayan] The Rostra" }, - { EAetheryteLocation.OldSharlayanLeveilleurEstate, "[Old Sharlayan] The Leveilleur Estate" }, - { EAetheryteLocation.OldSharlayanJourneysEnd, "[Old Sharlayan] Journey's End" }, - { EAetheryteLocation.OldSharlayanScholarsHarbor, "[Old Sharlayan] Scholar's Harbor" }, - { EAetheryteLocation.OldSharlayanHallOfArtifice, "[Old Sharlayan] The Hall of Artifice (Labyrinthos)" }, - - { EAetheryteLocation.RadzAtHan, "[Radz-at-Han] Aetheryte Plaza" }, - { EAetheryteLocation.RadzAtHanMeghaduta, "[Radz-at-Han] Meghaduta" }, - { EAetheryteLocation.RadzAtHanRuveydahFibers, "[Radz-at-Han] Ruveydah Fibers" }, - { EAetheryteLocation.RadzAtHanAirship, "[Radz-at-Han] Airship Landing" }, - { EAetheryteLocation.RadzAtHanAlzadaalsPeace, "[Radz-at-Han] Alzadaal's Peace" }, - { EAetheryteLocation.RadzAtHanHallOfTheRadiantHost, "[Radz-at-Han] Hall of the Radiant Host" }, - { EAetheryteLocation.RadzAtHanMehrydesMeyhane, "[Radz-at-Han] Mehryde's Meyhane" }, - { EAetheryteLocation.RadzAtHanKama, "[Radz-at-Han] Kama" }, - { EAetheryteLocation.RadzAtHanHighCrucible, "[Radz-at-Han] The High Crucible of Al-Kimiya" }, - { EAetheryteLocation.RadzAtHanGateOfFirstSight, "[Radz-at-Han] The Gate of First Sight (Thavnair)" }, - - { EAetheryteLocation.Tuliyollal, "[Tuliyollal] Aetheryte Plaza" }, - { EAetheryteLocation.TuliyollalDirigibleLanding, "[Tuliyollal] Dirigible Landing" }, - { EAetheryteLocation.TuliyollalTheResplendentQuarter, "[Tuliyollal] The Resplendent Quarter" }, - { EAetheryteLocation.TuliyollalTheForardCabins, "[Tuliyollal] The For'ard Cabins" }, - { EAetheryteLocation.TuliyollalBaysideBevyMarketplace, "[Tuliyollal] Bayside Bevy Marketplace" }, - { EAetheryteLocation.TuliyollalVollokShoonsa, "[Tuliyollal] Vollok Shoonsa" }, - { EAetheryteLocation.TuliyollalWachumeqimeqi, "[Tuliyollal] Wachumeqimeqi" }, - { EAetheryteLocation.TuliyollalBrightploomPost, "[Tuliyollal] Brightploom Post" }, - { EAetheryteLocation.TuliyollalArchOfTheDawnUrqopacha, "[Tuliyollal] Arch of the Dawn (Urqopacha)" }, - { EAetheryteLocation.TuliyollalArchOfTheDawnKozamauka, "[Tuliyollal] Arch of the Dawn (Kozama'uka)" }, - { EAetheryteLocation.TuliyollalIhuykatumu, "[Tuliyollal] Ihuykatumu (Kozama'uka)" }, - { EAetheryteLocation.TuliyollalDirigibleLandingYakTel, "[Tuliyollal] Dirigible Landing (Yak T'el)" }, - { EAetheryteLocation.TuliyollalXakTuralSkygate, "[Tuliyollal] Xak Tural Skygate (Shaaloani)" }, - - { EAetheryteLocation.SolutionNine, "[Solution Nine] Aetheryte Plaza" }, - { EAetheryteLocation.SolutionNineInformationCenter, "[Solution Nine] Information Center" }, - { EAetheryteLocation.SolutionNineTrueVue, "[Solution Nine] True Vue" }, - { EAetheryteLocation.SolutionNineNeonStein, "[Solution Nine] Neon Stein" }, - { EAetheryteLocation.SolutionNineTheArcadion, "[Solution Nine] The Arcadion" }, - { EAetheryteLocation.SolutionNineResolution, "[Solution Nine] Resolution" }, - { EAetheryteLocation.SolutionNineNexusArcade, "[Solution Nine] Nexus Arcade" }, - { EAetheryteLocation.SolutionNineResidentialSector, "[Solution Nine] Residential Sector" }, - { EAetheryteLocation.SolutionNineScanningPortNine, "[Solution Nine] Scanning Port Nine (Heritage Found)" }, - }; -} diff --git a/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs b/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs deleted file mode 100644 index 8b90769f..00000000 --- a/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public sealed class AethernetShortcutConverter : JsonConverter -{ - private static readonly Dictionary EnumToString = AethernetShardConverter.Values; - private static readonly Dictionary StringToEnum = - EnumToString.ToDictionary(x => x.Value, x => x.Key); - - public override AethernetShortcut Read(ref Utf8JsonReader reader, Type typeToConvert, - JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.StartArray) - throw new JsonException(); - - if (!reader.Read() || reader.TokenType != JsonTokenType.String) - throw new JsonException(); - - string from = reader.GetString() ?? throw new JsonException(); - - if (!reader.Read() || reader.TokenType != JsonTokenType.String) - throw new JsonException(); - - string to = reader.GetString() ?? throw new JsonException(); - - if (!reader.Read() || reader.TokenType != JsonTokenType.EndArray) - throw new JsonException(); - - return new AethernetShortcut - { - From = StringToEnum.TryGetValue(from, out var fromEnum) ? fromEnum : throw new JsonException(), - To = StringToEnum.TryGetValue(to, out var toEnum) ? toEnum : throw new JsonException() - }; - } - - public override void Write(Utf8JsonWriter writer, AethernetShortcut value, JsonSerializerOptions options) - { - writer.WriteStartArray(); - writer.WriteStringValue(EnumToString[value.From]); - writer.WriteStringValue(EnumToString[value.To]); - writer.WriteEndArray(); - } -} diff --git a/Questionable.Model/V1/Converter/AetheryteConverter.cs b/Questionable.Model/V1/Converter/AetheryteConverter.cs deleted file mode 100644 index ab0dd549..00000000 --- a/Questionable.Model/V1/Converter/AetheryteConverter.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class AetheryteConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EAetheryteLocation.Gridania, "Gridania" }, - { EAetheryteLocation.CentralShroudBentbranchMeadows, "Central Shroud - Bentbranch Meadows" }, - { EAetheryteLocation.EastShroudHawthorneHut, "East Shroud - Hawthorne Hut" }, - { EAetheryteLocation.SouthShroudQuarrymill, "South Shroud - Quarrymill" }, - { EAetheryteLocation.SouthShroudCampTranquil, "South Shroud - Camp Tranquil" }, - { EAetheryteLocation.NorthShroudFallgourdFloat, "North Shroud - Fallgourd Float" }, - - { EAetheryteLocation.Uldah, "Ul'dah" }, - { EAetheryteLocation.WesternThanalanHorizon, "Western Thanalan - Horizon" }, - { EAetheryteLocation.CentralThanalanBlackBrushStation, "Central Thanalan - Black Brush Station" }, - { EAetheryteLocation.EasternThanalanCampDrybone, "Eastern Thanalan - Camp Drybone" }, - { EAetheryteLocation.SouthernThanalanLittleAlaMhigo, "Southern Thanalan - Little Ala Mhigo" }, - { EAetheryteLocation.SouthernThanalanForgottenSprings, "Southern Thanalan - Forgotten Springs" }, - { EAetheryteLocation.NorthernThanalanCampBluefog, "Northern Thanalan - Camp Bluefog" }, - { EAetheryteLocation.NorthernThanalanCeruleumProcessingPlant, "Northern Thanalan - Ceruleum Processing Plant" }, - - { EAetheryteLocation.Limsa, "Limsa Lominsa" }, - { EAetheryteLocation.MiddleLaNosceaSummerfordFarms, "Middle La Noscea - Summerford Farms" }, - { EAetheryteLocation.LowerLaNosceaMorabyDrydocks, "Lower La Noscea - Moraby Drydocks" }, - { EAetheryteLocation.EasternLaNosceaCostaDelSol, "Eastern La Noscea - Costa Del Sol" }, - { EAetheryteLocation.EasternLaNosceaWineport, "Eastern La Noscea - Wineport" }, - { EAetheryteLocation.WesternLaNosceaSwiftperch, "Western La Noscea - Swiftperch" }, - { EAetheryteLocation.WesternLaNosceaAleport, "Western La Noscea - Aleport" }, - { EAetheryteLocation.UpperLaNosceaCampBronzeLake, "Upper La Noscea - Camp Bronze Lake" }, - { EAetheryteLocation.OuterLaNosceaCampOverlook, "Outer La Noscea - Camp Overlook" }, - - { EAetheryteLocation.CoerthasCentralHighlandsCampDragonhead, "Coerthas Central Highlands - Camp Dragonhead" }, - { EAetheryteLocation.MorDhona, "Mor Dhona" }, - { EAetheryteLocation.GoldSaucer, "Gold Saucer" }, - { EAetheryteLocation.WolvesDenPier, "Wolves' Den Pier" }, - - { EAetheryteLocation.Ishgard, "Ishgard" }, - { EAetheryteLocation.Idyllshire, "Idyllshire" }, - { EAetheryteLocation.CoerthasWesternHighlandsFalconsNest, "Coerthas Western Highlands - Falcon's Nest" }, - { EAetheryteLocation.SeaOfCloudsCampCloudtop, "The Sea of Clouds - Camp Cloudtop" }, - { EAetheryteLocation.SeaOfCloudsOkZundu, "The Sea of Clouds - Ok' Zundu" }, - { EAetheryteLocation.AzysLlaHelix, "Azys Lla - Helix" }, - { EAetheryteLocation.DravanianForelandsTailfeather, "The Dravanian Forelands - Tailfeather" }, - { EAetheryteLocation.DravanianForelandsAnyxTrine, "The Dravanian Forelands - Anyx Trine" }, - { EAetheryteLocation.ChurningMistsMoghome, "The Churning Mists - Moghome" }, - { EAetheryteLocation.ChurningMistsZenith, "The Churning Mists - Zenith" }, - - { EAetheryteLocation.RhalgrsReach, "Rhalgr's Reach" }, - { EAetheryteLocation.FringesCastrumOriens, "Fringes - Castrum Oriens" }, - { EAetheryteLocation.FringesPeeringStones, "Fringes - Peering Stones" }, - { EAetheryteLocation.PeaksAlaGannha, "Peaks - Ala Gannha" }, - { EAetheryteLocation.PeaksAlaGhiri, "Peaks - Ala Ghiri" }, - { EAetheryteLocation.LochsPortaPraetoria, "Lochs - Porta Praetoria" }, - { EAetheryteLocation.LochsAlaMhiganQuarter, "Lochs - Ala Mhigan Quarter" }, - { EAetheryteLocation.Kugane, "Kugane" }, - { EAetheryteLocation.RubySeaTamamizu, "Ruby Sea - Tamamizu" }, - { EAetheryteLocation.RubySeaOnokoro, "Ruby Sea - Onokoro" }, - { EAetheryteLocation.YanxiaNamai, "Yanxia - Namai" }, - { EAetheryteLocation.YanxiaHouseOfTheFierce, "Yanxia - House of the Fierce" }, - { EAetheryteLocation.AzimSteppeReunion, "Azim Steppe - Reunion" }, - { EAetheryteLocation.AzimSteppeDawnThrone, "Azim Steppe - Dawn Throne" }, - { EAetheryteLocation.AzimSteppeDhoroIloh, "Azim Steppe - Dhoro Iloh" }, - { EAetheryteLocation.DomanEnclave, "Doman Enclave" }, - - { EAetheryteLocation.Crystarium, "Crystarium" }, - { EAetheryteLocation.Eulmore, "Eulmore" }, - { EAetheryteLocation.LakelandFortJobb, "Lakeland - Fort Jobb" }, - { EAetheryteLocation.LakelandOstallImperative, "Lakeland - Ostall Imperative" }, - { EAetheryteLocation.KholusiaStilltide, "Kholusia - Stilltide" }, - { EAetheryteLocation.KholusiaWright, "Kholusia - Wright" }, - { EAetheryteLocation.KholusiaTomra, "Kholusia - Tomra" }, - { EAetheryteLocation.AmhAraengMordSouq, "Amh Araeng - Mord Souq" }, - { EAetheryteLocation.AmhAraengInnAtJourneysHead, "Amh Araeng - Inn at Journey's Head" }, - { EAetheryteLocation.AmhAraengTwine, "Amh Araeng - Twine" }, - { EAetheryteLocation.RaktikaSlitherbough, "Rak'tika - Slitherbough" }, - { EAetheryteLocation.RaktikaFanow, "Rak'tika - Fanow" }, - { EAetheryteLocation.IlMhegLydhaLran, "Il Mheg - Lydha Lran" }, - { EAetheryteLocation.IlMhegPiaEnni, "Il Mheg - Pia Enni" }, - { EAetheryteLocation.IlMhegWolekdorf, "Il Mheg - Wolekdorf" }, - { EAetheryteLocation.TempestOndoCups, "Tempest - Ondo Cups" }, - { EAetheryteLocation.TempestMacarensesAngle, "Tempest - Macarenses Angle" }, - - { EAetheryteLocation.OldSharlayan, "Old Sharlayan" }, - { EAetheryteLocation.RadzAtHan, "Radz-at-Han" }, - { EAetheryteLocation.LabyrinthosArcheion, "Labyrinthos - Archeion" }, - { EAetheryteLocation.LabyrinthosSharlayanHamlet, "Labyrinthos - Sharlayan Hamlet" }, - { EAetheryteLocation.LabyrinthosAporia, "Labyrinthos - Aporia" }, - { EAetheryteLocation.ThavnairYedlihmad, "Thavnair - Yedlihmad" }, - { EAetheryteLocation.ThavnairGreatWork, "Thavnair - Great Work" }, - { EAetheryteLocation.ThavnairPalakasStand, "Thavnair - Palaka's Stand" }, - { EAetheryteLocation.GarlemaldCampBrokenGlass, "Garlemald - Camp Broken Glass" }, - { EAetheryteLocation.GarlemaldTertium, "Garlemald - Tertium" }, - { EAetheryteLocation.MareLamentorumSinusLacrimarum, "Mare Lamentorum - Sinus Lacrimarum" }, - { EAetheryteLocation.MareLamentorumBestwaysBurrow, "Mare Lamentorum - Bestways Burrow" }, - { EAetheryteLocation.ElpisAnagnorisis, "Elpis - Anagnorisis" }, - { EAetheryteLocation.ElpisTwelveWonders, "Elpis - Twelve Wonders" }, - { EAetheryteLocation.ElpisPoietenOikos, "Elpis - Poieten Oikos" }, - { EAetheryteLocation.UltimaThuleReahTahra, "Ultima Thule - Reah Tahra" }, - { EAetheryteLocation.UltimaThuleAbodeOfTheEa, "Ultima Thule - Abode of the Ea" }, - { EAetheryteLocation.UltimaThuleBaseOmicron, "Ultima Thule - Base Omicron" }, - - { EAetheryteLocation.Tuliyollal, "Tuliyollal" }, - { EAetheryteLocation.SolutionNine, "Solution Nine" }, - { EAetheryteLocation.UrqopachaWachunpelo, "Urqopacha - Wachunpelo" }, - { EAetheryteLocation.UrqopachaWorlarsEcho, "Urqopacha - Worlar's Echo" }, - { EAetheryteLocation.KozamaukaOkHanu, "Kozama'uka - Ok'hanu" }, - { EAetheryteLocation.KozamaukaManyFires, "Kozama'uka - Many Fires" }, - { EAetheryteLocation.KozamaukaEarthenshire, "Kozama'uka - Earthenshire" }, - { EAetheryteLocation.YakTelIqBraax, "Yak T'el - Iq Br'aax" }, - { EAetheryteLocation.YakTelMamook, "Yak T'el - Mamook" }, - { EAetheryteLocation.ShaaloaniHhusatahwi, "Shaaloani - Hhusatahwi" }, - { EAetheryteLocation.ShaaloaniShesheneweziSprings, "Shaaloani - Sheshenewezi Springs" }, - { EAetheryteLocation.ShaaloaniMehwahhetsoan, "Shaaloani - Mehwahhetsoan" }, - { EAetheryteLocation.HeritageFoundYyasulaniStation, "Heritage Found - Yyasulani Station" }, - { EAetheryteLocation.HeritageFoundTheOutskirts, "Heritage Found - The Outskirts" }, - { EAetheryteLocation.HeritageFoundElectropeStrike, "Heritage Found - Electrope Strike" }, - { EAetheryteLocation.LivingMemoryLeynodeMnemo, "Living Memory - Leynode Mnemo" }, - { EAetheryteLocation.LivingMemoryLeynodePyro, "Living Memory - Leynode Pyro" }, - { EAetheryteLocation.LivingMemoryLeynodeAero, "Living Memory - Leynode Aero" }, - }; - - public static bool IsLargeAetheryte(EAetheryteLocation aetheryte) => Values.ContainsKey(aetheryte); -} diff --git a/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs b/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs deleted file mode 100644 index ea832cac..00000000 --- a/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class DialogueChoiceTypeConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EDialogChoiceType.YesNo, "YesNo" }, - { EDialogChoiceType.List, "List" }, - }; -} diff --git a/Questionable.Model/V1/Converter/EmoteConverter.cs b/Questionable.Model/V1/Converter/EmoteConverter.cs deleted file mode 100644 index 8a327517..00000000 --- a/Questionable.Model/V1/Converter/EmoteConverter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class EmoteConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EEmote.Stretch, "stretch" }, - { EEmote.Wave, "wave" }, - { EEmote.Rally, "rally" }, - { EEmote.Deny, "deny" }, - { EEmote.Pray, "pray" }, - { EEmote.Slap, "slap" }, - { EEmote.Doubt, "doubt" }, - { EEmote.Psych, "psych" }, - { EEmote.Cheer, "cheer" }, - { EEmote.Happy, "happy" }, - { EEmote.Poke, "poke" }, - { EEmote.Flex, "flex" }, - { EEmote.Soothe, "soothe" }, - { EEmote.Me, "me" }, - { EEmote.Welcome, "welcome" }, - { EEmote.ImperialSalute, "imperialsalute" }, - { EEmote.Pet, "pet" }, - { EEmote.Dance, "dance" }, - { EEmote.Respect, "respect" }, - { EEmote.Lookout, "lookout" }, - { EEmote.Kneel, "kneel" }, - { EEmote.Bow, "bow" }, - }; -} diff --git a/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs b/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs deleted file mode 100644 index 5c5de532..00000000 --- a/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class EnemySpawnTypeConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EEnemySpawnType.AfterInteraction, "AfterInteraction" }, - { EEnemySpawnType.AfterItemUse, "AfterItemUse" }, - { EEnemySpawnType.AutoOnEnterArea, "AutoOnEnterArea" }, - { EEnemySpawnType.OverworldEnemies, "OverworldEnemies" }, - }; -} diff --git a/Questionable.Model/V1/Converter/EnumConverter.cs b/Questionable.Model/V1/Converter/EnumConverter.cs deleted file mode 100644 index 3ed1267b..00000000 --- a/Questionable.Model/V1/Converter/EnumConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public abstract class EnumConverter : JsonConverter - where T : Enum -{ - private readonly ReadOnlyDictionary _enumToString; - private readonly ReadOnlyDictionary _stringToEnum; - - protected EnumConverter(IReadOnlyDictionary values) - { - _enumToString = values is IDictionary dict - ? new ReadOnlyDictionary(dict) - : new ReadOnlyDictionary(values.ToDictionary(x => x.Key, x => x.Value)); - _stringToEnum = new ReadOnlyDictionary(_enumToString.ToDictionary(x => x.Value, x => x.Key)); - } - - public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, - JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.String) - throw new JsonException(); - - string? str = reader.GetString(); - if (str == null) - throw new JsonException(); - - return _stringToEnum.TryGetValue(str, out T? value) ? value : throw new JsonException(); - } - - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - writer.WriteStringValue(_enumToString[value]); - } -} diff --git a/Questionable.Model/V1/Converter/ExcelRefConverter.cs b/Questionable.Model/V1/Converter/ExcelRefConverter.cs deleted file mode 100644 index 06ba3ff1..00000000 --- a/Questionable.Model/V1/Converter/ExcelRefConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public sealed class ExcelRefConverter : JsonConverter -{ - public override ExcelRef? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.TokenType switch - { - JsonTokenType.String => ExcelRef.FromKey(reader.GetString()!), - JsonTokenType.Number => ExcelRef.FromRowId(reader.GetUInt32()), - _ => null - }; - } - - public override void Write(Utf8JsonWriter writer, ExcelRef? value, JsonSerializerOptions options) - { - if (value == null) - writer.WriteNullValue(); - else if (value.Type == ExcelRef.EType.Key) - writer.WriteStringValue(value.AsKey()); - else if (value.Type == ExcelRef.EType.RowId) - writer.WriteNumberValue(value.AsRowId()); - else - throw new JsonException(); - } -} diff --git a/Questionable.Model/V1/Converter/InteractionTypeConverter.cs b/Questionable.Model/V1/Converter/InteractionTypeConverter.cs deleted file mode 100644 index 08be6ff6..00000000 --- a/Questionable.Model/V1/Converter/InteractionTypeConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class InteractionTypeConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EInteractionType.Interact, "Interact" }, - { EInteractionType.WalkTo, "WalkTo" }, - { EInteractionType.AttuneAethernetShard, "AttuneAethernetShard" }, - { EInteractionType.AttuneAetheryte, "AttuneAetheryte" }, - { EInteractionType.AttuneAetherCurrent, "AttuneAetherCurrent" }, - { EInteractionType.Combat, "Combat" }, - { EInteractionType.UseItem, "UseItem" }, - { EInteractionType.EquipItem, "EquipItem" }, - { EInteractionType.Say, "Say" }, - { EInteractionType.Emote, "Emote" }, - { EInteractionType.Action, "Action" }, - { EInteractionType.WaitForObjectAtPosition, "WaitForNpcAtPosition" }, - { EInteractionType.WaitForManualProgress, "WaitForManualProgress" }, - { EInteractionType.Duty, "Duty" }, - { EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" }, - { EInteractionType.Jump, "Jump" }, - { EInteractionType.Dive, "Dive" }, - { EInteractionType.Instruction, "Instruction" }, - { EInteractionType.AcceptQuest, "AcceptQuest" }, - { EInteractionType.CompleteQuest, "CompleteQuest" }, - }; -} diff --git a/Questionable.Model/V1/Converter/JumpTypeConverter.cs b/Questionable.Model/V1/Converter/JumpTypeConverter.cs deleted file mode 100644 index 94c8ea2b..00000000 --- a/Questionable.Model/V1/Converter/JumpTypeConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class JumpTypeConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EJumpType.SingleJump, "SingleJump" }, - { EJumpType.RepeatedJumps, "RepeatedJumps" }, - }; -} diff --git a/Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs b/Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs deleted file mode 100644 index 5d53058e..00000000 --- a/Questionable.Model/V1/Converter/LockedSkipConditionConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class LockedSkipConditionConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { ELockedSkipCondition.Locked, "Locked" }, - { ELockedSkipCondition.Unlocked, "Unlocked" }, - }; -} diff --git a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs b/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs deleted file mode 100644 index 2b376937..00000000 --- a/Questionable.Model/V1/Converter/QuestWorkConfigConverter.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public sealed class QuestWorkConfigConverter : JsonConverter -{ - public override QuestWorkValue Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Number) - return new QuestWorkValue(reader.GetByte()); - - if (reader.TokenType != JsonTokenType.StartObject) - throw new JsonException(); - - byte? high = null, low = null; - EQuestWorkMode mode = EQuestWorkMode.Bitwise; - while (reader.Read()) - { - switch (reader.TokenType) - { - case JsonTokenType.PropertyName: - string? propertyName = reader.GetString(); - if (propertyName == null || !reader.Read()) - throw new JsonException(); - - switch (propertyName) - { - case nameof(QuestWorkValue.High): - high = reader.GetByte(); - break; - - case nameof(QuestWorkValue.Low): - low = reader.GetByte(); - break; - - case nameof(QuestWorkValue.Mode): - mode = new QuestWorkModeConverter().Read(ref reader, typeof(EQuestWorkMode), options); - break; - - default: - throw new JsonException(); - } - - break; - - case JsonTokenType.EndObject: - return new QuestWorkValue(high, low, mode); - - default: - throw new JsonException(); - } - } - - throw new JsonException(); - } - - public override void Write(Utf8JsonWriter writer, QuestWorkValue value, JsonSerializerOptions options) - { - throw new NotImplementedException(); - } -} diff --git a/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs b/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs deleted file mode 100644 index a3697d66..00000000 --- a/Questionable.Model/V1/Converter/QuestWorkModeConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class QuestWorkModeConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EQuestWorkMode.Bitwise, "Bitwise" }, - { EQuestWorkMode.Exact, "Exact" }, - }; -} diff --git a/Questionable.Model/V1/Converter/SkipConditionConverter.cs b/Questionable.Model/V1/Converter/SkipConditionConverter.cs deleted file mode 100644 index f4b4e6fc..00000000 --- a/Questionable.Model/V1/Converter/SkipConditionConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -public sealed class SkipConditionConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { EExtraSkipCondition.WakingSandsMainArea, "WakingSandsMainArea" }, - }; -} diff --git a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs b/Questionable.Model/V1/Converter/StringListOrValueConverter.cs deleted file mode 100644 index b6da81a2..00000000 --- a/Questionable.Model/V1/Converter/StringListOrValueConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public sealed class StringListOrValueConverter : JsonConverter> -{ - public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - return [reader.GetString()!]; - - if (reader.TokenType != JsonTokenType.StartArray) - throw new JsonException(); - reader.Read(); - - List value = []; - while (reader.TokenType != JsonTokenType.EndArray) - { - value.Add(reader.GetString()!); - reader.Read(); - } - - return value; - } - - public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) - { - if (value == null) - writer.WriteNullValue(); - else if (value.Count == 1) - writer.WriteStringValue(value[0]); - else - { - writer.WriteStartArray(); - foreach (var v in value) - writer.WriteStringValue(v); - writer.WriteEndArray(); - } - } -} diff --git a/Questionable.Model/V1/Converter/VectorConverter.cs b/Questionable.Model/V1/Converter/VectorConverter.cs deleted file mode 100644 index f75ffe6a..00000000 --- a/Questionable.Model/V1/Converter/VectorConverter.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Numerics; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -public sealed class VectorConverter : JsonConverter -{ - public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType != JsonTokenType.StartObject) - throw new JsonException(); - - Vector3 vec = new Vector3(); - while (reader.Read()) - { - switch (reader.TokenType) - { - case JsonTokenType.PropertyName: - string? propertyName = reader.GetString(); - if (propertyName == null || !reader.Read()) - throw new JsonException(); - - switch (propertyName) - { - case nameof(Vector3.X): - vec.X = reader.GetSingle(); - break; - - case nameof(Vector3.Y): - vec.Y = reader.GetSingle(); - break; - - case nameof(Vector3.Z): - vec.Z = reader.GetSingle(); - break; - - default: - throw new JsonException(); - } - - break; - - case JsonTokenType.EndObject: - return vec; - - default: - throw new JsonException(); - } - } - - throw new JsonException(); - } - - public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options) - { - writer.WriteStartObject(); - writer.WriteNumber(nameof(Vector3.X), value.X); - writer.WriteNumber(nameof(Vector3.Y), value.X); - writer.WriteNumber(nameof(Vector3.Z), value.X); - writer.WriteEndObject(); - } -} diff --git a/Questionable.Model/V1/DialogueChoice.cs b/Questionable.Model/V1/DialogueChoice.cs deleted file mode 100644 index 80b49d05..00000000 --- a/Questionable.Model/V1/DialogueChoice.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -public sealed class DialogueChoice -{ - [JsonConverter(typeof(DialogueChoiceTypeConverter))] - public EDialogChoiceType Type { get; set; } - public string? ExcelSheet { get; set; } - - [JsonConverter(typeof(ExcelRefConverter))] - public ExcelRef? Prompt { get; set; } - - public bool Yes { get; set; } = true; - - [JsonConverter(typeof(ExcelRefConverter))] - public ExcelRef? Answer { get; set; } - - /// - /// If set, only applies when focusing the given target id. - /// - public uint? DataId { get; set; } -} diff --git a/Questionable.Model/V1/EAction.cs b/Questionable.Model/V1/EAction.cs deleted file mode 100644 index 8aca752f..00000000 --- a/Questionable.Model/V1/EAction.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(ActionConverter))] -public enum EAction -{ - Cure = 120, - Esuna = 7568, - Physick = 190, - Buffet = 4931, - Fumigate = 5872, - SiphonSnout = 18187, - RedGulal = 29382, - YellowGulal = 29383, - BlueGulal = 29384, -} - -public static class EActionExtensions -{ - public static bool RequiresMount(this EAction action) - { - return action - is EAction.Buffet - or EAction.Fumigate - or EAction.SiphonSnout - or EAction.RedGulal - or EAction.YellowGulal - or EAction.BlueGulal; - } -} diff --git a/Questionable.Model/V1/EAetheryteLocation.cs b/Questionable.Model/V1/EAetheryteLocation.cs deleted file mode 100644 index 1ddde305..00000000 --- a/Questionable.Model/V1/EAetheryteLocation.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(AetheryteConverter))] -public enum EAetheryteLocation -{ - None = 0, - - Gridania = 2, - GridaniaArcher = 25, - GridaniaLeatherworker = 26, - GridaniaLancer = 27, - GridaniaConjurer = 28, - GridaniaBotanist = 29, - GridaniaAmphitheatre = 30, - GridaniaBlueBadgerGate = 31, - GridaniaYellowSerpentGate = 32, - GridaniaWhiteWolfGate = 54, - GridaniaAirship = 94, - - CentralShroudBentbranchMeadows = 3, - EastShroudHawthorneHut = 4, - SouthShroudQuarrymill = 5, - SouthShroudCampTranquil = 6, - NorthShroudFallgourdFloat = 7, - - Uldah = 9, - UldahAdventurers = 33, - UldahThaumaturge = 34, - UldahGladiator = 35, - UldahMiner = 36, - UldahAlchemist = 37, - UldahWeaver = 47, - UldahGoldsmith = 50, - UldahChamberOfRule = 51, - UldahAirship = 95, - UldahGateOfTheSultana = 38, - UldahGateOfNald = 39, - UldahGateOfThal = 40, - UldahSapphireAvenue = 125, - - WesternThanalanHorizon = 17, - EasternThanalanCampDrybone = 18, - SouthernThanalanLittleAlaMhigo = 19, - SouthernThanalanForgottenSprings = 20, - NorthernThanalanCampBluefog = 21, - NorthernThanalanCeruleumProcessingPlant = 22, - CentralThanalanBlackBrushStation = 53, - - Limsa = 8, - LimsaAftcastle = 41, - LimsaCulinarian = 42, - LimsaArcanist = 43, - LimsaFisher = 44, - LimsaMarauder = 48, - LimsaHawkersAlley = 49, - LimsaZephyrGate = 45, - LimsaTempestGate = 46, - LimsaAirship = 93, - - LowerLaNosceaMorabyDrydocks = 10, - EasternLaNosceaCostaDelSol = 11, - EasternLaNosceaWineport = 12, - WesternLaNosceaSwiftperch = 13, - WesternLaNosceaAleport = 14, - UpperLaNosceaCampBronzeLake = 15, - OuterLaNosceaCampOverlook = 16, - MiddleLaNosceaSummerfordFarms = 52, - - CoerthasCentralHighlandsCampDragonhead = 23, - MorDhona = 24, - GoldSaucer = 62, - WolvesDenPier = 55, - - Ishgard = 70, - IshgardForgottenKnight = 80, - IshgardSkysteelManufactory = 81, - IshgardBrume = 82, - IshgardAthenaeumAstrologicum = 83, - IshgardJeweledCrozier = 84, - IshgardSaintReymanaudsCathedral = 85, - IshgardTribunal = 86, - IshgardLastVigil = 87, - IshgardGatesOfJudgement = 88, - - Idyllshire = 75, - IdyllshireWest = 90, - IdyllshirePrologueGate = 91, - IdyllshireEpilogueGate = 92, - - CoerthasWesternHighlandsFalconsNest = 71, - SeaOfCloudsCampCloudtop = 72, - SeaOfCloudsOkZundu = 73, - AzysLlaHelix = 74, - DravanianForelandsTailfeather = 76, - DravanianForelandsAnyxTrine = 77, - ChurningMistsMoghome = 78, - ChurningMistsZenith = 79, - - RhalgrsReach = 104, - RhalgrsReachWest = 121, - RhalgrsReachNorthEast = 122, - RhalgrsReachFringesGate = 123, - RhalgrsReachPeaksGate = 124, - - Kugane = 111, - KuganeShiokazeHostelry = 112, - KuganePier1 = 113, - KuganeThavnairianConsulate = 114, - KuganeMarkets = 115, - KuganeBokairoInn = 116, - KuganeRubyBazaar = 117, - KuganeSekiseigumiBarracks = 118, - KuganeRakuzaDistrict = 119, - KuganeRubyPrice = 120, - KuganeAirship = 126, - - FringesCastrumOriens = 98, - FringesPeeringStones = 99, - PeaksAlaGannha = 100, - PeaksAlaGhiri = 101, - LochsPortaPraetoria = 102, - LochsAlaMhiganQuarter = 103, - RubySeaTamamizu = 105, - RubySeaOnokoro = 106, - YanxiaNamai = 107, - YanxiaHouseOfTheFierce = 108, - AzimSteppeReunion = 109, - AzimSteppeDawnThrone = 110, - AzimSteppeDhoroIloh = 128, - - DomanEnclave = 127, - DomanEnclaveNorthern = 129, - DomanEnclaveSouthern = 130, - DomanEnclaveOneRiver = 131, - DomanEnclaveDocks = 162, - - Crystarium = 133, - CrystariumMarkets = 149, - CrystariumTemenosRookery = 150, - CrystariumDossalGate = 151, - CrystariumPendants = 152, - CrystariumAmaroLaunch = 153, - CrystariumCrystallineMean = 154, - CrystariumCabinetOfCuriosity = 155, - CrystariumTessellation = 156, - - Eulmore = 134, - EulmoreMainstay = 157, - EulmoreNightsoilPots = 158, - EulmoreGloryGate = 159, - EulmoreSoutheastDerelict = 135, - EulmorePathToGlory = 160, - - LakelandFortJobb = 132, - LakelandOstallImperative = 136, - KholusiaStilltide = 137, - KholusiaWright = 138, - KholusiaTomra = 139, - AmhAraengMordSouq = 140, - AmhAraengInnAtJourneysHead = 161, - AmhAraengTwine = 141, - RaktikaSlitherbough = 142, - RaktikaFanow = 143, - IlMhegLydhaLran = 144, - IlMhegPiaEnni = 145, - IlMhegWolekdorf = 146, - TempestOndoCups = 147, - TempestMacarensesAngle = 148, - - OldSharlayan = 182, - OldSharlayanStudium = 184, - OldSharlayanBaldesionAnnex = 185, - OldSharlayanRostra = 186, - OldSharlayanLeveilleurEstate = 187, - OldSharlayanJourneysEnd = 188, - OldSharlayanScholarsHarbor = 189, - OldSharlayanHallOfArtifice = 190, - - RadzAtHan = 183, - RadzAtHanMeghaduta = 191, - RadzAtHanRuveydahFibers = 192, - RadzAtHanAirship = 193, - RadzAtHanAlzadaalsPeace = 194, - RadzAtHanHallOfTheRadiantHost = 195, - RadzAtHanMehrydesMeyhane = 196, - RadzAtHanKama = 198, - RadzAtHanHighCrucible = 199, - RadzAtHanGateOfFirstSight = 197, - - LabyrinthosArcheion = 166, - LabyrinthosSharlayanHamlet = 167, - LabyrinthosAporia = 168, - ThavnairYedlihmad = 169, - ThavnairGreatWork = 170, - ThavnairPalakasStand = 171, - GarlemaldCampBrokenGlass = 172, - GarlemaldTertium = 173, - MareLamentorumSinusLacrimarum = 174, - MareLamentorumBestwaysBurrow = 175, - ElpisAnagnorisis = 176, - ElpisTwelveWonders = 177, - ElpisPoietenOikos = 178, - UltimaThuleReahTahra = 179, - UltimaThuleAbodeOfTheEa = 180, - UltimaThuleBaseOmicron = 181, - - Tuliyollal = 216, - - TuliyollalDirigibleLanding = 218, - TuliyollalTheResplendentQuarter = 219, - TuliyollalTheForardCabins = 220, - TuliyollalBaysideBevyMarketplace = 221, - TuliyollalVollokShoonsa = 222, - TuliyollalWachumeqimeqi = 223, - TuliyollalBrightploomPost = 224, - TuliyollalArchOfTheDawnUrqopacha = 225, - TuliyollalArchOfTheDawnKozamauka = 226, - TuliyollalIhuykatumu = 227, - TuliyollalDirigibleLandingYakTel = 228, - TuliyollalXakTuralSkygate = 229, - - SolutionNine = 217, - SolutionNineInformationCenter = 230, - SolutionNineTrueVue = 231, - SolutionNineNeonStein = 232, - SolutionNineTheArcadion = 233, - SolutionNineResolution = 234, - SolutionNineNexusArcade = 235, - SolutionNineResidentialSector = 236, - SolutionNineScanningPortNine = 237, - - UrqopachaWachunpelo = 200, - UrqopachaWorlarsEcho = 201, - KozamaukaOkHanu = 202, - KozamaukaManyFires = 203, - KozamaukaEarthenshire = 204, - YakTelIqBraax = 205, - YakTelMamook = 206, - ShaaloaniHhusatahwi = 207, - ShaaloaniShesheneweziSprings = 208, - ShaaloaniMehwahhetsoan = 209, - HeritageFoundYyasulaniStation = 210, - HeritageFoundTheOutskirts = 211, - HeritageFoundElectropeStrike = 212, - LivingMemoryLeynodeMnemo = 213, - LivingMemoryLeynodePyro = 214, - LivingMemoryLeynodeAero = 215, -} diff --git a/Questionable.Model/V1/EDialogChoiceType.cs b/Questionable.Model/V1/EDialogChoiceType.cs deleted file mode 100644 index 066639a3..00000000 --- a/Questionable.Model/V1/EDialogChoiceType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Questionable.Model.V1; - -public enum EDialogChoiceType -{ - None, - YesNo, - List, -} diff --git a/Questionable.Model/V1/EEmote.cs b/Questionable.Model/V1/EEmote.cs deleted file mode 100644 index 6657a1dd..00000000 --- a/Questionable.Model/V1/EEmote.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(EmoteConverter))] -public enum EEmote -{ - None = 0, - - Stretch = 37, - Wave = 16, - Rally = 34, - Deny = 25, - Pray = 58, - Slap = 111, - Doubt = 12, - Psych = 30, - Cheer = 6, - Happy = 48, - Poke = 28, - Flex = 139, - Soothe = 35, - Me = 23, - Welcome = 41, - ImperialSalute = 59, - Pet = 105, - Dance = 11, - Respect = 140, - Lookout = 22, - Kneel = 19, - Bow = 5, -} diff --git a/Questionable.Model/V1/EEnemySpawnType.cs b/Questionable.Model/V1/EEnemySpawnType.cs deleted file mode 100644 index 8465f011..00000000 --- a/Questionable.Model/V1/EEnemySpawnType.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(EnemySpawnTypeConverter))] -public enum EEnemySpawnType -{ - None = 0, - AfterInteraction, - AfterItemUse, - AutoOnEnterArea, - OverworldEnemies, -} diff --git a/Questionable.Model/V1/EExtraSkipCondition.cs b/Questionable.Model/V1/EExtraSkipCondition.cs deleted file mode 100644 index 227bf0f2..00000000 --- a/Questionable.Model/V1/EExtraSkipCondition.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(SkipConditionConverter))] -public enum EExtraSkipCondition -{ - None, - WakingSandsMainArea, -} diff --git a/Questionable.Model/V1/EInteractionType.cs b/Questionable.Model/V1/EInteractionType.cs deleted file mode 100644 index 843f600d..00000000 --- a/Questionable.Model/V1/EInteractionType.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(InteractionTypeConverter))] -public enum EInteractionType -{ - Interact, - WalkTo, - AttuneAethernetShard, - AttuneAetheryte, - AttuneAetherCurrent, - Combat, - UseItem, - EquipItem, - Say, - Emote, - Action, - WaitForObjectAtPosition, - WaitForManualProgress, - Duty, - SinglePlayerDuty, - Jump, - Dive, - - /// - /// Needs to be manually continued. - /// - Instruction, - - AcceptQuest, - CompleteQuest, -} diff --git a/Questionable.Model/V1/EJumpType.cs b/Questionable.Model/V1/EJumpType.cs deleted file mode 100644 index b06365eb..00000000 --- a/Questionable.Model/V1/EJumpType.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(JumpTypeConverter))] -public enum EJumpType -{ - SingleJump, - RepeatedJumps, -} diff --git a/Questionable.Model/V1/ELockedSkipCondition.cs b/Questionable.Model/V1/ELockedSkipCondition.cs deleted file mode 100644 index 2863c262..00000000 --- a/Questionable.Model/V1/ELockedSkipCondition.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(LockedSkipConditionConverter))] -public enum ELockedSkipCondition -{ - Locked, - Unlocked, -} diff --git a/Questionable.Model/V1/EQuestWorkMode.cs b/Questionable.Model/V1/EQuestWorkMode.cs deleted file mode 100644 index ef225b23..00000000 --- a/Questionable.Model/V1/EQuestWorkMode.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(QuestWorkModeConverter))] -public enum EQuestWorkMode -{ - Bitwise, - Exact, -} diff --git a/Questionable.Model/V1/ExcelRef.cs b/Questionable.Model/V1/ExcelRef.cs deleted file mode 100644 index 295dd5ba..00000000 --- a/Questionable.Model/V1/ExcelRef.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; - -namespace Questionable.Model.V1; - -public class ExcelRef -{ - private readonly string? _stringValue; - private readonly uint? _rowIdValue; - - public ExcelRef(string value) - { - _stringValue = value; - _rowIdValue = null; - Type = EType.Key; - } - - public ExcelRef(uint value) - { - _stringValue = null; - _rowIdValue = value; - Type = EType.RowId; - } - - private ExcelRef(string? stringValue, uint? rowIdValue, EType type) - { - _stringValue = stringValue; - _rowIdValue = rowIdValue; - Type = type; - } - - public static ExcelRef FromKey(string value) => new(value, null, EType.Key); - public static ExcelRef FromRowId(uint rowId) => new(null, rowId, EType.RowId); - public static ExcelRef FromSheetValue(string value) => new(value, null, EType.RawString); - - public EType Type { get; } - - public string AsKey() - { - if (Type != EType.Key) - throw new InvalidOperationException(); - - return _stringValue!; - } - - public uint AsRowId() - { - if (Type != EType.RowId) - throw new InvalidOperationException(); - - return _rowIdValue!.Value; - } - - public string AsRawString() - { - if (Type != EType.RawString) - throw new InvalidOperationException(); - - return _stringValue!; - } - - public enum EType - { - None, - Key, - RowId, - RawString, - } -} diff --git a/Questionable.Model/V1/JumpDestination.cs b/Questionable.Model/V1/JumpDestination.cs deleted file mode 100644 index 2497560a..00000000 --- a/Questionable.Model/V1/JumpDestination.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Numerics; -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -public sealed class JumpDestination -{ - [JsonConverter(typeof(VectorConverter))] - public Vector3 Position { get; set; } - - public float? StopDistance { get; set; } - public float? DelaySeconds { get; set; } - public EJumpType Type { get; set; } = EJumpType.SingleJump; - - public float CalculateStopDistance() => StopDistance ?? 1f; -} diff --git a/Questionable.Model/V1/QuestRoot.cs b/Questionable.Model/V1/QuestRoot.cs deleted file mode 100644 index ada2e9fd..00000000 --- a/Questionable.Model/V1/QuestRoot.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -public sealed class QuestRoot -{ - [JsonConverter(typeof(StringListOrValueConverter))] - public List Author { get; set; } = new(); - - /// - /// This is only relevant for release builds. - /// - public bool Disabled { get; set; } - - public string? Comment { get; set; } - public List TerritoryBlacklist { get; set; } = new(); - public List QuestSequence { get; set; } = new(); -} diff --git a/Questionable.Model/V1/QuestSequence.cs b/Questionable.Model/V1/QuestSequence.cs deleted file mode 100644 index 73807e0b..00000000 --- a/Questionable.Model/V1/QuestSequence.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Questionable.Model.V1; - -public sealed class QuestSequence -{ - public int Sequence { get; set; } - public string? Comment { get; set; } - public List Steps { get; set; } = new(); - - public QuestStep? FindStep(int step) - { - if (step < 0 || step >= Steps.Count) - return null; - - return Steps[step]; - } - - public QuestStep? LastStep() => Steps.LastOrDefault(); -} diff --git a/Questionable.Model/V1/QuestStep.cs b/Questionable.Model/V1/QuestStep.cs deleted file mode 100644 index accd6623..00000000 --- a/Questionable.Model/V1/QuestStep.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System.Collections.Generic; -using System.Numerics; -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -public sealed class QuestStep -{ - public const float DefaultStopDistance = 3f; - - public EInteractionType InteractionType { get; set; } - - public uint? DataId { get; set; } - - [JsonConverter(typeof(VectorConverter))] - public Vector3? Position { get; set; } - - public float? StopDistance { get; set; } - public float? NpcWaitDistance { get; set; } - public ushort TerritoryId { get; set; } - public ushort? TargetTerritoryId { get; set; } - public float? DelaySecondsAtStart { get; set; } - - public bool Disabled { get; set; } - public bool DisableNavmesh { get; set; } - public bool? Mount { get; set; } - public bool? Fly { get; set; } - public bool? Land { get; set; } - public bool? Sprint { get; set; } - public bool? IgnoreDistanceToObject { get; set; } - public string? Comment { get; set; } - - /// - /// Only used when attuning to an aetheryte. - /// - public EAetheryteLocation? Aetheryte { get; set; } - - /// - /// Only used when attuning to an aethernet shard. - /// - [JsonConverter(typeof(AethernetShardConverter))] - public EAetheryteLocation? AethernetShard { get; set; } - - public EAetheryteLocation? AetheryteShortcut { get; set; } - - public AethernetShortcut? AethernetShortcut { get; set; } - public uint? AetherCurrentId { get; set; } - - public uint? ItemId { get; set; } - public bool? GroundTarget { get; set; } - - public EEmote? Emote { get; set; } - public ChatMessage? ChatMessage { get; set; } - public EAction? Action { get; set; } - - public EEnemySpawnType? EnemySpawnType { get; set; } - public IList KillEnemyDataIds { get; set; } = new List(); - public IList ComplexCombatData { get; set; } = new List(); - public float? CombatDelaySecondsAtStart { get; set; } - - public JumpDestination? JumpDestination { get; set; } - public uint? ContentFinderConditionId { get; set; } - public SkipConditions? SkipConditions { get; set; } - - public List?> RequiredQuestVariables { get; set; } = new(); - public IList CompletionQuestVariablesFlags { get; set; } = new List(); - public IList DialogueChoices { get; set; } = new List(); - public IList PointMenuChoices { get; set; } = new List(); - - // TODO: Not implemented - public ushort? PickUpQuestId { get; set; } - - public ushort? TurnInQuestId { get; set; } - public ushort? NextQuestId { get; set; } - - [JsonConstructor] - public QuestStep() - { - } - - public QuestStep(EInteractionType interactionType, uint? dataId, Vector3? position, ushort territoryId) - { - InteractionType = interactionType; - DataId = dataId; - Position = position; - TerritoryId = territoryId; - } - - public float CalculateActualStopDistance() - { - if (InteractionType == EInteractionType.WalkTo) - return StopDistance ?? 0.25f; - if (InteractionType == EInteractionType.AttuneAetheryte) - return StopDistance ?? 10f; - else - return StopDistance ?? DefaultStopDistance; - } -} diff --git a/Questionable.Model/V1/QuestWorkValue.cs b/Questionable.Model/V1/QuestWorkValue.cs deleted file mode 100644 index 75c68511..00000000 --- a/Questionable.Model/V1/QuestWorkValue.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(QuestWorkConfigConverter))] -public sealed class QuestWorkValue(byte? high, byte? low, EQuestWorkMode mode) -{ - public QuestWorkValue(byte value) - : this((byte)(value >> 4), (byte)(value & 0xF), EQuestWorkMode.Bitwise) - { - } - - public byte? High { get; set; } = high; - public byte? Low { get; set; } = low; - public EQuestWorkMode Mode { get; set; } = mode; - - public override string ToString() - { - if (High != null && Low != null) - return ((byte)(High << 4) + Low).ToString(); - else if (High != null) - return High + "H"; - else if (Low != null) - return Low + "L"; - else - return "-"; - } -} diff --git a/Questionable.Model/V1/SkipAetheryteCondition.cs b/Questionable.Model/V1/SkipAetheryteCondition.cs deleted file mode 100644 index 86d0a1c6..00000000 --- a/Questionable.Model/V1/SkipAetheryteCondition.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Questionable.Model.V1; - -public sealed class SkipAetheryteCondition -{ - public bool Never { get; set; } - public bool InSameTerritory { get; set; } -} diff --git a/Questionable.Model/V1/SkipConditions.cs b/Questionable.Model/V1/SkipConditions.cs deleted file mode 100644 index 5f866865..00000000 --- a/Questionable.Model/V1/SkipConditions.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Questionable.Model.V1; - -public sealed class SkipConditions -{ - public SkipStepConditions? StepIf { get; set; } - public SkipAetheryteCondition? AetheryteShortcutIf { get; set; } - public SkipAetheryteCondition? AethernetShortcutIf { get; set; } -} diff --git a/Questionable.Model/V1/SkipItemConditions.cs b/Questionable.Model/V1/SkipItemConditions.cs deleted file mode 100644 index 9154dcd4..00000000 --- a/Questionable.Model/V1/SkipItemConditions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Questionable.Model.V1; - -public sealed class SkipItemConditions -{ - public bool NotInInventory { get; set; } -} diff --git a/Questionable.Model/V1/SkipStepConditions.cs b/Questionable.Model/V1/SkipStepConditions.cs deleted file mode 100644 index be8df96b..00000000 --- a/Questionable.Model/V1/SkipStepConditions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace Questionable.Model.V1; - -public sealed class SkipStepConditions -{ - public bool Never { get; set; } - public IList CompletionQuestVariablesFlags { get; set; } = new List(); - public ELockedSkipCondition? Flying { get; set; } - public ELockedSkipCondition? Chocobo { get; set; } - public bool NotTargetable { get; set; } - public List InTerritory { get; set; } = new(); - public List NotInTerritory { get; set; } = new(); - public SkipItemConditions? Item { get; set; } - public List QuestsAccepted { get; set; } = new(); - public List QuestsCompleted { get; set; } = new(); - public EExtraSkipCondition? ExtraCondition { get; set; } - - public bool HasSkipConditions() - { - if (Never) - return false; - return (CompletionQuestVariablesFlags.Count > 0 && CompletionQuestVariablesFlags.Any(x => x != null)) || - Flying != null || - Chocobo != null || - NotTargetable || - InTerritory.Count > 0 || - NotInTerritory.Count > 0 || - Item != null || - QuestsAccepted.Count > 0 || - QuestsCompleted.Count > 0 || - ExtraCondition != null; - } - - public override string ToString() - { - return - $"{nameof(Never)}: {Never}, {nameof(CompletionQuestVariablesFlags)}: {CompletionQuestVariablesFlags}, {nameof(Flying)}: {Flying}, {nameof(Chocobo)}: {Chocobo}, {nameof(NotTargetable)}: {NotTargetable}, {nameof(InTerritory)}: {string.Join(" ", InTerritory)}, {nameof(NotInTerritory)}: {string.Join(" ", NotInTerritory)}, {nameof(Item)}: {Item}, {nameof(QuestsAccepted)}: {string.Join(" ", QuestsAccepted)}, {nameof(QuestsCompleted)}: {string.Join(" ", QuestsCompleted)}, {nameof(ExtraCondition)}: {ExtraCondition}"; - } -} diff --git a/Questionable.Model/common-schema.json b/Questionable.Model/common-schema.json new file mode 100644 index 00000000..6017ecb7 --- /dev/null +++ b/Questionable.Model/common-schema.json @@ -0,0 +1,299 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json", + "$defs": { + "Aetheryte": { + "type": "string", + "enum": [ + "Gridania", + "Central Shroud - Bentbranch Meadows", + "East Shroud - Hawthorne Hut", + "South Shroud - Quarrymill", + "South Shroud - Camp Tranquil", + "North Shroud - Fallgourd Float", + "Ul'dah", + "Western Thanalan - Horizon", + "Central Thanalan - Black Brush Station", + "Eastern Thanalan - Camp Drybone", + "Southern Thanalan - Little Ala Mhigo", + "Southern Thanalan - Forgotten Springs", + "Northern Thanalan - Camp Bluefog", + "Northern Thanalan - Ceruleum Processing Plant", + "Limsa Lominsa", + "Middle La Noscea - Summerford Farms", + "Lower La Noscea - Moraby Drydocks", + "Eastern La Noscea - Costa Del Sol", + "Eastern La Noscea - Wineport", + "Western La Noscea - Swiftperch", + "Western La Noscea - Aleport", + "Upper La Noscea - Camp Bronze Lake", + "Outer La Noscea - Camp Overlook", + "Coerthas Central Highlands - Camp Dragonhead", + "Mor Dhona", + "Gold Saucer", + "Wolves' Den Pier", + "Ishgard", + "Idyllshire", + "Coerthas Western Highlands - Falcon's Nest", + "The Sea of Clouds - Camp Cloudtop", + "The Sea of Clouds - Ok' Zundu", + "Azys Lla - Helix", + "The Dravanian Forelands - Tailfeather", + "The Dravanian Forelands - Anyx Trine", + "The Churning Mists - Moghome", + "The Churning Mists - Zenith", + "Rhalgr's Reach", + "Fringes - Castrum Oriens", + "Fringes - Peering Stones", + "Peaks - Ala Gannha", + "Peaks - Ala Ghiri", + "Lochs - Porta Praetoria", + "Lochs - Ala Mhigan Quarter", + "Kugane", + "Ruby Sea - Tamamizu", + "Ruby Sea - Onokoro", + "Yanxia - Namai", + "Yanxia - House of the Fierce", + "Azim Steppe - Reunion", + "Azim Steppe - Dawn Throne", + "Azim Steppe - Dhoro Iloh", + "Doman Enclave", + "Crystarium", + "Eulmore", + "Lakeland - Fort Jobb", + "Lakeland - Ostall Imperative", + "Kholusia - Stilltide", + "Kholusia - Wright", + "Kholusia - Tomra", + "Amh Araeng - Mord Souq", + "Amh Araeng - Inn at Journey's Head", + "Amh Araeng - Twine", + "Rak'tika - Slitherbough", + "Rak'tika - Fanow", + "Il Mheg - Lydha Lran", + "Il Mheg - Pia Enni", + "Il Mheg - Wolekdorf", + "Tempest - Ondo Cups", + "Tempest - Macarenses Angle", + "Old Sharlayan", + "Radz-at-Han", + "Labyrinthos - Archeion", + "Labyrinthos - Sharlayan Hamlet", + "Labyrinthos - Aporia", + "Thavnair - Yedlihmad", + "Thavnair - Great Work", + "Thavnair - Palaka's Stand", + "Garlemald - Camp Broken Glass", + "Garlemald - Tertium", + "Mare Lamentorum - Sinus Lacrimarum", + "Mare Lamentorum - Bestways Burrow", + "Elpis - Anagnorisis", + "Elpis - Twelve Wonders", + "Elpis - Poieten Oikos", + "Ultima Thule - Reah Tahra", + "Ultima Thule - Abode of the Ea", + "Ultima Thule - Base Omicron", + "Tuliyollal", + "Solution Nine", + "Urqopacha - Wachunpelo", + "Urqopacha - Worlar's Echo", + "Kozama'uka - Ok'hanu", + "Kozama'uka - Many Fires", + "Kozama'uka - Earthenshire", + "Yak T'el - Iq Br'aax", + "Yak T'el - Mamook", + "Shaaloani - Hhusatahwi", + "Shaaloani - Sheshenewezi Springs", + "Shaaloani - Mehwahhetsoan", + "Heritage Found - Yyasulani Station", + "Heritage Found - The Outskirts", + "Heritage Found - Electrope Strike", + "Living Memory - Leynode Mnemo", + "Living Memory - Leynode Pyro", + "Living Memory - Leynode Aero" + ] + }, + "AethernetShard": { + "type": "string", + "enum": [ + "[Gridania] Aetheryte Plaza", + "[Gridania] Archers' Guild", + "[Gridania] Leatherworkers' Guild & Shaded Bower", + "[Gridania] Lancers' Guild", + "[Gridania] Conjurers' Guild", + "[Gridania] Botanists' Guild", + "[Gridania] Mih Khetto's Amphitheatre", + "[Gridania] Blue Badger Gate (Central Shroud)", + "[Gridania] Yellow Serpent Gate (North Shroud)", + "[Gridania] White Wolf Gate (Central Shroud)", + "[Gridania] Airship Landing", + "[Ul'dah] Aetheryte Plaza", + "[Ul'dah] Adventurers' Guild", + "[Ul'dah] Thaumaturges' Guild", + "[Ul'dah] Gladiators' Guild", + "[Ul'dah] Miners' Guild", + "[Ul'dah] Weavers' Guild", + "[Ul'dah] Goldsmiths' Guild", + "[Ul'dah] Sapphire Avenue Exchange", + "[Ul'dah] Alchemists' Guild", + "[Ul'dah] Gate of the Sultana (Western Thanalan)", + "[Ul'dah] Gate of Nald (Central Thanalan)", + "[Ul'dah] Gate of Thal (Central Thanalan)", + "[Ul'dah] The Chamber of Rule", + "[Ul'dah] Airship Landing", + "[Limsa Lominsa] Aetheryte Plaza", + "[Limsa Lominsa] Arcanists' Guild", + "[Limsa Lominsa] Fishermens' Guild", + "[Limsa Lominsa] Hawkers' Alley", + "[Limsa Lominsa] The Aftcastle", + "[Limsa Lominsa] Culinarians' Guild", + "[Limsa Lominsa] Marauders' Guild", + "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)", + "[Limsa Lominsa] Tempest Gate (Lower La Noscea)", + "[Limsa Lominsa] Airship Landing", + "[Ishgard] Aetheryte Plaza", + "[Ishgard] The Forgotten Knight", + "[Ishgard] Skysteel Manufactory", + "[Ishgard] The Brume", + "[Ishgard] Athenaeum Astrologicum", + "[Ishgard] The Jeweled Crozier", + "[Ishgard] Saint Reymanaud's Cathedral", + "[Ishgard] The Tribunal", + "[Ishgard] The Last Vigil", + "[Ishgard] The Gates of Judgement (Coerthas Central Highlands)", + "[Idyllshire] Aetheryte Plaza", + "[Idyllshire] West Idyllshire", + "[Idyllshire] Prologue Gate (Western Hinterlands)", + "[Idyllshire] Epilogue Gate (Eastern Hinterlands)", + "[Rhalgr's Reach] Aetheryte Plaza", + "[Rhalgr's Reach] Western Rhalgr's Reach", + "[Rhalgr's Reach] Northeastern Rhalgr's Reach", + "[Rhalgr's Reach] Fringes Gate", + "[Rhalgr's Reach] Peaks Gate", + "[Kugane] Aetheryte Plaza", + "[Kugane] Shiokaze Hostelry", + "[Kugane] Pier #1", + "[Kugane] Thavnairian Consulate", + "[Kugane] Kogane Dori Markets", + "[Kugane] Bokairo Inn", + "[Kugane] The Ruby Bazaar", + "[Kugane] Sekiseigumi Barracks", + "[Kugane] Rakuza District", + "[Kugane] The Ruby Price", + "[Kugane] Airship Landing", + "[Crystarium] Aetheryte Plaza", + "[Crystarium] Musica Universalis Markets", + "[Crystarium] Temenos Rookery", + "[Crystarium] The Dossal Gate", + "[Crystarium] The Pendants", + "[Crystarium] The Amaro Launch", + "[Crystarium] The Crystalline Mean", + "[Crystarium] The Cabinet of Curiosity", + "[Crystarium] Tessellation (Lakeland)", + "[Eulmore] Aetheryte Plaza", + "[Eulmore] Southeast Derelicts", + "[Eulmore] Nightsoil Pots", + "[Eulmore] The Glory Gate", + "[Eulmore] The Mainstay", + "[Eulmore] The Path to Glory (Kholusia)", + "[Old Sharlayan] Aetheryte Plaza", + "[Old Sharlayan] The Studium", + "[Old Sharlayan] The Baldesion Annex", + "[Old Sharlayan] The Rostra", + "[Old Sharlayan] The Leveilleur Estate", + "[Old Sharlayan] Journey's End", + "[Old Sharlayan] Scholar's Harbor", + "[Old Sharlayan] The Hall of Artifice (Labyrinthos)", + "[Radz-at-Han] Aetheryte Plaza", + "[Radz-at-Han] Meghaduta", + "[Radz-at-Han] Ruveydah Fibers", + "[Radz-at-Han] Airship Landing", + "[Radz-at-Han] Alzadaal's Peace", + "[Radz-at-Han] Hall of the Radiant Host", + "[Radz-at-Han] Mehryde's Meyhane", + "[Radz-at-Han] Kama", + "[Radz-at-Han] The High Crucible of Al-Kimiya", + "[Radz-at-Han] The Gate of First Sight (Thavnair)", + "[Tuliyollal] Aetheryte Plaza", + "[Tuliyollal] Dirigible Landing", + "[Tuliyollal] The Resplendent Quarter", + "[Tuliyollal] The For'ard Cabins", + "[Tuliyollal] Bayside Bevy Marketplace", + "[Tuliyollal] Vollok Shoonsa", + "[Tuliyollal] Wachumeqimeqi", + "[Tuliyollal] Brightploom Post", + "[Tuliyollal] Arch of the Dawn (Urqopacha)", + "[Tuliyollal] Arch of the Dawn (Kozama'uka)", + "[Tuliyollal] Ihuykatumu (Kozama'uka)", + "[Tuliyollal] Dirigible Landing (Yak T'el)", + "[Tuliyollal] Xak Tural Skygate (Shaaloani)", + "[Solution Nine] Aetheryte Plaza", + "[Solution Nine] Information Center", + "[Solution Nine] True Vue", + "[Solution Nine] Neon Stein", + "[Solution Nine] The Arcadion", + "[Solution Nine] Resolution", + "[Solution Nine] Nexus Arcade", + "[Solution Nine] Residential Sector", + "[Solution Nine] Scanning Port Nine (Heritage Found)" + ] + }, + "CompletionFlags": { + "type": "array", + "description": "Quest Variables that dictate whether or not this step is skipped: null is don't check, positive values need to be set, negative values need to be unset", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "High": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Low": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "maximum": 15 + }, + "Negative": { + "type": "boolean" + }, + "Mode": { + "type": "string", + "enum": [ + "Bitwise", + "Exact" + ] + } + } + }, + { + "type": "number", + "enum": [ + 1, + 2, + 4, + 8, + 16, + 32, + 64, + 128 + ] + }, + { + "type": "null" + } + ] + }, + "minItems": 6, + "maxItems": 6 + } + } +} diff --git a/Questionable.sln b/Questionable.sln index a083acfb..b5314287 100644 --- a/Questionable.sln +++ b/Questionable.sln @@ -15,6 +15,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Questionable.Model", "Quest EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuestPathGenerator.Tests", "QuestPathGenerator.Tests\QuestPathGenerator.Tests.csproj", "{4FD6F346-8961-4BD5-BDA2-E5F426DE4FC7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPaths", "GatheringPaths\GatheringPaths.csproj", "{8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPathRenderer", "GatheringPathRenderer\GatheringPathRenderer.csproj", "{F514DA95-9867-4F3F-8062-ACE0C62E8740}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -45,6 +49,14 @@ Global {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Debug|x64.Build.0 = Debug|x64 {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|x64.ActiveCfg = Release|x64 {C91EEF13-A1AC-4A40-B695-DD4E378E5989}.Release|x64.Build.0 = Release|x64 + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Debug|x64.ActiveCfg = Debug|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Debug|x64.Build.0 = Debug|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Release|x64.ActiveCfg = Release|Any CPU + {8BF98BEF-6F00-4197-91ED-75F8F1C35FFB}.Release|x64.Build.0 = Release|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.ActiveCfg = Debug|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.Build.0 = Debug|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.ActiveCfg = Release|Any CPU + {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Questionable/ChatFunctions.cs b/Questionable/ChatFunctions.cs index 26ca9a22..d28946a8 100644 --- a/Questionable/ChatFunctions.cs +++ b/Questionable/ChatFunctions.cs @@ -14,7 +14,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.String; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable; diff --git a/Questionable/Controller/CombatController.cs b/Questionable/Controller/CombatController.cs index f747966e..1f95e9da 100644 --- a/Questionable/Controller/CombatController.cs +++ b/Questionable/Controller/CombatController.cs @@ -14,7 +14,7 @@ using FFXIVClientStructs.FFXIV.Common.Math; using Microsoft.Extensions.Logging; using Questionable.Controller.CombatModules; using Questionable.Controller.Utils; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller; diff --git a/Questionable/Controller/GameUiController.cs b/Questionable/Controller/GameUiController.cs index 0bb4e12b..61d31fbd 100644 --- a/Questionable/Controller/GameUiController.cs +++ b/Questionable/Controller/GameUiController.cs @@ -14,7 +14,7 @@ using LLib.GameUI; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.Logging; using Questionable.Data; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Quest = Questionable.Model.Quest; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; diff --git a/Questionable/Controller/MovementController.cs b/Questionable/Controller/MovementController.cs index 1db1d5cf..d7fc74a9 100644 --- a/Questionable/Controller/MovementController.cs +++ b/Questionable/Controller/MovementController.cs @@ -18,8 +18,10 @@ using Microsoft.Extensions.Logging; using Questionable.Controller.NavigationOverrides; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing; +using Questionable.Model.Questing.Converter; namespace Questionable.Controller; diff --git a/Questionable/Controller/QuestController.cs b/Questionable/Controller/QuestController.cs index c92fee2b..e50891d2 100644 --- a/Questionable/Controller/QuestController.cs +++ b/Questionable/Controller/QuestController.cs @@ -10,7 +10,7 @@ using Questionable.Controller.Steps; using Questionable.Controller.Steps.Shared; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller; diff --git a/Questionable/Controller/QuestRegistry.cs b/Questionable/Controller/QuestRegistry.cs index 71750a1c..f472c115 100644 --- a/Questionable/Controller/QuestRegistry.cs +++ b/Questionable/Controller/QuestRegistry.cs @@ -11,7 +11,7 @@ using Dalamud.Plugin; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.QuestPaths; using Questionable.Validation; using Questionable.Validation.Validators; diff --git a/Questionable/Controller/Steps/Common/NextQuest.cs b/Questionable/Controller/Steps/Common/NextQuest.cs index 30a705e6..dddc8f9d 100644 --- a/Questionable/Controller/Steps/Common/NextQuest.cs +++ b/Questionable/Controller/Steps/Common/NextQuest.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Common; diff --git a/Questionable/Controller/Steps/ITaskFactory.cs b/Questionable/Controller/Steps/ITaskFactory.cs index 159d5c12..287f029f 100644 --- a/Questionable/Controller/Steps/ITaskFactory.cs +++ b/Questionable/Controller/Steps/ITaskFactory.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps; diff --git a/Questionable/Controller/Steps/Interactions/Action.cs b/Questionable/Controller/Steps/Interactions/Action.cs index 94125e43..000811ca 100644 --- a/Questionable/Controller/Steps/Interactions/Action.cs +++ b/Questionable/Controller/Steps/Interactions/Action.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/AetherCurrent.cs b/Questionable/Controller/Steps/Interactions/AetherCurrent.cs index 82b13d27..3ae2c4b3 100644 --- a/Questionable/Controller/Steps/Interactions/AetherCurrent.cs +++ b/Questionable/Controller/Steps/Interactions/AetherCurrent.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/AethernetShard.cs b/Questionable/Controller/Steps/Interactions/AethernetShard.cs index 87a4f348..b3219a6e 100644 --- a/Questionable/Controller/Steps/Interactions/AethernetShard.cs +++ b/Questionable/Controller/Steps/Interactions/AethernetShard.cs @@ -1,9 +1,9 @@ using System; -using FFXIVClientStructs.FFXIV.Client.Game.Object; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Aetheryte.cs b/Questionable/Controller/Steps/Interactions/Aetheryte.cs index a6bccc4c..c2cab7df 100644 --- a/Questionable/Controller/Steps/Interactions/Aetheryte.cs +++ b/Questionable/Controller/Steps/Interactions/Aetheryte.cs @@ -2,7 +2,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Combat.cs b/Questionable/Controller/Steps/Interactions/Combat.cs index 97201b46..2d7de402 100644 --- a/Questionable/Controller/Steps/Interactions/Combat.cs +++ b/Questionable/Controller/Steps/Interactions/Combat.cs @@ -6,7 +6,7 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Steps.Shared; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Dive.cs b/Questionable/Controller/Steps/Interactions/Dive.cs index 05e9cf44..3976eb73 100644 --- a/Questionable/Controller/Steps/Interactions/Dive.cs +++ b/Questionable/Controller/Steps/Interactions/Dive.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Duty.cs b/Questionable/Controller/Steps/Interactions/Duty.cs index a7de058c..ab2afdcd 100644 --- a/Questionable/Controller/Steps/Interactions/Duty.cs +++ b/Questionable/Controller/Steps/Interactions/Duty.cs @@ -3,7 +3,7 @@ using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Emote.cs b/Questionable/Controller/Steps/Interactions/Emote.cs index 44478475..0a5e9064 100644 --- a/Questionable/Controller/Steps/Interactions/Emote.cs +++ b/Questionable/Controller/Steps/Interactions/Emote.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/EquipItem.cs b/Questionable/Controller/Steps/Interactions/EquipItem.cs index 9322563d..95aad266 100644 --- a/Questionable/Controller/Steps/Interactions/EquipItem.cs +++ b/Questionable/Controller/Steps/Interactions/EquipItem.cs @@ -6,7 +6,7 @@ using FFXIVClientStructs.FFXIV.Client.Game; using Lumina.Excel.GeneratedSheets; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Quest = Questionable.Model.Quest; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Interact.cs b/Questionable/Controller/Steps/Interactions/Interact.cs index f49394de..7dba0d44 100644 --- a/Questionable/Controller/Steps/Interactions/Interact.cs +++ b/Questionable/Controller/Steps/Interactions/Interact.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Shared; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Jump.cs b/Questionable/Controller/Steps/Interactions/Jump.cs index 5c3d9add..0b0b099d 100644 --- a/Questionable/Controller/Steps/Interactions/Jump.cs +++ b/Questionable/Controller/Steps/Interactions/Jump.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/Say.cs b/Questionable/Controller/Steps/Interactions/Say.cs index c833badc..20fc7f67 100644 --- a/Questionable/Controller/Steps/Interactions/Say.cs +++ b/Questionable/Controller/Steps/Interactions/Say.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs index f7d5172a..648627c1 100644 --- a/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs +++ b/Questionable/Controller/Steps/Interactions/SinglePlayerDuty.cs @@ -4,7 +4,7 @@ using Dalamud.Plugin.Services; using Microsoft.Extensions.DependencyInjection; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Interactions/UseItem.cs b/Questionable/Controller/Steps/Interactions/UseItem.cs index 3e1212f8..e17f005e 100644 --- a/Questionable/Controller/Steps/Interactions/UseItem.cs +++ b/Questionable/Controller/Steps/Interactions/UseItem.cs @@ -13,7 +13,8 @@ using Questionable.Controller.Steps.Shared; using Questionable.Controller.Utils; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using AethernetShortcut = Questionable.Controller.Steps.Shared.AethernetShortcut; namespace Questionable.Controller.Steps.Interactions; diff --git a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs index df7f5788..a66e7c0f 100644 --- a/Questionable/Controller/Steps/Shared/AethernetShortcut.cs +++ b/Questionable/Controller/Steps/Shared/AethernetShortcut.cs @@ -8,8 +8,10 @@ using Microsoft.Extensions.Logging; using Questionable.Data; using Questionable.External; using Questionable.Model; -using Questionable.Model.V1; -using Questionable.Model.V1.Converter; +using Questionable.Model.Common; +using Questionable.Model.Common.Converter; +using Questionable.Model.Questing; +using Questionable.Model.Questing.Converter; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs index 413dd37a..ed8d1c07 100644 --- a/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs +++ b/Questionable/Controller/Steps/Shared/AetheryteShortcut.cs @@ -7,7 +7,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Common; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/Move.cs b/Questionable/Controller/Steps/Shared/Move.cs index e7474688..24d3e7f8 100644 --- a/Questionable/Controller/Steps/Shared/Move.cs +++ b/Questionable/Controller/Steps/Shared/Move.cs @@ -13,7 +13,7 @@ using Questionable.Controller.NavigationOverrides; using Questionable.Controller.Steps.Common; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/SkipCondition.cs b/Questionable/Controller/Steps/Shared/SkipCondition.cs index 2f768ecd..5d50ba18 100644 --- a/Questionable/Controller/Steps/Shared/SkipCondition.cs +++ b/Questionable/Controller/Steps/Shared/SkipCondition.cs @@ -11,7 +11,8 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/StepDisabled.cs b/Questionable/Controller/Steps/Shared/StepDisabled.cs index 16bb8365..609f3143 100644 --- a/Questionable/Controller/Steps/Shared/StepDisabled.cs +++ b/Questionable/Controller/Steps/Shared/StepDisabled.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs index 0d44663c..6d54623e 100644 --- a/Questionable/Controller/Steps/Shared/WaitAtEnd.cs +++ b/Questionable/Controller/Steps/Shared/WaitAtEnd.cs @@ -12,7 +12,7 @@ using Questionable.Controller.Steps.Common; using Questionable.Controller.Utils; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Steps/Shared/WaitAtStart.cs b/Questionable/Controller/Steps/Shared/WaitAtStart.cs index 4a1f411e..b39e301d 100644 --- a/Questionable/Controller/Steps/Shared/WaitAtStart.cs +++ b/Questionable/Controller/Steps/Shared/WaitAtStart.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Questionable.Controller.Steps.Common; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Steps.Shared; diff --git a/Questionable/Controller/Utils/QuestWorkUtils.cs b/Questionable/Controller/Utils/QuestWorkUtils.cs index 6bb77180..59235918 100644 --- a/Questionable/Controller/Utils/QuestWorkUtils.cs +++ b/Questionable/Controller/Utils/QuestWorkUtils.cs @@ -4,7 +4,7 @@ using System.Linq; using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using Microsoft.Extensions.Logging; using Questionable.Controller.Steps.Shared; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Controller.Utils; diff --git a/Questionable/Data/AetheryteData.cs b/Questionable/Data/AetheryteData.cs index 9e216cdc..28d8e459 100644 --- a/Questionable/Data/AetheryteData.cs +++ b/Questionable/Data/AetheryteData.cs @@ -4,8 +4,7 @@ using System.Linq; using System.Numerics; using Dalamud.Plugin.Services; using Lumina.Excel.GeneratedSheets; -using Microsoft.Extensions.Logging; -using Questionable.Model.V1; +using Questionable.Model.Common; namespace Questionable.Data; diff --git a/Questionable/External/LifestreamIpc.cs b/Questionable/External/LifestreamIpc.cs index deab3a24..f3267709 100644 --- a/Questionable/External/LifestreamIpc.cs +++ b/Questionable/External/LifestreamIpc.cs @@ -1,7 +1,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using Questionable.Data; -using Questionable.Model.V1; +using Questionable.Model.Common; namespace Questionable.External; diff --git a/Questionable/GameFunctions.cs b/Questionable/GameFunctions.cs index 6487eb98..724f2f11 100644 --- a/Questionable/GameFunctions.cs +++ b/Questionable/GameFunctions.cs @@ -24,7 +24,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using Action = Lumina.Excel.GeneratedSheets2.Action; using BattleChara = FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara; using ContentFinderCondition = Lumina.Excel.GeneratedSheets.ContentFinderCondition; diff --git a/Questionable/Model/Quest.cs b/Questionable/Model/Quest.cs index a33bcd18..5124de9d 100644 --- a/Questionable/Model/Quest.cs +++ b/Questionable/Model/Quest.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Model; diff --git a/Questionable/Validation/Validators/AethernetShortcutValidator.cs b/Questionable/Validation/Validators/AethernetShortcutValidator.cs index 36643c3e..e620d8a5 100644 --- a/Questionable/Validation/Validators/AethernetShortcutValidator.cs +++ b/Questionable/Validation/Validators/AethernetShortcutValidator.cs @@ -2,7 +2,7 @@ using System.Linq; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/BasicSequenceValidator.cs b/Questionable/Validation/Validators/BasicSequenceValidator.cs index 0c10e032..0127bc19 100644 --- a/Questionable/Validation/Validators/BasicSequenceValidator.cs +++ b/Questionable/Validation/Validators/BasicSequenceValidator.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/CompletionFlagsValidator.cs b/Questionable/Validation/Validators/CompletionFlagsValidator.cs index 1d36c8c4..2cfc58d7 100644 --- a/Questionable/Validation/Validators/CompletionFlagsValidator.cs +++ b/Questionable/Validation/Validators/CompletionFlagsValidator.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Numerics; using Questionable.Controller.Utils; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Validation/Validators/JsonSchemaValidator.cs b/Questionable/Validation/Validators/JsonSchemaValidator.cs index b3ed6f4e..7cacc520 100644 --- a/Questionable/Validation/Validators/JsonSchemaValidator.cs +++ b/Questionable/Validation/Validators/JsonSchemaValidator.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Text.Json.Nodes; using Json.Schema; @@ -12,6 +13,13 @@ internal sealed class JsonSchemaValidator : IQuestValidator private readonly Dictionary _questNodes = new(); private JsonSchema? _questSchema; + public JsonSchemaValidator() + { + SchemaRegistry.Global.Register( + new Uri("https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json"), + JsonSchema.FromStream(AssemblyModelLoader.CommonSchema).AsTask().Result); + } + public IEnumerable Validate(Quest quest) { _questSchema ??= JsonSchema.FromStream(AssemblyQuestLoader.QuestSchema).AsTask().Result; @@ -36,7 +44,6 @@ internal sealed class JsonSchemaValidator : IQuestValidator }; } } - } public void Enqueue(ushort questId, JsonNode questNode) => _questNodes[questId] = questNode; diff --git a/Questionable/Validation/Validators/UniqueStartStopValidator.cs b/Questionable/Validation/Validators/UniqueStartStopValidator.cs index b95522f1..b385306d 100644 --- a/Questionable/Validation/Validators/UniqueStartStopValidator.cs +++ b/Questionable/Validation/Validators/UniqueStartStopValidator.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Linq; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Validation.Validators; diff --git a/Questionable/Windows/DebugOverlay.cs b/Questionable/Windows/DebugOverlay.cs index 20b572fe..e7cc34e7 100644 --- a/Questionable/Windows/DebugOverlay.cs +++ b/Questionable/Windows/DebugOverlay.cs @@ -11,7 +11,7 @@ using ImGuiNET; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Windows; diff --git a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs index f819526a..14b628d3 100644 --- a/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs +++ b/Questionable/Windows/QuestComponents/ActiveQuestComponent.cs @@ -13,7 +13,7 @@ using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; using ImGuiNET; using Questionable.Controller; using Questionable.Controller.Steps.Shared; -using Questionable.Model.V1; +using Questionable.Model.Questing; namespace Questionable.Windows.QuestComponents; diff --git a/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs b/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs index a1fac0a4..b824f1af 100644 --- a/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs +++ b/Questionable/Windows/QuestComponents/CreationUtilsComponent.cs @@ -16,7 +16,8 @@ using Microsoft.Extensions.Logging; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Common; +using Questionable.Model.Questing; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Questionable.Windows.QuestComponents; @@ -160,23 +161,38 @@ internal sealed class CreationUtilsComponent "Left click: Copy target position as JSON.\nRight click: Copy target position as C# code."); if (copy) { - string interactionType = gameObject->NamePlateIconId switch + var target = _targetManager.Target; + if (target.ObjectKind == ObjectKind.GatheringPoint) { - 71201 or 71211 or 71221 or 71231 or 71341 or 71351 => "AcceptQuest", - 71202 or 71212 or 71222 or 71232 or 71342 or 71352 => "AcceptQuest", // repeatable - 71205 or 71215 or 71225 or 71235 or 71345 or 71355 => "CompleteQuest", - _ => "Interact", - }; - ImGui.SetClipboardText($$""" - "DataId": {{_targetManager.Target.DataId}}, - "Position": { - "X": {{_targetManager.Target.Position.X.ToString(CultureInfo.InvariantCulture)}}, - "Y": {{_targetManager.Target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, - "Z": {{_targetManager.Target.Position.Z.ToString(CultureInfo.InvariantCulture)}} - }, - "TerritoryId": {{_clientState.TerritoryType}}, - "InteractionType": "{{interactionType}}" - """); + ImGui.SetClipboardText($$""" + "DataId": {{target.DataId}}, + "Position": { + "X": {{target.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{target.Position.Z.ToString(CultureInfo.InvariantCulture)}} + } + """); + } + else + { + string interactionType = gameObject->NamePlateIconId switch + { + 71201 or 71211 or 71221 or 71231 or 71341 or 71351 => "AcceptQuest", + 71202 or 71212 or 71222 or 71232 or 71342 or 71352 => "AcceptQuest", // repeatable + 71205 or 71215 or 71225 or 71235 or 71345 or 71355 => "CompleteQuest", + _ => "Interact", + }; + ImGui.SetClipboardText($$""" + "DataId": {{target.DataId}}, + "Position": { + "X": {{target.Position.X.ToString(CultureInfo.InvariantCulture)}}, + "Y": {{target.Position.Y.ToString(CultureInfo.InvariantCulture)}}, + "Z": {{target.Position.Z.ToString(CultureInfo.InvariantCulture)}} + }, + "TerritoryId": {{_clientState.TerritoryType}}, + "InteractionType": "{{interactionType}}" + """); + } } else if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) { diff --git a/Questionable/Windows/QuestSelectionWindow.cs b/Questionable/Windows/QuestSelectionWindow.cs index 6f420786..8da2c2d0 100644 --- a/Questionable/Windows/QuestSelectionWindow.cs +++ b/Questionable/Windows/QuestSelectionWindow.cs @@ -19,7 +19,7 @@ using LLib.ImGui; using Questionable.Controller; using Questionable.Data; using Questionable.Model; -using Questionable.Model.V1; +using Questionable.Model.Questing; using Questionable.Windows.QuestComponents; namespace Questionable.Windows;