From: Liza Carvelli Date: Fri, 14 Jun 2024 09:37:33 +0000 (+0200) Subject: Update how quests are embedded X-Git-Tag: v0.15~2 X-Git-Url: https://git.jacobcasper.com/?a=commitdiff_plain;h=5a4a693d66018da39fde184fc1fae25709dc6d90;p=Questionable.git Update how quests are embedded --- diff --git a/.gitignore b/.gitignore index 05dc5493..f0fb17c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ -/.idea +obj/ +bin/ +/.idea +/.vs *.user diff --git a/QuestPathGenerator/QuestPathGenerator.csproj b/QuestPathGenerator/QuestPathGenerator.csproj new file mode 100644 index 00000000..b62d2878 --- /dev/null +++ b/QuestPathGenerator/QuestPathGenerator.csproj @@ -0,0 +1,37 @@ + + + netstandard2.0 + false + 12 + enable + true + Questionable.QuestPathGenerator + portable + + true + true + + QuestPathGenerator + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + diff --git a/QuestPathGenerator/QuestSourceGenerator.cs b/QuestPathGenerator/QuestSourceGenerator.cs new file mode 100644 index 00000000..9bc6cc29 --- /dev/null +++ b/QuestPathGenerator/QuestSourceGenerator.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Questionable.Model.V1; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; +using static Questionable.QuestPathGenerator.RoslynShortcuts; + +namespace Questionable.QuestPathGenerator; + +/// +/// A sample source generator that creates C# classes based on the text file (in this case, Domain Driven Design ubiquitous language registry). +/// When using a simple text file as a baseline, we can create a non-incremental source generator. +/// +[Generator] +public class QuestSourceGenerator : ISourceGenerator +{ + public void Initialize(GeneratorInitializationContext context) + { + // No initialization required for this generator. + } + + public void Execute(GeneratorExecutionContext context) + { + List<(ushort, QuestData)> quests = []; + + // Go through all files marked as an Additional File in file properties. + foreach (var additionalFile in context.AdditionalFiles) + { + if (additionalFile == null) + continue; + + if (Path.GetExtension(additionalFile.Path) != ".json") + continue; + + string name = Path.GetFileName(additionalFile.Path); + ushort id = ushort.Parse(name.Substring(0, name.IndexOf('_'))); + + var text = additionalFile.GetText(); + if (text == null) + continue; + + var quest = JsonSerializer.Deserialize(text.ToString())!; + quests.Add((id, quest)); + } + + quests = quests.OrderBy(x => x.Item1).ToList(); + + 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("V1"))) + })) + .WithMembers( + SingletonList( + FileScopedNamespaceDeclaration( + QualifiedName( + IdentifierName("Questionable"), + IdentifierName("QuestPaths"))) + .WithMembers( + SingletonList( + ClassDeclaration("AssemblyQuestLoader") + .WithModifiers( + TokenList( + [ + Token(SyntaxKind.PartialKeyword) + ])) + .WithMembers( + SingletonList( + FieldDeclaration( + VariableDeclaration( + GenericName( + Identifier("IReadOnlyDictionary")) + .WithTypeArgumentList( + TypeArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + PredefinedType( + Token(SyntaxKind + .UShortKeyword)), + Token(SyntaxKind.CommaToken), + IdentifierName("QuestData") + })))) + .WithVariables( + SingletonSeparatedList( + VariableDeclarator( + Identifier("Quests")) + .WithInitializer( + EqualsValueClause( + ObjectCreationExpression( + GenericName( + Identifier( + "Dictionary")) + .WithTypeArgumentList( + TypeArgumentList( + SeparatedList< + TypeSyntax>( + new + SyntaxNodeOrToken + [] + { + PredefinedType( + Token( + SyntaxKind + .UShortKeyword)), + Token( + SyntaxKind + .CommaToken), + IdentifierName( + "QuestData") + })))) + .WithArgumentList( + ArgumentList()) + .WithInitializer( + InitializerExpression( + SyntaxKind + .CollectionInitializerExpression, + SeparatedList< + ExpressionSyntax>( + quests.SelectMany(x => + CreateQuestInitializer( + x.Item1, + x.Item2) + .ToArray()))))))))) + .WithModifiers( + TokenList( + [ + Token(SyntaxKind.InternalKeyword), + Token(SyntaxKind.StaticKeyword) + ])))))))) + .NormalizeWhitespace(); + + // Add the source code to the compilation. + context.AddSource("AssemblyQuestLoader.g.cs", code.ToFullString()); + } + + private static IEnumerable CreateQuestInitializer(ushort questId, QuestData quest) + { + return new SyntaxNodeOrToken[] + { + InitializerExpression( + SyntaxKind.ComplexElementInitializerExpression, + SeparatedList( + new SyntaxNodeOrToken[] + { + LiteralExpression( + SyntaxKind.NumericLiteralExpression, + Literal(questId)), + Token(SyntaxKind.CommaToken), + ObjectCreationExpression( + IdentifierName(nameof(QuestData))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(QuestData.Author), quest.Author, null) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestData.Contributors), quest.Contributors) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestData.Comment), quest.Comment, null) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestData.TerritoryBlacklist), + quest.TerritoryBlacklist).AsSyntaxNodeOrToken(), + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(nameof(QuestData.QuestSequence)), + CreateQuestSequence(quest.QuestSequence)) + )))) + })), + Token(SyntaxKind.CommaToken) + }; + } + + private static ExpressionSyntax CreateQuestSequence(List sequences) + { + return CollectionExpression( + SeparatedList( + sequences.SelectMany(sequence => new SyntaxNodeOrToken[] + { + ExpressionElement( + ObjectCreationExpression( + IdentifierName(nameof(QuestSequence))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(QuestSequence.Sequence), sequence.Sequence, null) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestSequence.Comment), sequence.Comment, null) + .AsSyntaxNodeOrToken(), + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(nameof(QuestSequence.Steps)), + CreateQuestSteps(sequence.Steps))))))), + Token(SyntaxKind.CommaToken), + }.ToArray()))); + } + + private static ExpressionSyntax CreateQuestSteps(List steps) + { + QuestStep emptyStep = new(); + return CollectionExpression( + SeparatedList( + steps.SelectMany(step => new SyntaxNodeOrToken[] + { + ExpressionElement( + ObjectCreationExpression( + IdentifierName(nameof(QuestStep))) + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Argument(LiteralValue(step.InteractionType)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(step.DataId)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(step.Position)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(step.TerritoryId)) + }))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(QuestStep.StopDistance), step.StopDistance, + emptyStep.StopDistance) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.TargetTerritoryId), step.TargetTerritoryId, + emptyStep.TargetTerritoryId) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Disabled), step.Disabled, emptyStep.Disabled) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.DisableNavmesh), step.DisableNavmesh, + emptyStep.DisableNavmesh) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Mount), step.Mount, emptyStep.Mount) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Fly), step.Fly, emptyStep.Fly) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Sprint), step.Sprint, emptyStep.Sprint) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Comment), step.Comment, emptyStep.Comment) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.AetheryteShortcut), step.AetheryteShortcut, + emptyStep.AetheryteShortcut) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.AethernetShortcut), step.AethernetShortcut, + emptyStep.AethernetShortcut) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.AetherCurrentId), step.AetherCurrentId, + emptyStep.AetherCurrentId) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.ItemId), step.ItemId, emptyStep.ItemId) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.GroundTarget), step.GroundTarget, + emptyStep.GroundTarget) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.Emote), step.Emote, emptyStep.Emote) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.ChatMessage), step.ChatMessage, + emptyStep.ChatMessage) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.EnemySpawnType), step.EnemySpawnType, + emptyStep.EnemySpawnType) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestStep.KillEnemyDataIds), step.KillEnemyDataIds) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.JumpDestination), step.JumpDestination, + emptyStep.JumpDestination) + .AsSyntaxNodeOrToken(), + Assignment(nameof(QuestStep.ContentFinderConditionId), + step.ContentFinderConditionId, emptyStep.ContentFinderConditionId) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestStep.SkipIf), step.SkipIf) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestStep.CompletionQuestVariablesFlags), + step.CompletionQuestVariablesFlags) + .AsSyntaxNodeOrToken(), + AssignmentList(nameof(QuestStep.DialogueChoices), step.DialogueChoices) + .AsSyntaxNodeOrToken()))))), + Token(SyntaxKind.CommaToken), + }.ToArray()))); + } +} diff --git a/QuestPathGenerator/RoslynShortcuts.cs b/QuestPathGenerator/RoslynShortcuts.cs new file mode 100644 index 00000000..545cb27a --- /dev/null +++ b/QuestPathGenerator/RoslynShortcuts.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Questionable.Model.V1; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Questionable.QuestPathGenerator; + +public static class RoslynShortcuts +{ + public static IEnumerable SyntaxNodeList(params SyntaxNodeOrToken?[] nodes) + { + nodes = nodes.Where(x => x != null).ToArray(); + if (nodes.Length == 0) + return []; + + List list = new(); + for (int i = 0; i < nodes.Length; ++i) + { + if (i > 0) + list.Add(Token(SyntaxKind.CommaToken)); + list.Add(nodes[i].GetValueOrDefault()); + } + + return list; + } + + public static ExpressionSyntax LiteralValue(T? value) + { + if (value is string s) + return LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(s)); + else if (value is bool b) + return LiteralExpression(b ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression); + else if (value is short i16) + return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(i16)); + else if (value is int i32) + return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(i32)); + else if (value is ushort u16) + return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(u16)); + else if (value is uint u32) + return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(u32)); + else if (value is float f) + return LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(f)); + else if (value != null && value.GetType().IsEnum) + return MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(value.GetType().Name), + IdentifierName(value.GetType().GetEnumName(value)!)); + else if (value is Vector3 vector) + { + return ObjectCreationExpression( + IdentifierName(nameof(Vector3))) + .WithArgumentList( + ArgumentList( + SeparatedList( + new SyntaxNodeOrToken[] + { + Argument(LiteralValue(vector.X)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(vector.Y)), + Token(SyntaxKind.CommaToken), + Argument(LiteralValue(vector.Z)) + }))); + } + else if (value is AethernetShortcut aethernetShortcut) + { + return ObjectCreationExpression( + IdentifierName(nameof(AethernetShortcut))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(AethernetShortcut.From), aethernetShortcut.From, + null) + .AsSyntaxNodeOrToken(), + Assignment(nameof(AethernetShortcut.To), aethernetShortcut.To, + null) + .AsSyntaxNodeOrToken())))); + } + else if (value is ChatMessage chatMessage) + { + ChatMessage emptyMessage = new(); + return ObjectCreationExpression( + IdentifierName(nameof(ChatMessage))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(ChatMessage.ExcelSheet), chatMessage.ExcelSheet, + emptyMessage.ExcelSheet) + .AsSyntaxNodeOrToken(), + Assignment(nameof(ChatMessage.Key), chatMessage.Key, + emptyMessage.Key) + .AsSyntaxNodeOrToken())))); + } + else if (value is DialogueChoice dialogueChoice) + { + DialogueChoice emptyChoice = new(); + return ObjectCreationExpression( + IdentifierName(nameof(DialogueChoice))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(DialogueChoice.Type), dialogueChoice.Type, null) + .AsSyntaxNodeOrToken(), + Assignment(nameof(DialogueChoice.ExcelSheet), dialogueChoice.ExcelSheet, + emptyChoice.ExcelSheet) + .AsSyntaxNodeOrToken(), + Assignment(nameof(DialogueChoice.Prompt), dialogueChoice.Prompt, emptyChoice.Prompt) + .AsSyntaxNodeOrToken(), + Assignment(nameof(DialogueChoice.Yes), dialogueChoice.Yes, emptyChoice.Yes) + .AsSyntaxNodeOrToken(), + Assignment(nameof(DialogueChoice.Answer), dialogueChoice.Answer, emptyChoice.Answer) + .AsSyntaxNodeOrToken(), + Assignment(nameof(DialogueChoice.DataId), dialogueChoice.DataId, emptyChoice.DataId) + .AsSyntaxNodeOrToken())))); + } + else if (value is JumpDestination jumpDestination) + { + return ObjectCreationExpression( + IdentifierName(nameof(JumpDestination))) + .WithInitializer( + InitializerExpression( + SyntaxKind.ObjectInitializerExpression, + SeparatedList( + SyntaxNodeList( + Assignment(nameof(JumpDestination.Position), jumpDestination.Position, null) + .AsSyntaxNodeOrToken(), + Assignment(nameof(JumpDestination.StopDistance), jumpDestination.StopDistance, null) + .AsSyntaxNodeOrToken(), + Assignment(nameof(JumpDestination.DelaySeconds), jumpDestination.DelaySeconds, null) + .AsSyntaxNodeOrToken())))); + } + else if (value is ExcelRef excelRef) + { + if (excelRef.Type == ExcelRef.EType.Key) + { + return ObjectCreationExpression( + IdentifierName(nameof(ExcelRef))) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument(LiteralValue(excelRef.AsKey()))))); + } + else if (excelRef.Type == ExcelRef.EType.RowId) + { + return ObjectCreationExpression( + IdentifierName(nameof(ExcelRef))) + .WithArgumentList( + ArgumentList( + SingletonSeparatedList( + Argument(LiteralValue(excelRef.AsRowId()))))); + } + else + throw new Exception($"Unsupported ExcelRef type {excelRef.Type}"); + } + else if (value is null) + return LiteralExpression(SyntaxKind.NullLiteralExpression); + else + throw new Exception($"Unsupported data type {value.GetType()} = {value}"); + } + + public static AssignmentExpressionSyntax? Assignment(string name, T? value, T? defaultValue) + { + if (value == null && defaultValue == null) + return null; + + if (value != null && defaultValue != null && value.Equals(defaultValue)) + return null; + + return AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(name), + LiteralValue(value)); + } + + public static AssignmentExpressionSyntax? AssignmentList(string name, IEnumerable value) + { + IEnumerable list = value.ToList(); + if (!list.Any()) + return null; + + return AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + IdentifierName(name), + CollectionExpression( + SeparatedList( + SyntaxNodeList(list.Select(x => ExpressionElement( + LiteralValue(x)).AsSyntaxNodeOrToken()).ToArray()) + ))); + } + + public static SyntaxNodeOrToken? AsSyntaxNodeOrToken(this SyntaxNode? node) + { + if (node == null) + return null; + + return node; + } +} diff --git a/QuestPathGenerator/packages.lock.json b/QuestPathGenerator/packages.lock.json new file mode 100644 index 00000000..a9d05083 --- /dev/null +++ b/QuestPathGenerator/packages.lock.json @@ -0,0 +1,244 @@ +{ + "version": 1, + "dependencies": { + ".NETStandard,Version=v2.0": { + "Microsoft.CodeAnalysis.Analyzers": { + "type": "Direct", + "requested": "[3.3.4, )", + "resolved": "3.3.4", + "contentHash": "AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==" + }, + "Microsoft.CodeAnalysis.CSharp": { + "type": "Direct", + "requested": "[4.9.2, )", + "resolved": "4.9.2", + "contentHash": "HGIo7E9Mf3exAJbUdYpDFfLoYkSVaHDJXPyusWTYUTBaOPCowGw+Gap5McE1w+K+ryIXre72oiqL88sQHmHBmg==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "[4.9.2]" + } + }, + "Microsoft.CodeAnalysis.CSharp.Workspaces": { + "type": "Direct", + "requested": "[4.9.2, )", + "resolved": "4.9.2", + "contentHash": "c74oxEil3fiZ3nXchnIgY6mXS4roHGiQBT6p3X6dMWokVqluHiqi3PNcXyxH8N/w28rQeXprF3mca83rPPNrMw==", + "dependencies": { + "Humanizer.Core": "2.14.1", + "Microsoft.CodeAnalysis.CSharp": "[4.9.2]", + "Microsoft.CodeAnalysis.Common": "[4.9.2]", + "Microsoft.CodeAnalysis.Workspaces.Common": "[4.9.2]" + } + }, + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "System.Text.Json": { + "type": "Direct", + "requested": "[8.0.3, )", + "resolved": "8.0.3", + "contentHash": "hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "8.0.0", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Humanizer.Core": { + "type": "Transitive", + "resolved": "2.14.1", + "contentHash": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw==" + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.CodeAnalysis.Common": { + "type": "Transitive", + "resolved": "4.9.2", + "contentHash": "M5PThug7b2AdxL7xKmQs50KzAQTl9jENw5jMT3iUt16k+DAFlw1S87juU3UuPs3gvBm8trMBSOEvSFDr31c9Vw==", + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Memory": "4.5.5", + "System.Reflection.Metadata": "8.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.CodeAnalysis.Workspaces.Common": { + "type": "Transitive", + "resolved": "4.9.2", + "contentHash": "sgBlkBjKwUdpbtwM7SnBdOxvQxuaTtO9F8QgvKY5cH/OnlwDTZqmkK8hfDbhxv9wnN2wME10BL2vIv1fLJwFGA==", + "dependencies": { + "Humanizer.Core": "2.14.1", + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "Microsoft.CodeAnalysis.Common": "[4.9.2]", + "System.Composition": "8.0.0", + "System.IO.Pipelines": "8.0.0", + "System.Threading.Channels": "8.0.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Composition": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "E9oO9olNNxA39J8CxQwf7ceIPm+j/B/PhYpyK9M4LhN/OLLRw6u5fNInkhVqaWueMB9iXxYqnwqwgz+W91loIA==", + "dependencies": { + "System.Composition.AttributedModel": "8.0.0", + "System.Composition.Convention": "8.0.0", + "System.Composition.Hosting": "8.0.0", + "System.Composition.Runtime": "8.0.0", + "System.Composition.TypedParts": "8.0.0" + } + }, + "System.Composition.AttributedModel": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "NyElSuvmBMYdn2iPG0n29i7Igu0bq99izOP3MAtEwskY3OP9jqsavvVmPn9lesVaj/KT/o/QkNjA43dOJTsDQw==" + }, + "System.Composition.Convention": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "UuVkc1B3vQU/LzEbWLMZ1aYVssv4rpShzf8wPEyrUqoGNqdYKREmB8bXR73heOMKkwS6ZnPz3PjGODT2MenukQ==", + "dependencies": { + "System.Composition.AttributedModel": "8.0.0" + } + }, + "System.Composition.Hosting": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "qwbONqoxlazxcbiohvb3t1JWZgKIKcRdXS5uEeLbo5wtuBupIbAvdC3PYTAeBCZrZeERvrtAbhYHuuS43Zr1bQ==", + "dependencies": { + "System.Composition.Runtime": "8.0.0" + } + }, + "System.Composition.Runtime": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "G+kRyB5/6+3ucRRQz+DF4uSHGqpkK8Q4ilVdbt4zvxpmvLVZNmSkyFAQpJLcbOyVF85aomJx0m+TGMDVlwx7ZQ==" + }, + "System.Composition.TypedParts": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "DsSklhuA+Dsgo3ZZrar8hjBFvq1wa1grrkNCTt+6SoX3vq0Vy+HXJnVXrU/nNH1BjlGH684A7h4hJQHZd/u5mA==", + "dependencies": { + "System.Composition.AttributedModel": "8.0.0", + "System.Composition.Hosting": "8.0.0", + "System.Composition.Runtime": "8.0.0" + } + }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "dependencies": { + "System.Collections.Immutable": "8.0.0", + "System.Memory": "4.5.5" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Encoding.CodePages": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Threading.Channels": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "CMaFr7v+57RW7uZfZkPExsPB6ljwzhjACWW1gfU35Y56rk72B/Wu+sTqxVmGSk4SFUlPc3cjeKND0zktziyjBA==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.3, )" + } + } + } + } +} \ No newline at end of file diff --git a/QuestPaths/AssemblyQuestLoader.cs b/QuestPaths/AssemblyQuestLoader.cs index 95faeb46..9601c4dc 100644 --- a/QuestPaths/AssemblyQuestLoader.cs +++ b/QuestPaths/AssemblyQuestLoader.cs @@ -1,30 +1,11 @@ -#if RELEASE -using System; -using System.IO; -using System.IO.Compression; +using System.Collections.Generic; +using Questionable.Model.V1; +#if RELEASE namespace Questionable.QuestPaths; -public static class AssemblyQuestLoader +public static partial class AssemblyQuestLoader { - public static void LoadQuestsFromEmbeddedResources(Action loadFunction) - { - foreach (string resourceName in typeof(AssemblyQuestLoader).Assembly.GetManifestResourceNames()) - { - if (resourceName.EndsWith(".zip")) - { - using ZipArchive zipArchive = - new ZipArchive(typeof(AssemblyQuestLoader).Assembly.GetManifestResourceStream(resourceName)!); - foreach (ZipArchiveEntry entry in zipArchive.Entries) - { - if (entry.Name.EndsWith(".json")) - { - using Stream stream = entry.Open(); - loadFunction(entry.Name, stream); - } - } - } - } - } + public static IReadOnlyDictionary GetQuests() => Quests; } #endif diff --git a/QuestPaths/QuestPaths.csproj b/QuestPaths/QuestPaths.csproj index 3ea68608..2a204647 100644 --- a/QuestPaths/QuestPaths.csproj +++ b/QuestPaths/QuestPaths.csproj @@ -8,29 +8,22 @@ true none $(SolutionDir)=X:\ + true - - - - - - - - - - - + + + + - - - + + + + + + diff --git a/QuestPaths/packages.lock.json b/QuestPaths/packages.lock.json index f9ae1775..aced35f4 100644 --- a/QuestPaths/packages.lock.json +++ b/QuestPaths/packages.lock.json @@ -1,6 +1,105 @@ { "version": 1, "dependencies": { - "net8.0-windows7.0": {} + "net8.0-windows7.0": { + "Dalamud.Extensions.MicrosoftLogging": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "fMEL2ajtF/30SBBku7vMyG0yye5eHN/A9fgT//1CEjUth/Wz2CYco5Ehye21T8KN1IuAPwoqJuu49rB71j+8ug==", + "dependencies": { + "Microsoft.Extensions.Logging": "8.0.0" + } + }, + "DalamudPackager": { + "type": "Transitive", + "resolved": "2.1.12", + "contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg==" + }, + "JetBrains.Annotations": { + "type": "Transitive", + "resolved": "2023.3.0", + "contentHash": "PHfnvdBUdGaTVG9bR/GEfxgTwWM0Z97Y6X3710wiljELBISipSfF5okn/vz+C2gfO+ihoEyVPjaJwn8ZalVukA==" + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "8.0.3", + "contentHash": "hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + }, + "llib": { + "type": "Project" + }, + "questionable": { + "type": "Project", + "dependencies": { + "Dalamud.Extensions.MicrosoftLogging": "[4.0.1, )", + "DalamudPackager": "[2.1.12, )", + "JetBrains.Annotations": "[2023.3.0, )", + "LLib": "[1.0.0, )", + "Microsoft.Extensions.DependencyInjection": "[8.0.0, )", + "QuestPaths": "[1.0.0, )", + "Questionable.Model": "[1.0.0, )", + "System.Text.Json": "[8.0.3, )" + } + }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.3, )" + } + } + } } } \ No newline at end of file diff --git a/Questionable.Model/Questionable.Model.csproj b/Questionable.Model/Questionable.Model.csproj new file mode 100644 index 00000000..c1fcd0f1 --- /dev/null +++ b/Questionable.Model/Questionable.Model.csproj @@ -0,0 +1,15 @@ + + + netstandard2.0 + 12 + enable + true + $(SolutionDir)=X:\ + true + portable + + + + + + diff --git a/Questionable.Model/V1/AethernetShortcut.cs b/Questionable.Model/V1/AethernetShortcut.cs new file mode 100644 index 00000000..40514b58 --- /dev/null +++ b/Questionable.Model/V1/AethernetShortcut.cs @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000..71721380 --- /dev/null +++ b/Questionable.Model/V1/ChatMessage.cs @@ -0,0 +1,7 @@ +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/Converter/AethernetShortcutConverter.cs b/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs new file mode 100644 index 00000000..76a06550 --- /dev/null +++ b/Questionable.Model/V1/Converter/AethernetShortcutConverter.cs @@ -0,0 +1,159 @@ +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 = 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" }, + { EAetheryteLocation.IdyllshireEpilogueGate, "[Idyllshire] Epilogue Gate" }, + + { 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.CrystariumThemenosRookery, "[Crystarium] Themenos 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)" }, + }; + + 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 new file mode 100644 index 00000000..80b92f7d --- /dev/null +++ b/Questionable.Model/V1/Converter/AetheryteConverter.cs @@ -0,0 +1,108 @@ +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" } + }; + + 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 new file mode 100644 index 00000000..ea832cac --- /dev/null +++ b/Questionable.Model/V1/Converter/DialogueChoiceTypeConverter.cs @@ -0,0 +1,12 @@ +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 new file mode 100644 index 00000000..8cc50027 --- /dev/null +++ b/Questionable.Model/V1/Converter/EmoteConverter.cs @@ -0,0 +1,18 @@ +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" }, + }; +} diff --git a/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs b/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs new file mode 100644 index 00000000..5c5de532 --- /dev/null +++ b/Questionable.Model/V1/Converter/EnemySpawnTypeConverter.cs @@ -0,0 +1,14 @@ +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 new file mode 100644 index 00000000..3ed1267b --- /dev/null +++ b/Questionable.Model/V1/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.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 new file mode 100644 index 00000000..0c48e5bb --- /dev/null +++ b/Questionable.Model/V1/Converter/ExcelRefConverter.cs @@ -0,0 +1,30 @@ +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) + { + if (reader.TokenType == JsonTokenType.String) + return new ExcelRef(reader.GetString()!); + else if (reader.TokenType == JsonTokenType.Number) + return new ExcelRef(reader.GetUInt32()); + else + return 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 new file mode 100644 index 00000000..6c43696f --- /dev/null +++ b/Questionable.Model/V1/Converter/InteractionTypeConverter.cs @@ -0,0 +1,27 @@ +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.WaitForObjectAtPosition, "WaitForNpcAtPosition" }, + { EInteractionType.WaitForManualProgress, "WaitForManualProgress" }, + { EInteractionType.Duty, "Duty" }, + { EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" }, + { EInteractionType.Jump, "Jump" }, + { EInteractionType.ShouldBeAJump, "ShouldBeAJump" }, + { EInteractionType.Instruction, "Instruction" }, + }; +} diff --git a/Questionable.Model/V1/Converter/SkipConditionConverter.cs b/Questionable.Model/V1/Converter/SkipConditionConverter.cs new file mode 100644 index 00000000..dd38ac4f --- /dev/null +++ b/Questionable.Model/V1/Converter/SkipConditionConverter.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Questionable.Model.V1.Converter; + +public sealed class SkipConditionConverter() : EnumConverter(Values) +{ + private static readonly Dictionary Values = new() + { + { ESkipCondition.Never, "Never" }, + { ESkipCondition.FlyingLocked, "FlyingLocked" }, + { ESkipCondition.FlyingUnlocked, "FlyingUnlocked" }, + }; +} diff --git a/Questionable.Model/V1/Converter/VectorConverter.cs b/Questionable.Model/V1/Converter/VectorConverter.cs new file mode 100644 index 00000000..f75ffe6a --- /dev/null +++ b/Questionable.Model/V1/Converter/VectorConverter.cs @@ -0,0 +1,64 @@ +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 new file mode 100644 index 00000000..80b49d05 --- /dev/null +++ b/Questionable.Model/V1/DialogueChoice.cs @@ -0,0 +1,24 @@ +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/EAetheryteLocation.cs b/Questionable.Model/V1/EAetheryteLocation.cs new file mode 100644 index 00000000..a49a471e --- /dev/null +++ b/Questionable.Model/V1/EAetheryteLocation.cs @@ -0,0 +1,209 @@ +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, + CrystariumThemenosRookery = 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 +} diff --git a/Questionable.Model/V1/EDialogChoiceType.cs b/Questionable.Model/V1/EDialogChoiceType.cs new file mode 100644 index 00000000..066639a3 --- /dev/null +++ b/Questionable.Model/V1/EDialogChoiceType.cs @@ -0,0 +1,8 @@ +namespace Questionable.Model.V1; + +public enum EDialogChoiceType +{ + None, + YesNo, + List, +} diff --git a/Questionable.Model/V1/EEmote.cs b/Questionable.Model/V1/EEmote.cs new file mode 100644 index 00000000..3ad0afbb --- /dev/null +++ b/Questionable.Model/V1/EEmote.cs @@ -0,0 +1,19 @@ +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, +} diff --git a/Questionable.Model/V1/EEnemySpawnType.cs b/Questionable.Model/V1/EEnemySpawnType.cs new file mode 100644 index 00000000..8465f011 --- /dev/null +++ b/Questionable.Model/V1/EEnemySpawnType.cs @@ -0,0 +1,14 @@ +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/EInteractionType.cs b/Questionable.Model/V1/EInteractionType.cs new file mode 100644 index 00000000..6e3b7da8 --- /dev/null +++ b/Questionable.Model/V1/EInteractionType.cs @@ -0,0 +1,34 @@ +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, + WaitForObjectAtPosition, + WaitForManualProgress, + Duty, + SinglePlayerDuty, + Jump, + + /// + /// Needs to be adjusted for coords etc. in the quest data. + /// + ShouldBeAJump, + + /// + /// Needs to be manually continued. + /// + Instruction, +} diff --git a/Questionable.Model/V1/ESkipCondition.cs b/Questionable.Model/V1/ESkipCondition.cs new file mode 100644 index 00000000..4f2639d4 --- /dev/null +++ b/Questionable.Model/V1/ESkipCondition.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; +using Questionable.Model.V1.Converter; + +namespace Questionable.Model.V1; + +[JsonConverter(typeof(SkipConditionConverter))] +public enum ESkipCondition +{ + None, + Never, + FlyingLocked, + FlyingUnlocked, +} diff --git a/Questionable.Model/V1/ExcelRef.cs b/Questionable.Model/V1/ExcelRef.cs new file mode 100644 index 00000000..c6451ac2 --- /dev/null +++ b/Questionable.Model/V1/ExcelRef.cs @@ -0,0 +1,48 @@ +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; + } + + 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 enum EType + { + None, + Key, + RowId, + } +} diff --git a/Questionable.Model/V1/JumpDestination.cs b/Questionable.Model/V1/JumpDestination.cs new file mode 100644 index 00000000..e6a709e7 --- /dev/null +++ b/Questionable.Model/V1/JumpDestination.cs @@ -0,0 +1,14 @@ +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; } +} diff --git a/Questionable.Model/V1/QuestData.cs b/Questionable.Model/V1/QuestData.cs new file mode 100644 index 00000000..111bd257 --- /dev/null +++ b/Questionable.Model/V1/QuestData.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Questionable.Model.V1; + +public sealed class QuestData +{ + public string Author { get; set; } = null!; + public List Contributors { get; set; } = new(); + 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 new file mode 100644 index 00000000..62736416 --- /dev/null +++ b/Questionable.Model/V1/QuestSequence.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +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]; + } +} diff --git a/Questionable.Model/V1/QuestStep.cs b/Questionable.Model/V1/QuestStep.cs new file mode 100644 index 00000000..029060e7 --- /dev/null +++ b/Questionable.Model/V1/QuestStep.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Text.Json.Serialization; +using Questionable.Model.V1.Converter; + +namespace Questionable.Model.V1; + +public sealed class QuestStep +{ + public EInteractionType InteractionType { get; set; } + + public uint? DataId { get; set; } + + [JsonConverter(typeof(VectorConverter))] + public Vector3? Position { get; set; } + + public float? StopDistance { get; set; } + public ushort TerritoryId { get; set; } + public ushort? TargetTerritoryId { get; set; } + + public bool Disabled { get; set; } + public bool DisableNavmesh { get; set; } + public bool? Mount { get; set; } + public bool? Fly { get; set; } + public bool? Sprint { get; set; } + public string? Comment { 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 EEnemySpawnType? EnemySpawnType { get; set; } + public IList KillEnemyDataIds { get; set; } = new List(); + + public JumpDestination? JumpDestination { get; set; } + public uint? ContentFinderConditionId { get; set; } + + public IList SkipIf { get; set; } = new List(); + public IList CompletionQuestVariablesFlags { get; set; } = new List(); + public IList DialogueChoices { get; set; } = new List(); + + [JsonConstructor] + public QuestStep() + { + } + + public QuestStep(EInteractionType interactionType, uint? dataId, Vector3? position, ushort territoryId) + { + InteractionType = interactionType; + DataId = dataId; + Position = position; + TerritoryId = territoryId; + } +} diff --git a/Questionable.Model/packages.lock.json b/Questionable.Model/packages.lock.json new file mode 100644 index 00000000..7bcc7e48 --- /dev/null +++ b/Questionable.Model/packages.lock.json @@ -0,0 +1,86 @@ +{ + "version": 1, + "dependencies": { + ".NETStandard,Version=v2.0": { + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "System.Text.Json": { + "type": "Direct", + "requested": "[8.0.3, )", + "resolved": "8.0.3", + "contentHash": "hpagS9joOwv6efWfrMmV9MjQXpiXZH72PgN067Ysfr6AWMSD1/1hEcvh/U5mUpPLezEWsOJSuVrmqDIVD958iA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "8.0.0", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==", + "dependencies": { + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + } + } + } +} \ No newline at end of file diff --git a/Questionable.sln b/Questionable.sln index 1ad54b6d..5a420a9c 100644 --- a/Questionable.sln +++ b/Questionable.sln @@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLib", "LLib\LLib.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPaths", "QuestPaths\QuestPaths.csproj", "{7A136F28-8D5C-478D-B993-0F39F1451A47}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuestPaths", "QuestPathGenerator\QuestPathGenerator.csproj", "{DFFD56A8-FA89-4585-A47B-C6AB27B65F0F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Questionable.Model", "Questionable.Model\Questionable.Model.csproj", "{E15144A5-AFF5-4D86-9561-AFF7DF7F505D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +28,13 @@ Global {7A136F28-8D5C-478D-B993-0F39F1451A47}.Debug|Any CPU.Build.0 = Debug|Any CPU {7A136F28-8D5C-478D-B993-0F39F1451A47}.Release|Any CPU.ActiveCfg = Release|Any CPU {7A136F28-8D5C-478D-B993-0F39F1451A47}.Release|Any CPU.Build.0 = Release|Any CPU + {DFFD56A8-FA89-4585-A47B-C6AB27B65F0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFFD56A8-FA89-4585-A47B-C6AB27B65F0F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFFD56A8-FA89-4585-A47B-C6AB27B65F0F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFFD56A8-FA89-4585-A47B-C6AB27B65F0F}.Release|Any CPU.Build.0 = Release|Any CPU + {E15144A5-AFF5-4D86-9561-AFF7DF7F505D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E15144A5-AFF5-4D86-9561-AFF7DF7F505D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E15144A5-AFF5-4D86-9561-AFF7DF7F505D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E15144A5-AFF5-4D86-9561-AFF7DF7F505D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Questionable/.gitignore b/Questionable/.gitignore index 958518b5..a60a458a 100644 --- a/Questionable/.gitignore +++ b/Questionable/.gitignore @@ -1,3 +1 @@ /dist -/obj -/bin diff --git a/Questionable/Controller/QuestRegistry.cs b/Questionable/Controller/QuestRegistry.cs index 1bc3a44e..71b91a19 100644 --- a/Questionable/Controller/QuestRegistry.cs +++ b/Questionable/Controller/QuestRegistry.cs @@ -33,7 +33,17 @@ internal sealed class QuestRegistry #if RELEASE _logger.LogInformation("Loading quests from assembly"); - QuestPaths.AssemblyQuestLoader.LoadQuestsFromEmbeddedResources(LoadQuestFromStream); + + foreach ((ushort questId, QuestData questData) in QuestPaths.AssemblyQuestLoader.GetQuests()) + { + Quest quest = new() + { + QuestId = questId, + Name = string.Empty, + Data = questData, + }; + _quests[questId] = quest; + } #else DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation?.Directory?.Parent?.Parent; if (solutionDirectory != null) @@ -48,6 +58,7 @@ internal sealed class QuestRegistry } } #endif + LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "Quests"))); foreach (var (questId, quest) in _quests) @@ -60,6 +71,8 @@ internal sealed class QuestRegistry quest.Name = questData.Name.ToString(); quest.Level = questData.ClassJobLevel0; } + + _logger.LogInformation("Loaded {Count} quests", _quests.Count); } diff --git a/Questionable/Model/V1/AethernetShortcut.cs b/Questionable/Model/V1/AethernetShortcut.cs deleted file mode 100644 index 2fd707a1..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))] -internal 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 c33bf43a..00000000 --- a/Questionable/Model/V1/ChatMessage.cs +++ /dev/null @@ -1,10 +0,0 @@ -using JetBrains.Annotations; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal sealed class ChatMessage -{ - public string? ExcelSheet { get; set; } - public string Key { get; set; } = null!; -} diff --git a/Questionable/Model/V1/Converter/AethernetShortcutConverter.cs b/Questionable/Model/V1/Converter/AethernetShortcutConverter.cs deleted file mode 100644 index 9393e9c3..00000000 --- a/Questionable/Model/V1/Converter/AethernetShortcutConverter.cs +++ /dev/null @@ -1,162 +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; - -internal sealed class AethernetShortcutConverter : JsonConverter -{ - private static readonly Dictionary EnumToString = 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" }, - { EAetheryteLocation.IdyllshireEpilogueGate, "[Idyllshire] Epilogue Gate" }, - - { 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.CrystariumThemenosRookery, "[Crystarium] Themenos 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)" }, - }; - - 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) - { - ArgumentNullException.ThrowIfNull(writer); - ArgumentNullException.ThrowIfNull(value); - - 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 6d722458..00000000 --- a/Questionable/Model/V1/Converter/AetheryteConverter.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal 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" } - }; - - 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 b40304d7..00000000 --- a/Questionable/Model/V1/Converter/DialogueChoiceTypeConverter.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal 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 bf8e62de..00000000 --- a/Questionable/Model/V1/Converter/EmoteConverter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal 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" }, - }; -} diff --git a/Questionable/Model/V1/Converter/EnemySpawnTypeConverter.cs b/Questionable/Model/V1/Converter/EnemySpawnTypeConverter.cs deleted file mode 100644 index a0ffe843..00000000 --- a/Questionable/Model/V1/Converter/EnemySpawnTypeConverter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal 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 afd37fde..00000000 --- a/Questionable/Model/V1/Converter/EnumConverter.cs +++ /dev/null @@ -1,43 +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; - -internal 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) - : values.ToDictionary(x => x.Key, x => x.Value).AsReadOnly(); - _stringToEnum = _enumToString.ToDictionary(x => x.Value, x => x.Key) - .AsReadOnly(); - } - - 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) - { - ArgumentNullException.ThrowIfNull(writer); - 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 0c446e4e..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; - -internal sealed class ExcelRefConverter : JsonConverter -{ - public override ExcelRef? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.String) - return new ExcelRef(reader.GetString()!); - else if (reader.TokenType == JsonTokenType.Number) - return new ExcelRef(reader.GetUInt32()); - else - return 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 d67435f5..00000000 --- a/Questionable/Model/V1/Converter/InteractionTypeConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal 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.WaitForObjectAtPosition, "WaitForNpcAtPosition" }, - { EInteractionType.WaitForManualProgress, "WaitForManualProgress" }, - { EInteractionType.Duty, "Duty" }, - { EInteractionType.SinglePlayerDuty, "SinglePlayerDuty" }, - { EInteractionType.Jump, "Jump" }, - { EInteractionType.ShouldBeAJump, "ShouldBeAJump" }, - { EInteractionType.Instruction, "Instruction" }, - }; -} diff --git a/Questionable/Model/V1/Converter/SkipConditionConverter.cs b/Questionable/Model/V1/Converter/SkipConditionConverter.cs deleted file mode 100644 index a65d5044..00000000 --- a/Questionable/Model/V1/Converter/SkipConditionConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Questionable.Model.V1.Converter; - -internal sealed class SkipConditionConverter() : EnumConverter(Values) -{ - private static readonly Dictionary Values = new() - { - { ESkipCondition.Never, "Never" }, - { ESkipCondition.FlyingLocked, "FlyingLocked" }, - { ESkipCondition.FlyingUnlocked, "FlyingUnlocked" }, - }; -} diff --git a/Questionable/Model/V1/Converter/VectorConverter.cs b/Questionable/Model/V1/Converter/VectorConverter.cs deleted file mode 100644 index 575fd885..00000000 --- a/Questionable/Model/V1/Converter/VectorConverter.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Numerics; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Questionable.Model.V1.Converter; - -internal 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) - { - ArgumentNullException.ThrowIfNull(writer); - - 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 ddfc0ae0..00000000 --- a/Questionable/Model/V1/DialogueChoice.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Text.Json.Serialization; -using JetBrains.Annotations; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal 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/EAetheryteLocation.cs b/Questionable/Model/V1/EAetheryteLocation.cs deleted file mode 100644 index c6ec79f9..00000000 --- a/Questionable/Model/V1/EAetheryteLocation.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(AetheryteConverter))] -internal 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, - CrystariumThemenosRookery = 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 -} diff --git a/Questionable/Model/V1/EDialogChoiceType.cs b/Questionable/Model/V1/EDialogChoiceType.cs deleted file mode 100644 index e8f18dda..00000000 --- a/Questionable/Model/V1/EDialogChoiceType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Questionable.Model.V1; - -internal enum EDialogChoiceType -{ - None, - YesNo, - List, -} diff --git a/Questionable/Model/V1/EEmote.cs b/Questionable/Model/V1/EEmote.cs deleted file mode 100644 index 2e751d36..00000000 --- a/Questionable/Model/V1/EEmote.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(EmoteConverter))] -internal enum EEmote -{ - None = 0, - - Stretch = 37, - Wave = 16, - Rally = 34, - Deny = 25, - Pray = 58, - Slap = 111, - Doubt = 12, - Psych = 30, -} diff --git a/Questionable/Model/V1/EEnemySpawnType.cs b/Questionable/Model/V1/EEnemySpawnType.cs deleted file mode 100644 index 1c19132d..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))] -internal enum EEnemySpawnType -{ - None = 0, - AfterInteraction, - AfterItemUse, - AutoOnEnterArea, - OverworldEnemies, -} diff --git a/Questionable/Model/V1/EInteractionType.cs b/Questionable/Model/V1/EInteractionType.cs deleted file mode 100644 index edb27cee..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))] -internal enum EInteractionType -{ - Interact, - WalkTo, - AttuneAethernetShard, - AttuneAetheryte, - AttuneAetherCurrent, - Combat, - UseItem, - EquipItem, - Say, - Emote, - WaitForObjectAtPosition, - WaitForManualProgress, - Duty, - SinglePlayerDuty, - Jump, - - /// - /// Needs to be adjusted for coords etc. in the quest data. - /// - ShouldBeAJump, - - /// - /// Needs to be manually continued. - /// - Instruction, -} diff --git a/Questionable/Model/V1/ESkipCondition.cs b/Questionable/Model/V1/ESkipCondition.cs deleted file mode 100644 index f7e173c9..00000000 --- a/Questionable/Model/V1/ESkipCondition.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[JsonConverter(typeof(SkipConditionConverter))] -internal enum ESkipCondition -{ - None, - Never, - FlyingLocked, - FlyingUnlocked, -} diff --git a/Questionable/Model/V1/ExcelRef.cs b/Questionable/Model/V1/ExcelRef.cs deleted file mode 100644 index c6451ac2..00000000 --- a/Questionable/Model/V1/ExcelRef.cs +++ /dev/null @@ -1,48 +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; - } - - 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 enum EType - { - None, - Key, - RowId, - } -} diff --git a/Questionable/Model/V1/JumpDestination.cs b/Questionable/Model/V1/JumpDestination.cs deleted file mode 100644 index 1827f879..00000000 --- a/Questionable/Model/V1/JumpDestination.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Numerics; -using System.Text.Json.Serialization; -using JetBrains.Annotations; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal sealed class JumpDestination -{ - [JsonConverter(typeof(VectorConverter))] - public Vector3 Position { get; set; } - - public float? StopDistance { get; set; } - public float? DelaySeconds { get; set; } -} diff --git a/Questionable/Model/V1/QuestData.cs b/Questionable/Model/V1/QuestData.cs deleted file mode 100644 index d484481b..00000000 --- a/Questionable/Model/V1/QuestData.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using JetBrains.Annotations; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal sealed class QuestData -{ - public required string Author { get; set; } - public List Contributors { get; set; } = new(); - public string? Comment { get; set; } - public List TerritoryBlacklist { get; set; } = new(); - public required List QuestSequence { get; set; } = new(); -} diff --git a/Questionable/Model/V1/QuestSequence.cs b/Questionable/Model/V1/QuestSequence.cs deleted file mode 100644 index 58393c32..00000000 --- a/Questionable/Model/V1/QuestSequence.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using JetBrains.Annotations; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal sealed class QuestSequence -{ - public required 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]; - } -} diff --git a/Questionable/Model/V1/QuestStep.cs b/Questionable/Model/V1/QuestStep.cs deleted file mode 100644 index 44e3ce44..00000000 --- a/Questionable/Model/V1/QuestStep.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Numerics; -using System.Text.Json.Serialization; -using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; -using JetBrains.Annotations; -using Questionable.Model.V1.Converter; - -namespace Questionable.Model.V1; - -[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.WithMembers)] -internal sealed class QuestStep -{ - public EInteractionType InteractionType { get; set; } - - public uint? DataId { get; set; } - - [JsonConverter(typeof(VectorConverter))] - public Vector3? Position { get; set; } - - public float? StopDistance { get; set; } - public ushort TerritoryId { get; set; } - public ushort? TargetTerritoryId { get; set; } - - public bool Disabled { get; set; } - public bool DisableNavmesh { get; set; } - public bool? Mount { get; set; } - public bool? Fly { get; set; } - public bool? Sprint { get; set; } - public string? Comment { 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 EEnemySpawnType? EnemySpawnType { get; set; } - - public IList KillEnemyDataIds { get; set; } = new List(); - public JumpDestination? JumpDestination { get; set; } - public uint? ContentFinderConditionId { get; set; } - - public IList SkipIf { get; set; } = new List(); - public IList CompletionQuestVariablesFlags { get; set; } = new List(); - public IList DialogueChoices { get; set; } = new List(); - - /// - /// Positive values: Must be set to this value; will wait for the step to have these set. - /// Negative values: Will skip if set to this value, won't wait for this to be set. - /// - public unsafe bool MatchesQuestVariables(QuestWork questWork, bool forSkip) - { - if (CompletionQuestVariablesFlags.Count != 6) - return false; - - for (int i = 0; i < 6; ++i) - { - short? check = CompletionQuestVariablesFlags[i]; - if (check == null) - continue; - - byte actualValue = questWork.Variables[i]; - byte checkByte = check > 0 ? (byte)check : (byte)-check; - if (forSkip) - { - byte expectedValue = (byte)Math.Abs(check.Value); - if ((actualValue & checkByte) != expectedValue) - return false; - } - else if (!forSkip && check > 0) - { - byte expectedValue = check > 0 ? (byte)check : (byte)0; - if ((actualValue & checkByte) != expectedValue) - return false; - } - } - - return true; - } -} diff --git a/Questionable/Model/V1/QuestStepExtensions.cs b/Questionable/Model/V1/QuestStepExtensions.cs new file mode 100644 index 00000000..dedf2ebc --- /dev/null +++ b/Questionable/Model/V1/QuestStepExtensions.cs @@ -0,0 +1,41 @@ +using System; +using FFXIVClientStructs.FFXIV.Application.Network.WorkDefinitions; + +namespace Questionable.Model.V1; + +internal static class QuestStepExtensions +{ + /// + /// Positive values: Must be set to this value; will wait for the step to have these set. + /// Negative values: Will skip if set to this value, won't wait for this to be set. + /// + public static unsafe bool MatchesQuestVariables(this QuestStep step, QuestWork questWork, bool forSkip) + { + if (step.CompletionQuestVariablesFlags.Count != 6) + return false; + + for (int i = 0; i < 6; ++i) + { + short? check = step.CompletionQuestVariablesFlags[i]; + if (check == null) + continue; + + byte actualValue = questWork.Variables[i]; + byte checkByte = check > 0 ? (byte)check : (byte)-check; + if (forSkip) + { + byte expectedValue = (byte)Math.Abs(check.Value); + if ((actualValue & checkByte) != expectedValue) + return false; + } + else if (!forSkip && check > 0) + { + byte expectedValue = check > 0 ? (byte)check : (byte)0; + if ((actualValue & checkByte) != expectedValue) + return false; + } + } + + return true; + } +} diff --git a/Questionable/Questionable.csproj b/Questionable/Questionable.csproj index 2e9031b4..64a7caf1 100644 --- a/Questionable/Questionable.csproj +++ b/Questionable/Questionable.csproj @@ -59,6 +59,7 @@ - + + diff --git a/Questionable/packages.lock.json b/Questionable/packages.lock.json index e4dec3d5..f9ea92b0 100644 --- a/Questionable/packages.lock.json +++ b/Questionable/packages.lock.json @@ -86,8 +86,17 @@ "llib": { "type": "Project" }, + "questionable.model": { + "type": "Project", + "dependencies": { + "System.Text.Json": "[8.0.3, )" + } + }, "questpaths": { - "type": "Project" + "type": "Project", + "dependencies": { + "Questionable.Model": "[1.0.0, )" + } } } }