1
0
forked from liza/Questionable

Schema update

This commit is contained in:
Liza 2024-08-02 20:04:45 +02:00
parent ae87b4ccc5
commit 9bfbc99144
Signed by: liza
GPG Key ID: 7199F8D727D55F67
20 changed files with 502 additions and 104 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "LLib"] [submodule "LLib"]
path = LLib path = LLib
url = https://git.carvel.li/liza/LLib.git url = https://git.carvel.li/liza/LLib.git
[submodule "vendor/ECommons"]
path = vendor/ECommons
url = https://github.com/NightmareXIV/ECommons.git

View File

@ -1,3 +1,8 @@
<Project Sdk="Dalamud.NET.Sdk/10.0.0"> <Project Sdk="Dalamud.NET.Sdk/10.0.0">
<ItemGroup>
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" />
<ProjectReference Include="..\vendor\ECommons\ECommons\ECommons.csproj" />
</ItemGroup>
<Import Project="..\LLib\LLib.targets"/> <Import Project="..\LLib\LLib.targets"/>
</Project> </Project>

View File

@ -0,0 +1,6 @@
{
"Name": "GatheringPathRenderer",
"Author": "Liza Carvelli",
"Punchline": "dev only plugin: Renders gathering location.",
"Description": "dev only plugin: Renders gathering location (without ECommons polluting the entire normal project)."
}

View File

@ -1,11 +1,189 @@
using Dalamud.Plugin; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using ECommons;
using ECommons.Schedulers;
using ECommons.SplatoonAPI;
using Questionable.Model.Gathering;
namespace GatheringPathRenderer; namespace GatheringPathRenderer;
public sealed class RendererPlugin : IDalamudPlugin public sealed class RendererPlugin : IDalamudPlugin
{ {
private const long OnTerritoryChange = -2;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly IClientState _clientState;
private readonly IPluginLog _pluginLog;
private readonly List<(ushort Id, GatheringRoot Root)> _gatheringLocations = [];
public RendererPlugin(IDalamudPluginInterface pluginInterface, IClientState clientState, IPluginLog pluginLog)
{
_pluginInterface = pluginInterface;
_clientState = clientState;
_pluginLog = pluginLog;
_pluginInterface.GetIpcSubscriber<object>("Questionable.ReloadData")
.Subscribe(Reload);
ECommonsMain.Init(pluginInterface, this, Module.SplatoonAPI);
LoadGatheringLocationsFromDirectory();
_clientState.TerritoryChanged += TerritoryChanged;
if (_clientState.IsLoggedIn)
TerritoryChanged(_clientState.TerritoryType);
}
private void Reload()
{
LoadGatheringLocationsFromDirectory();
TerritoryChanged(_clientState.TerritoryType);
}
private void LoadGatheringLocationsFromDirectory()
{
_gatheringLocations.Clear();
DirectoryInfo? solutionDirectory = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent?.Parent;
if (solutionDirectory != null)
{
DirectoryInfo pathProjectDirectory =
new DirectoryInfo(Path.Combine(solutionDirectory.FullName, "GatheringPaths"));
if (pathProjectDirectory.Exists)
{
try
{
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "2.x - A Realm Reborn")));
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "3.x - Heavensward")));
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "4.x - Stormblood")));
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "5.x - Shadowbringers")));
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "6.x - Endwalker")));
LoadFromDirectory(
new DirectoryInfo(Path.Combine(pathProjectDirectory.FullName, "7.x - Dawntrail")));
_pluginLog.Information(
$"Loaded {_gatheringLocations.Count} gathering root locations from project directory");
}
catch (Exception e)
{
_pluginLog.Error(e, "Failed to load quests from project directory");
}
}
else
_pluginLog.Warning($"Project directory {pathProjectDirectory} does not exist");
}
else
_pluginLog.Warning($"Solution directory {solutionDirectory} does not exist");
}
private void LoadFromDirectory(DirectoryInfo directory)
{
if (!directory.Exists)
return;
_pluginLog.Information($"Loading locations from {directory}");
foreach (FileInfo fileInfo in directory.GetFiles("*.json"))
{
try
{
using FileStream stream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read);
LoadLocationFromStream(fileInfo.Name, stream);
}
catch (Exception e)
{
throw new InvalidDataException($"Unable to load file {fileInfo.FullName}", e);
}
}
foreach (DirectoryInfo childDirectory in directory.GetDirectories())
LoadFromDirectory(childDirectory);
}
private void LoadLocationFromStream(string fileName, Stream stream)
{
var locationNode = JsonNode.Parse(stream)!;
GatheringRoot root = locationNode.Deserialize<GatheringRoot>()!;
_gatheringLocations.Add((ushort.Parse(fileName.Split('_')[0]), root));
}
private void TerritoryChanged(ushort territoryId)
{
Splatoon.RemoveDynamicElements("GatheringPathRenderer");
var elements = _gatheringLocations
.Where(x => x.Root.TerritoryId == territoryId)
.SelectMany(v =>
v.Root.Groups.SelectMany(group =>
group.Nodes.SelectMany(node => node.Locations
.SelectMany(x =>
new List<Element>
{
new Element(x.IsCone()
? ElementType.ConeAtFixedCoordinates
: ElementType.CircleAtFixedCoordinates)
{
refX = x.Position.X,
refY = x.Position.Z,
refZ = x.Position.Y,
Filled = true,
radius = x.MinimumDistance,
Donut = x.MaximumDistance - x.MinimumDistance,
color = 0x2020FF80,
Enabled = true,
coneAngleMin = x.IsCone() ? (int)x.MinimumAngle.GetValueOrDefault() : 0,
coneAngleMax = x.IsCone() ? (int)x.MaximumAngle.GetValueOrDefault() : 0
},
new Element(ElementType.CircleAtFixedCoordinates)
{
refX = x.Position.X,
refY = x.Position.Z,
refZ = x.Position.Y,
color = 0x00000000,
Enabled = true,
overlayText = $"{v.Id} // {node.DataId} / {node.Locations.IndexOf(x)}"
}
}))))
.ToList();
if (elements.Count == 0)
{
_pluginLog.Information("No new elements to render.");
return;
}
_ = new TickScheduler(delegate
{
try
{
Splatoon.AddDynamicElements("GatheringPathRenderer",
elements.ToArray(),
new[] { OnTerritoryChange });
_pluginLog.Information($"Created {elements.Count} splatoon elements.");
}
catch (Exception e)
{
_pluginLog.Error(e, "Unable to create splatoon layer");
}
});
}
public void Dispose() public void Dispose()
{ {
_clientState.TerritoryChanged -= TerritoryChanged;
Splatoon.RemoveDynamicElements("GatheringPathRenderer");
ECommonsMain.Dispose();
_pluginInterface.GetIpcSubscriber<object>("Questionable.ReloadData")
.Unsubscribe(Reload);
} }
} }

View File

@ -75,6 +75,34 @@
"Microsoft.Build.Tasks.Git": "1.1.1", "Microsoft.Build.Tasks.Git": "1.1.1",
"Microsoft.SourceLink.Common": "1.1.1" "Microsoft.SourceLink.Common": "1.1.1"
} }
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
},
"System.Text.Json": {
"type": "Transitive",
"resolved": "8.0.4",
"contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==",
"dependencies": {
"System.Text.Encodings.Web": "8.0.0"
}
},
"ecommons": {
"type": "Project"
},
"gatheringpaths": {
"type": "Project",
"dependencies": {
"Questionable.Model": "[1.0.0, )"
}
},
"questionable.model": {
"type": "Project",
"dependencies": {
"System.Text.Json": "[8.0.4, )"
}
} }
} }
} }

View File

@ -3,54 +3,148 @@
"Author": "liza", "Author": "liza",
"TerritoryId": 957, "TerritoryId": 957,
"AetheryteShortcut": "Thavnair - Great Work", "AetheryteShortcut": "Thavnair - Great Work",
"Nodes": [ "Groups": [
{ {
"DataId": 33918, "Nodes": [
"Position": { {
"X": -582.5132, "DataId": 33918,
"Y": 40.54578, "Locations": [
"Z": -426.0171 {
} "Position": {
"X": -582.5132,
"Y": 40.54578,
"Z": -426.0171
},
"MinimumAngle": -50,
"MaximumAngle": 90
}
]
},
{
"DataId": 33919,
"Locations": [
{
"Position": {
"X": -578.2101,
"Y": 41.27147,
"Z": -447.6376
},
"MinimumAngle": 130,
"MaximumAngle": 220
},
{
"Position": {
"X": -546.2882,
"Y": 44.52267,
"Z": -435.8184
},
"MinimumAngle": 200,
"MaximumAngle": 360
}
]
}
]
}, },
{ {
"DataId": 33919, "Nodes": [
"Position": { {
"X": -578.2101, "DataId": 33920,
"Y": 41.27147, "Locations": [
"Z": -447.6376 {
} "Position": {
"X": -488.2276,
"Y": 34.71221,
"Z": -359.6945
},
"MinimumAngle": 20,
"MaximumAngle": 128,
"MinimumDistance": 1.3
}
]
},
{
"DataId": 33921,
"Locations": [
{
"Position": {
"X": -498.8687,
"Y": 31.08014,
"Z": -351.9397
},
"MinimumAngle": 40,
"MaximumAngle": 190
},
{
"Position": {
"X": -490.7759,
"Y": 28.70215,
"Z": -344.4114
},
"MinimumAngle": -110,
"MaximumAngle": 60
},
{
"Position": {
"X": -494.1286,
"Y": 32.89971,
"Z": -355.0208
},
"MinimumAngle": 80,
"MaximumAngle": 230
}
]
}
]
}, },
{ {
"DataId": 33920, "Nodes": [
"Position": { {
"X": -488.2276, "DataId": 33922,
"Y": 34.71221, "Locations": [
"Z": -359.6945 {
} "Position": {
}, "X": -304.0609,
{ "Y": 68.76999,
"DataId": 33921, "Z": -479.1875
"Position": { },
"X": -498.8687, "MinimumAngle": -110,
"Y": 31.08014, "MaximumAngle": 70
"Z": -351.9397 }
} ]
}, },
{ {
"DataId": 33922, "DataId": 33923,
"Position": { "Locations": [
"X": -304.0609, {
"Y": 68.76999, "Position": {
"Z": -479.1875 "X": -293.6989,
} "Y": 68.77935,
}, "Z": -484.2256
{ },
"DataId": 33923, "MinimumAngle": -30,
"Position": { "MaximumAngle": 110
"X": -293.6989, },
"Y": 68.77935, {
"Z": -484.2256 "Position": {
} "X": -295.0806,
"Y": 69.12621,
"Z": -498.1898
},
"MinimumAngle": 10,
"MaximumAngle": 200
},
{
"Position": {
"X": -281.4858,
"Y": 67.64153,
"Z": -477.6673
},
"MinimumAngle": -90,
"MaximumAngle": 60
}
]
}
]
} }
] ]
} }

View File

@ -16,12 +16,10 @@ public static partial class AssemblyGatheringLocationLoader
if (_locations == null) if (_locations == null)
{ {
_locations = []; _locations = [];
#if RELEASE
LoadLocations(); LoadLocations();
#endif
} }
return _locations ?? throw new InvalidOperationException("quest data is not initialized"); return _locations ?? throw new InvalidOperationException("location data is not initialized");
} }
public static Stream QuestSchema => public static Stream QuestSchema =>

View File

@ -26,7 +26,7 @@
<AdditionalFiles Include="..\Questionable.Model\common-schema.json" /> <AdditionalFiles Include="..\Questionable.Model\common-schema.json" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'"> <ItemGroup>
<None Remove="2.x - A Realm Reborn" /> <None Remove="2.x - A Realm Reborn" />
<None Remove="3.x - Heavensward" /> <None Remove="3.x - Heavensward" />
<None Remove="4.x - Stormblood" /> <None Remove="4.x - Stormblood" />

View File

@ -25,41 +25,64 @@
"AetheryteShortcut": { "AetheryteShortcut": {
"$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte" "$ref": "https://git.carvel.li/liza/Questionable/raw/branch/master/Questionable.Model/common-schema.json#/$defs/Aetheryte"
}, },
"Nodes": { "Groups": {
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
"properties": { "properties": {
"DataId": { "Nodes": {
"type": "number", "type": "array",
"minimum": 30000, "items": {
"maximum": 50000 "type": "object",
}, "properties": {
"Position": { "DataId": {
"$ref": "#/$defs/Vector3" "type": "number",
}, "minimum": 30000,
"MinimumAngle": { "maximum": 50000
"type": "number", },
"minimum": -360, "Locations": {
"maximum": 360 "type": "array",
}, "items": {
"MaximumAngle": { "type": "object",
"type": "number", "properties": {
"minimum": -360, "Position": {
"maximum": 360 "$ref": "#/$defs/Vector3"
}, },
"MinimumDistance": { "MinimumAngle": {
"type": "number", "type": "number",
"minimum": 0 "minimum": -360,
}, "maximum": 360
"MaximumDistance": { },
"type": "number", "MaximumAngle": {
"exclusiveMinimum": 0 "type": "number",
"minimum": -360,
"maximum": 360
},
"MinimumDistance": {
"type": "number",
"minimum": 0
},
"MaximumDistance": {
"type": "number",
"exclusiveMinimum": 0
}
},
"required": [
"Position"
],
"additionalProperties": false
}
}
},
"required": [
"DataId"
],
"additionalProperties": false
}
} }
}, },
"required": [ "required": [
"DataId", "Nodes"
"Position"
], ],
"additionalProperties": false "additionalProperties": false
} }

View File

@ -153,7 +153,7 @@ public class GatheringSourceGenerator : ISourceGenerator
Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, default) Assignment(nameof(GatheringRoot.TerritoryId), root.TerritoryId, default)
.AsSyntaxNodeOrToken(), .AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut, null), Assignment(nameof(GatheringRoot.AetheryteShortcut), root.AetheryteShortcut, null),
AssignmentList(nameof(GatheringRoot.Nodes), root.Nodes).AsSyntaxNodeOrToken())))); AssignmentList(nameof(GatheringRoot.Groups), root.Groups).AsSyntaxNodeOrToken()))));
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -314,30 +314,55 @@ public static class RoslynShortcuts
Assignment(nameof(SkipAetheryteCondition.InSameTerritory), Assignment(nameof(SkipAetheryteCondition.InSameTerritory),
skipAetheryteCondition.InSameTerritory, emptyAetheryte.InSameTerritory))))); skipAetheryteCondition.InSameTerritory, emptyAetheryte.InSameTerritory)))));
} }
else if (value is GatheringNodeLocation nodeLocation) else if (value is GatheringNodeGroup nodeGroup)
{ {
var emptyLocation = new GatheringNodeLocation();
return ObjectCreationExpression( return ObjectCreationExpression(
IdentifierName(nameof(GatheringNodeLocation))) IdentifierName(nameof(GatheringNodeGroup)))
.WithInitializer( .WithInitializer(
InitializerExpression( InitializerExpression(
SyntaxKind.ObjectInitializerExpression, SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>( SeparatedList<ExpressionSyntax>(
SyntaxNodeList( SyntaxNodeList(
Assignment(nameof(GatheringNodeLocation.DataId), nodeLocation.DataId, AssignmentList(nameof(GatheringNodeGroup.Nodes), nodeGroup.Nodes)
.AsSyntaxNodeOrToken()))));
}
else if (value is GatheringNode nodeLocation)
{
var emptyLocation = new GatheringNode();
return ObjectCreationExpression(
IdentifierName(nameof(GatheringNode)))
.WithInitializer(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
SyntaxNodeList(
Assignment(nameof(GatheringNode.DataId), nodeLocation.DataId,
emptyLocation.DataId) emptyLocation.DataId)
.AsSyntaxNodeOrToken(), .AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringNodeLocation.Position), nodeLocation.Position, AssignmentList(nameof(GatheringNode.Locations), nodeLocation.Locations)
.AsSyntaxNodeOrToken()))));
}
else if (value is GatheringLocation location)
{
var emptyLocation = new GatheringLocation();
return ObjectCreationExpression(
IdentifierName(nameof(GatheringLocation)))
.WithInitializer(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(
SyntaxNodeList(
Assignment(nameof(GatheringLocation.Position), location.Position,
emptyLocation.Position).AsSyntaxNodeOrToken(), emptyLocation.Position).AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringNodeLocation.MinimumAngle), nodeLocation.MinimumAngle, Assignment(nameof(GatheringLocation.MinimumAngle), location.MinimumAngle,
emptyLocation.MinimumAngle).AsSyntaxNodeOrToken(), emptyLocation.MinimumAngle).AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringNodeLocation.MaximumAngle), nodeLocation.MaximumAngle, Assignment(nameof(GatheringLocation.MaximumAngle), location.MaximumAngle,
emptyLocation.MaximumAngle).AsSyntaxNodeOrToken(), emptyLocation.MaximumAngle).AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringNodeLocation.MinimumDistance), Assignment(nameof(GatheringLocation.MinimumDistance),
nodeLocation.MinimumDistance, emptyLocation.MinimumDistance) location.MinimumDistance, emptyLocation.MinimumDistance)
.AsSyntaxNodeOrToken(), .AsSyntaxNodeOrToken(),
Assignment(nameof(GatheringNodeLocation.MaximumDistance), Assignment(nameof(GatheringLocation.MaximumDistance),
nodeLocation.MaximumDistance, emptyLocation.MaximumDistance) location.MaximumDistance, emptyLocation.MaximumDistance)
.AsSyntaxNodeOrToken())))); .AsSyntaxNodeOrToken()))));
} }
else if (value is null) else if (value is null)

View File

@ -55,12 +55,13 @@ public static class Utils
Culture = CultureInfo.InvariantCulture, Culture = CultureInfo.InvariantCulture,
OutputFormat = OutputFormat.List, OutputFormat = OutputFormat.List,
}); });
if (!evaluationResult.IsValid) if (evaluationResult.HasErrors)
{ {
var error = Diagnostic.Create(invalidJson, var error = Diagnostic.Create(invalidJson,
null, null,
Path.GetFileName(additionalFile.Path)); Path.GetFileName(additionalFile.Path));
context.ReportDiagnostic(error); context.ReportDiagnostic(error);
continue;
} }
yield return (id, node); yield return (id, node);

View File

@ -0,0 +1,21 @@
using System.Numerics;
using System.Text.Json.Serialization;
using Questionable.Model.Common.Converter;
namespace Questionable.Model.Gathering;
public sealed class GatheringLocation
{
[JsonConverter(typeof(VectorConverter))]
public Vector3 Position { get; set; }
public float? MinimumAngle { get; set; }
public float? MaximumAngle { get; set; }
public float MinimumDistance { get; set; } = 1f;
public float MaximumDistance { get; set; } = 3f;
public bool IsCone()
{
return MinimumAngle != null && MaximumAngle != null;
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Questionable.Model.Gathering;
public sealed class GatheringNode
{
public uint DataId { get; set; }
public List<GatheringLocation> Locations { get; set; } = [];
}

View File

@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Questionable.Model.Gathering;
public sealed class GatheringNodeGroup
{
public List<GatheringNode> Nodes { get; set; } = [];
}

View File

@ -1,13 +0,0 @@
using System.Numerics;
namespace Questionable.Model.Gathering;
public sealed class GatheringNodeLocation
{
public uint DataId { get; set; }
public Vector3 Position { get; set; }
public float? MinimumAngle { get; set; }
public float? MaximumAngle { get; set; }
public float? MinimumDistance { get; set; } = 0.5f;
public float? MaximumDistance { get; set; } = 3f;
}

View File

@ -14,5 +14,5 @@ public sealed class GatheringRoot
[JsonConverter(typeof(AetheryteConverter))] [JsonConverter(typeof(AetheryteConverter))]
public EAetheryteLocation? AetheryteShortcut { get; set; } public EAetheryteLocation? AetheryteShortcut { get; set; }
public List<GatheringNodeLocation> Nodes { get; set; } = []; public List<GatheringNodeGroup> Groups { get; set; } = [];
} }

View File

@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPaths", "Gathering
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPathRenderer", "GatheringPathRenderer\GatheringPathRenderer.csproj", "{F514DA95-9867-4F3F-8062-ACE0C62E8740}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GatheringPathRenderer", "GatheringPathRenderer\GatheringPathRenderer.csproj", "{F514DA95-9867-4F3F-8062-ACE0C62E8740}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ECommons", "vendor\ECommons\ECommons\ECommons.csproj", "{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@ -57,6 +59,10 @@ Global
{F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.Build.0 = Debug|Any CPU {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Debug|x64.Build.0 = Debug|Any CPU
{F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.ActiveCfg = Release|Any CPU {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.ActiveCfg = Release|Any CPU
{F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.Build.0 = Release|Any CPU {F514DA95-9867-4F3F-8062-ACE0C62E8740}.Release|x64.Build.0 = Release|Any CPU
{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Debug|x64.ActiveCfg = Debug|x64
{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Debug|x64.Build.0 = Debug|x64
{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Release|x64.ActiveCfg = Release|x64
{A12D7B4B-8E6E-4DCF-A41A-12F62E9FF94B}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Questionable.Data; using Questionable.Data;
using Questionable.Model; using Questionable.Model;
@ -23,8 +24,9 @@ internal sealed class QuestRegistry
private readonly IDalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _pluginInterface;
private readonly QuestData _questData; private readonly QuestData _questData;
private readonly QuestValidator _questValidator; private readonly QuestValidator _questValidator;
private readonly ILogger<QuestRegistry> _logger;
private readonly JsonSchemaValidator _jsonSchemaValidator; private readonly JsonSchemaValidator _jsonSchemaValidator;
private readonly ILogger<QuestRegistry> _logger;
private readonly ICallGateProvider<object> _reloadDataIpc;
private readonly Dictionary<ushort, Quest> _quests = new(); private readonly Dictionary<ushort, Quest> _quests = new();
@ -37,6 +39,7 @@ internal sealed class QuestRegistry
_questValidator = questValidator; _questValidator = questValidator;
_jsonSchemaValidator = jsonSchemaValidator; _jsonSchemaValidator = jsonSchemaValidator;
_logger = logger; _logger = logger;
_reloadDataIpc = _pluginInterface.GetIpcProvider<object>("Questionable.ReloadData");
} }
public IEnumerable<Quest> AllQuests => _quests.Values; public IEnumerable<Quest> AllQuests => _quests.Values;
@ -66,6 +69,7 @@ internal sealed class QuestRegistry
ValidateQuests(); ValidateQuests();
Reloaded?.Invoke(this, EventArgs.Empty); Reloaded?.Invoke(this, EventArgs.Empty);
_reloadDataIpc.SendMessage();
_logger.LogInformation("Loaded {Count} quests in total", _quests.Count); _logger.LogInformation("Loaded {Count} quests in total", _quests.Count);
} }

1
vendor/ECommons vendored Submodule

@ -0,0 +1 @@
Subproject commit 9e90d0032f0efd4c9e65d9c5a8e8bd0e99557d68