using System;
+using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
+using System.Text.Json.Serialization.Metadata;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
WriteIndented = true,
+ TypeInfoResolver = new DefaultJsonTypeInfoResolver
+ {
+ Modifiers = { NoEmptyCollectionModifier }
+ },
};
using (var stream = File.Create(targetFile.FullName))
{
Reload();
}
+ private static void NoEmptyCollectionModifier(JsonTypeInfo typeInfo)
+ {
+ foreach (var property in typeInfo.Properties)
+ {
+ if (typeof(ICollection).IsAssignableFrom(property.PropertyType))
+ {
+ property.ShouldSerialize = (_, val) => val is ICollection { Count: > 0 };
+ }
+ }
+ }
+
private void TerritoryChanged(ushort territoryId) => Redraw();
private void ClassJobChanged(uint classJobId)
refZ = x.Position.Y,
Filled = true,
radius = locationOverride?.MinimumDistance ?? x.CalculateMinimumDistance(),
- Donut = (locationOverride?.MaximumDistance ?? x.CalculateMaximumDistance()) - (locationOverride?.MinimumDistance ?? x.CalculateMinimumDistance()),
+ Donut = (locationOverride?.MaximumDistance ?? x.CalculateMaximumDistance()) -
+ (locationOverride?.MinimumDistance ?? x.CalculateMinimumDistance()),
color = _colors[location.Root.Groups.IndexOf(group) % _colors.Count],
Enabled = true,
coneAngleMin = minimumAngle,
"AethernetShortcut": [
"[Idyllshire] Aetheryte Plaza",
"[Idyllshire] Epilogue Gate (Eastern Hinterlands)"
- ]
+ ],
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InTerritory": [
+ 399
+ ]
+ }
+ }
}
],
"Groups": [
"AethernetShortcut": [
"[Idyllshire] Aetheryte Plaza",
"[Idyllshire] Prologue Gate (Western Hinterlands)"
- ]
+ ],
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InTerritory": [
+ 399
+ ]
+ }
+ }
}
],
"Groups": [
--- /dev/null
+{
+ "$schema": "https://git.carvel.li/liza/Questionable/raw/branch/master/GatheringPaths/gatheringlocation-v1.json",
+ "Author": "liza",
+ "Steps": [
+ {
+ "TerritoryId": 399,
+ "InteractionType": "None",
+ "AetheryteShortcut": "Idyllshire",
+ "AethernetShortcut": [
+ "[Idyllshire] Aetheryte Plaza",
+ "[Idyllshire] Prologue Gate (Western Hinterlands)"
+ ],
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InTerritory": [
+ 399
+ ]
+ }
+ }
+ }
+ ],
+ "Groups": [
+ {
+ "Nodes": [
+ {
+ "DataId": 33285,
+ "Locations": [
+ {
+ "Position": {
+ "X": -426.4134,
+ "Y": 137.5601,
+ "Z": 514.3357
+ }
+ }
+ ]
+ },
+ {
+ "DataId": 33286,
+ "Locations": [
+ {
+ "Position": {
+ "X": -448.7838,
+ "Y": 137.5986,
+ "Z": 514.3243
+ }
+ },
+ {
+ "Position": {
+ "X": -433.5015,
+ "Y": 137.6451,
+ "Z": 487.8173
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "Nodes": [
+ {
+ "DataId": 33288,
+ "Locations": [
+ {
+ "Position": {
+ "X": -354.5423,
+ "Y": 137.5715,
+ "Z": 638.9959
+ }
+ }
+ ]
+ },
+ {
+ "DataId": 33287,
+ "Locations": [
+ {
+ "Position": {
+ "X": -352.4377,
+ "Y": 137.5906,
+ "Z": 604.364
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "Nodes": [
+ {
+ "DataId": 33284,
+ "Locations": [
+ {
+ "Position": {
+ "X": -254.4776,
+ "Y": 137.97,
+ "Z": 591.0092
+ },
+ "MinimumAngle": -20,
+ "MaximumAngle": 85
+ }
+ ]
+ },
+ {
+ "DataId": 33283,
+ "Locations": [
+ {
+ "Position": {
+ "X": -263.1079,
+ "Y": 137.4419,
+ "Z": 569.8724
+ },
+ "MinimumAngle": -10,
+ "MaximumAngle": 190
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Text.Json.Serialization;
using Questionable.Model.Common;
namespace Questionable.Model.Questing;
+[SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")]
public sealed class QuestStep
{
public const float DefaultStopDistance = 3f;
- public EInteractionType InteractionType { get; set; }
-
public uint? DataId { get; set; }
[JsonConverter(typeof(VectorConverter))]
public Vector3? Position { get; set; }
public float? StopDistance { get; set; }
- public float? NpcWaitDistance { get; set; }
public ushort TerritoryId { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
+ public EInteractionType InteractionType { get; set; }
+
+ public float? NpcWaitDistance { get; set; }
public ushort? TargetTerritoryId { get; set; }
public float? DelaySecondsAtStart { get; set; }
public EAction? Action { get; set; }
public EEnemySpawnType? EnemySpawnType { get; set; }
- public IList<uint> KillEnemyDataIds { get; set; } = new List<uint>();
- public IList<ComplexCombatData> ComplexCombatData { get; set; } = new List<ComplexCombatData>();
+ public List<uint> KillEnemyDataIds { get; set; } = [];
+ public List<ComplexCombatData> ComplexCombatData { get; set; } = [];
public float? CombatDelaySecondsAtStart { get; set; }
public JumpDestination? JumpDestination { get; set; }
public List<List<QuestWorkValue>?> RequiredQuestVariables { get; set; } = new();
public List<GatheredItem> RequiredGatheredItems { get; set; } = [];
- public IList<QuestWorkValue?> CompletionQuestVariablesFlags { get; set; } = new List<QuestWorkValue?>();
- public IList<DialogueChoice> DialogueChoices { get; set; } = new List<DialogueChoice>();
- public IList<uint> PointMenuChoices { get; set; } = new List<uint>();
+ public List<QuestWorkValue?> CompletionQuestVariablesFlags { get; set; } = [];
+ public List<DialogueChoice> DialogueChoices { get; set; } = [];
+ public List<uint> PointMenuChoices { get; set; } = [];
// TODO: Not implemented
[JsonConverter(typeof(ElementIdConverter))]
if (toastAware.OnErrorToast(message))
{
isHandled = true;
- return;
}
}
}
if (!_questRegistry.TryGetQuest(x, out Quest? quest))
return false;
- return quest.AllSteps().All(x =>
+ return quest.AllSteps().All(y =>
{
- if (x.Step.AetheryteShortcut is { } aetheryteShortcut &&
+ if (y.Step.AetheryteShortcut is { } aetheryteShortcut &&
_aetheryteFunctions.IsAetheryteUnlocked(aetheryteShortcut))
return false;
- if (x.Step.AethernetShortcut is { } aethernetShortcut &&
+ if (y.Step.AethernetShortcut is { } aethernetShortcut &&
(!_aetheryteFunctions.IsAetheryteUnlocked(aethernetShortcut.From) ||
!_aetheryteFunctions.IsAetheryteUnlocked(aethernetShortcut.To)))
return false;