muffin v7.4.18
This commit is contained in:
parent
53aa9fdee8
commit
f82b9ce2a2
50 changed files with 142364 additions and 230361 deletions
|
|
@ -48,26 +48,22 @@ public static class AssemblyFateDefinitionLoader
|
||||||
List<FateActionTarget> list = new List<FateActionTarget>(num);
|
List<FateActionTarget> list = new List<FateActionTarget>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<FateActionTarget> span = CollectionsMarshal.AsSpan(list);
|
Span<FateActionTarget> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = new FateActionTarget
|
||||||
span[num2] = new FateActionTarget
|
|
||||||
{
|
{
|
||||||
DataId = 18862u,
|
DataId = 18862u,
|
||||||
Action = EAction.CheerRhythmYellow
|
Action = EAction.CheerRhythmYellow
|
||||||
};
|
};
|
||||||
num2++;
|
span[1] = new FateActionTarget
|
||||||
span[num2] = new FateActionTarget
|
|
||||||
{
|
{
|
||||||
DataId = 18860u,
|
DataId = 18860u,
|
||||||
Action = EAction.CheerRhythmBlue
|
Action = EAction.CheerRhythmBlue
|
||||||
};
|
};
|
||||||
num2++;
|
span[2] = new FateActionTarget
|
||||||
span[num2] = new FateActionTarget
|
|
||||||
{
|
{
|
||||||
DataId = 18861u,
|
DataId = 18861u,
|
||||||
Action = EAction.CheerRhythmGreen
|
Action = EAction.CheerRhythmGreen
|
||||||
};
|
};
|
||||||
num2++;
|
span[3] = new FateActionTarget
|
||||||
span[num2] = new FateActionTarget
|
|
||||||
{
|
{
|
||||||
DataId = 18859u,
|
DataId = 18859u,
|
||||||
Action = EAction.CheerRhythmRed
|
Action = EAction.CheerRhythmRed
|
||||||
|
|
@ -76,34 +72,34 @@ public static class AssemblyFateDefinitionLoader
|
||||||
obj.RequiredStatusId = EStatus.FaceInTheCrowd;
|
obj.RequiredStatusId = EStatus.FaceInTheCrowd;
|
||||||
obj.TransformNpcDataId = 1055771u;
|
obj.TransformNpcDataId = 1055771u;
|
||||||
obj.TransformNpcPosition = new Vector3(-37.369385f, 5.0000005f, -130.14423f);
|
obj.TransformNpcPosition = new Vector3(-37.369385f, 5.0000005f, -130.14423f);
|
||||||
num2 = 3;
|
num = 3;
|
||||||
List<DialogueChoice> list2 = new List<DialogueChoice>(num2);
|
List<DialogueChoice> list2 = new List<DialogueChoice>(num);
|
||||||
CollectionsMarshal.SetCount(list2, num2);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<DialogueChoice> span2 = CollectionsMarshal.AsSpan(list2);
|
Span<DialogueChoice> span2 = CollectionsMarshal.AsSpan(list2);
|
||||||
num = 0;
|
span2[0] = new DialogueChoice
|
||||||
span2[num] = new DialogueChoice
|
|
||||||
{
|
{
|
||||||
Type = EDialogChoiceType.List,
|
Type = EDialogChoiceType.List,
|
||||||
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
||||||
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_Q1_000_000"),
|
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_Q1_000_000"),
|
||||||
Answer = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_A1_000_001")
|
Answer = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_A1_000_001")
|
||||||
};
|
};
|
||||||
num++;
|
span2[1] = new DialogueChoice
|
||||||
span2[num] = new DialogueChoice
|
|
||||||
{
|
{
|
||||||
Type = EDialogChoiceType.List,
|
Type = EDialogChoiceType.List,
|
||||||
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
||||||
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_Q2_000_000"),
|
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_Q2_000_000"),
|
||||||
Answer = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_A2_100_004")
|
Answer = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_A2_100_004")
|
||||||
};
|
};
|
||||||
num++;
|
span2[2] = new DialogueChoice
|
||||||
span2[num] = new DialogueChoice
|
|
||||||
{
|
{
|
||||||
Type = EDialogChoiceType.YesNo,
|
Type = EDialogChoiceType.YesNo,
|
||||||
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
ExcelSheet = "custom/009/FesPdy2026FateDisguise_00951",
|
||||||
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_CONFIRM_100_004")
|
Prompt = new ExcelRef("TEXT_FESPDY2026FATEDISGUISE_00951_CONFIRM_100_004")
|
||||||
};
|
};
|
||||||
obj.TransformDialogueChoices = list2;
|
obj.TransformDialogueChoices = list2;
|
||||||
|
obj.RequiredQuestId = (ushort)5444;
|
||||||
|
obj.StopAction = EAction.CurtainCall;
|
||||||
|
obj.EventExpiry = new DateTime(2026, 3, 12, 14, 59, 0, DateTimeKind.Utc);
|
||||||
AddDefinition(1, obj);
|
AddDefinition(1, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -90,6 +90,21 @@
|
||||||
"description": "The data id of the NPC/Object/Aetheryte/Aether Current",
|
"description": "The data id of the NPC/Object/Aetheryte/Aether Current",
|
||||||
"exclusiveMinimum": 0
|
"exclusiveMinimum": 0
|
||||||
},
|
},
|
||||||
|
"DataIds": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Multiple data ids to search for (e.g. for clearing randomly spawned objects)",
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"exclusiveMinimum": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"WaypointPositions": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Exit/waypoint positions to walk to after clearing all DataIds objects (e.g. doors between zones in a looping duty)",
|
||||||
|
"items": {
|
||||||
|
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Position": {
|
"Position": {
|
||||||
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
|
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
|
||||||
},
|
},
|
||||||
|
|
@ -624,8 +639,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"required": [
|
"anyOf": [
|
||||||
"Position"
|
{ "required": ["Position"] },
|
||||||
|
{ "required": ["DataId"] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1416,7 +1432,10 @@
|
||||||
"Cheer Rhythm: Red",
|
"Cheer Rhythm: Red",
|
||||||
"Cheer Rhythm: Blue",
|
"Cheer Rhythm: Blue",
|
||||||
"Cheer Rhythm: Green",
|
"Cheer Rhythm: Green",
|
||||||
"Cheer Rhythm: Yellow"
|
"Cheer Rhythm: Yellow",
|
||||||
|
"Pruning Pirouette",
|
||||||
|
"Roaring Eggscapade",
|
||||||
|
"The Spriganator"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -15,9 +15,7 @@ public sealed class StringListOrValueConverter : JsonConverter<List<string>>
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<string> list = new List<string>(num);
|
List<string> list = new List<string>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<string> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = reader.GetString();
|
||||||
int index = 0;
|
|
||||||
span[index] = reader.GetString();
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
if (reader.TokenType != JsonTokenType.StartArray)
|
if (reader.TokenType != JsonTokenType.StartArray)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Questionable.Model.Common.Converter;
|
||||||
|
|
||||||
|
public sealed class VectorListConverter : JsonConverter<List<Vector3>>
|
||||||
|
{
|
||||||
|
private static readonly VectorConverter ItemConverter = new VectorConverter();
|
||||||
|
|
||||||
|
public override List<Vector3> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonTokenType.StartArray)
|
||||||
|
{
|
||||||
|
throw new JsonException();
|
||||||
|
}
|
||||||
|
List<Vector3> list = new List<Vector3>();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.EndArray)
|
||||||
|
{
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
list.Add(ItemConverter.Read(ref reader, typeof(Vector3), options));
|
||||||
|
}
|
||||||
|
throw new JsonException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, List<Vector3> value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartArray();
|
||||||
|
foreach (Vector3 item in value)
|
||||||
|
{
|
||||||
|
ItemConverter.Write(writer, item, options);
|
||||||
|
}
|
||||||
|
writer.WriteEndArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -219,6 +219,18 @@ public sealed class ActionConverter : EnumConverter<EAction>
|
||||||
EAction.CheerRhythmYellow,
|
EAction.CheerRhythmYellow,
|
||||||
"Cheer Rhythm: Yellow"
|
"Cheer Rhythm: Yellow"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
EAction.PruningPirouette,
|
||||||
|
"Pruning Pirouette"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
EAction.RoaringEggscapade,
|
||||||
|
"Roaring Eggscapade"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
EAction.TheSpriganator,
|
||||||
|
"The Spriganator"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
EAction.CurtainCall,
|
EAction.CurtainCall,
|
||||||
"Curtain Call"
|
"Curtain Call"
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,9 @@ public enum EAction
|
||||||
CheerRhythmBlue = 44502,
|
CheerRhythmBlue = 44502,
|
||||||
CheerRhythmGreen = 44503,
|
CheerRhythmGreen = 44503,
|
||||||
CheerRhythmYellow = 44504,
|
CheerRhythmYellow = 44504,
|
||||||
|
PruningPirouette = 45127,
|
||||||
|
RoaringEggscapade = 42039,
|
||||||
|
TheSpriganator = 42038,
|
||||||
CurtainCall = 11063,
|
CurtainCall = 11063,
|
||||||
Prospect = 227,
|
Prospect = 227,
|
||||||
CollectMiner = 240,
|
CollectMiner = 240,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ public sealed class QuestStep
|
||||||
|
|
||||||
public uint? DataId { get; set; }
|
public uint? DataId { get; set; }
|
||||||
|
|
||||||
|
public List<uint> DataIds { get; set; } = new List<uint>();
|
||||||
|
|
||||||
|
[JsonConverter(typeof(VectorListConverter))]
|
||||||
|
public List<Vector3> WaypointPositions { get; set; } = new List<Vector3>();
|
||||||
|
|
||||||
[JsonConverter(typeof(VectorConverter))]
|
[JsonConverter(typeof(VectorConverter))]
|
||||||
public Vector3? Position { get; set; }
|
public Vector3? Position { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Questionable.Model.Common;
|
||||||
|
using Questionable.Model.Common.Converter;
|
||||||
|
using Questionable.Model.Questing.Converter;
|
||||||
|
|
||||||
|
namespace Questionable.Model.Questing;
|
||||||
|
|
||||||
|
public sealed class SeasonalDutyDefinition
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public ushort TerritoryId { get; set; }
|
||||||
|
|
||||||
|
public EAetheryteLocation Aetheryte { get; set; }
|
||||||
|
|
||||||
|
public AethernetShortcut? AethernetShortcut { get; set; }
|
||||||
|
|
||||||
|
public uint NpcDataId { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(VectorConverter))]
|
||||||
|
public Vector3 NpcPosition { get; set; }
|
||||||
|
|
||||||
|
public List<DialogueChoice> DialogueChoices { get; set; } = new List<DialogueChoice>();
|
||||||
|
|
||||||
|
public ushort DutyTerritoryId { get; set; }
|
||||||
|
|
||||||
|
public List<uint> DataIds { get; set; } = new List<uint>();
|
||||||
|
|
||||||
|
[JsonConverter(typeof(VectorListConverter))]
|
||||||
|
public List<Vector3> WaypointPositions { get; set; } = new List<Vector3>();
|
||||||
|
|
||||||
|
[JsonConverter(typeof(ActionConverter))]
|
||||||
|
public EAction Action { get; set; }
|
||||||
|
|
||||||
|
public float StopDistance { get; set; }
|
||||||
|
|
||||||
|
public ushort? RequiredQuestId { get; set; }
|
||||||
|
|
||||||
|
public DateTime? EventExpiry { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -63,6 +63,8 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
|
|
||||||
private readonly FateController _fateController;
|
private readonly FateController _fateController;
|
||||||
|
|
||||||
|
private readonly SeasonalDutyController _seasonalDutyController;
|
||||||
|
|
||||||
private readonly BossModIpc _bossModIpc;
|
private readonly BossModIpc _bossModIpc;
|
||||||
|
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
|
|
@ -79,7 +81,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!_isInitialCheck && !_questController.IsRunning && !_fateController.IsRunning)
|
if (!_isInitialCheck && !_questController.IsRunning && !_fateController.IsRunning && !_seasonalDutyController.IsRunning)
|
||||||
{
|
{
|
||||||
return _territoryData.IsQuestBattleInstance(_clientState.TerritoryType);
|
return _territoryData.IsQuestBattleInstance(_clientState.TerritoryType);
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +89,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe InteractionUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, QuestFunctions questFunctions, AetheryteFunctions aetheryteFunctions, ExcelFunctions excelFunctions, QuestController questController, GatheringPointRegistry gatheringPointRegistry, QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, IGameGui gameGui, ITargetManager targetManager, IPluginLog pluginLog, IClientState clientState, IObjectTable objectTable, ShopController shopController, FateController fateController, BossModIpc bossModIpc, Configuration configuration, ILogger<InteractionUiController> logger)
|
public unsafe InteractionUiController(IAddonLifecycle addonLifecycle, IDataManager dataManager, QuestFunctions questFunctions, AetheryteFunctions aetheryteFunctions, ExcelFunctions excelFunctions, QuestController questController, GatheringPointRegistry gatheringPointRegistry, QuestRegistry questRegistry, QuestData questData, TerritoryData territoryData, IGameGui gameGui, ITargetManager targetManager, IPluginLog pluginLog, IClientState clientState, IObjectTable objectTable, ShopController shopController, FateController fateController, SeasonalDutyController seasonalDutyController, BossModIpc bossModIpc, Configuration configuration, ILogger<InteractionUiController> logger)
|
||||||
{
|
{
|
||||||
_addonLifecycle = addonLifecycle;
|
_addonLifecycle = addonLifecycle;
|
||||||
_dataManager = dataManager;
|
_dataManager = dataManager;
|
||||||
|
|
@ -105,6 +107,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
_objectTable = objectTable;
|
_objectTable = objectTable;
|
||||||
_shopController = shopController;
|
_shopController = shopController;
|
||||||
_fateController = fateController;
|
_fateController = fateController;
|
||||||
|
_seasonalDutyController = seasonalDutyController;
|
||||||
_bossModIpc = bossModIpc;
|
_bossModIpc = bossModIpc;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
@ -118,6 +121,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "DifficultySelectYesNo", DifficultySelectYesNoPostSetup);
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "DifficultySelectYesNo", DifficultySelectYesNoPostSetup);
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "PointMenu", PointMenuPostSetup);
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "PointMenu", PointMenuPostSetup);
|
||||||
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
|
||||||
|
_addonLifecycle.RegisterListener(AddonEvent.PostSetup, "EasterMowingResult", EasterMowingResultPostSetup);
|
||||||
if (_gameGui.TryGetAddonByName<AtkUnitBase>("RhythmAction", out var addonPtr))
|
if (_gameGui.TryGetAddonByName<AtkUnitBase>("RhythmAction", out var addonPtr))
|
||||||
{
|
{
|
||||||
addonPtr->Close(fireCallback: true);
|
addonPtr->Close(fireCallback: true);
|
||||||
|
|
@ -369,9 +373,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<EAetheryteLocation> list2 = new List<EAetheryteLocation>(num);
|
List<EAetheryteLocation> list2 = new List<EAetheryteLocation>(num);
|
||||||
CollectionsMarshal.SetCount(list2, num);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<EAetheryteLocation> span = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = valueOrDefault;
|
||||||
int index = 0;
|
|
||||||
span[index] = valueOrDefault;
|
|
||||||
source = list2;
|
source = list2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -466,6 +468,15 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
list.AddRange(list4.Select((DialogueChoice x) => new DialogueChoiceInfo(null, x)));
|
list.AddRange(list4.Select((DialogueChoice x) => new DialogueChoiceInfo(null, x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_seasonalDutyController.IsRunning)
|
||||||
|
{
|
||||||
|
List<DialogueChoice> list5 = _seasonalDutyController.CurrentDuty?.DialogueChoices;
|
||||||
|
if (list5 != null && list5.Count > 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Adding {Count} dialogue choices from active seasonal duty", list5.Count);
|
||||||
|
list.AddRange(list5.Select((DialogueChoice x) => new DialogueChoiceInfo(null, x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (list.Count == 0)
|
if (list.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("No dialogue choices to check");
|
_logger.LogDebug("No dialogue choices to check");
|
||||||
|
|
@ -658,15 +669,15 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QuestController.QuestProgress nextQuest = _questController.NextQuest;
|
QuestController.QuestProgress nextQuest = _questController.NextQuest;
|
||||||
if ((nextQuest != null && CheckQuestYesNo(addonSelectYesno, nextQuest, text, checkAllSteps)) || !_fateController.IsRunning)
|
if (nextQuest != null && CheckQuestYesNo(addonSelectYesno, nextQuest, text, checkAllSteps))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (_fateController.IsRunning)
|
||||||
|
{
|
||||||
List<DialogueChoice> list = _fateController.CurrentFate?.TransformDialogueChoices;
|
List<DialogueChoice> list = _fateController.CurrentFate?.TransformDialogueChoices;
|
||||||
if (list == null)
|
if (list != null)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
foreach (DialogueChoice item in list)
|
foreach (DialogueChoice item in list)
|
||||||
{
|
{
|
||||||
if (item.Type == EDialogChoiceType.YesNo)
|
if (item.Type == EDialogChoiceType.YesNo)
|
||||||
|
|
@ -676,6 +687,30 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
{
|
{
|
||||||
_logger.LogInformation("FATE: Returning {YesNo} for '{Prompt}'", item.Yes ? "Yes" : "No", text);
|
_logger.LogInformation("FATE: Returning {YesNo} for '{Prompt}'", item.Yes ? "Yes" : "No", text);
|
||||||
addonSelectYesno->AtkUnitBase.FireCallbackInt((!item.Yes) ? 1 : 0);
|
addonSelectYesno->AtkUnitBase.FireCallbackInt((!item.Yes) ? 1 : 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_seasonalDutyController.IsRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<DialogueChoice> list2 = _seasonalDutyController.CurrentDuty?.DialogueChoices;
|
||||||
|
if (list2 == null || list2.Count <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (DialogueChoice item2 in list2)
|
||||||
|
{
|
||||||
|
if (item2.Type == EDialogChoiceType.YesNo)
|
||||||
|
{
|
||||||
|
StringOrRegex stringOrRegex2 = ResolveReference(null, item2.ExcelSheet, item2.Prompt, item2.PromptIsRegularExpression);
|
||||||
|
if (stringOrRegex2 != null && IsMatch(text, stringOrRegex2))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Seasonal duty: Returning {YesNo} for '{Prompt}'", item2.Yes ? "Yes" : "No", text);
|
||||||
|
addonSelectYesno->AtkUnitBase.FireCallbackInt((!item2.Yes) ? 1 : 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1017,6 +1052,35 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe void EasterMowingResultPostSetup(AddonEvent type, AddonArgs args)
|
||||||
|
{
|
||||||
|
if (_seasonalDutyController.IsRunning)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Dismissing EasterMowingResult");
|
||||||
|
AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address;
|
||||||
|
AtkValue* values = stackalloc AtkValue[3]
|
||||||
|
{
|
||||||
|
new AtkValue
|
||||||
|
{
|
||||||
|
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
|
||||||
|
Int = -1
|
||||||
|
},
|
||||||
|
new AtkValue
|
||||||
|
{
|
||||||
|
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
|
||||||
|
Int = 1
|
||||||
|
},
|
||||||
|
new AtkValue
|
||||||
|
{
|
||||||
|
Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int,
|
||||||
|
Int = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
address->FireCallback(3u, values);
|
||||||
|
address->Close(fireCallback: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private StringOrRegex? ResolveReference(Questionable.Model.Quest? quest, string? excelSheet, ExcelRef? excelRef, bool isRegExp)
|
private StringOrRegex? ResolveReference(Questionable.Model.Quest? quest, string? excelSheet, ExcelRef? excelRef, bool isRegExp)
|
||||||
{
|
{
|
||||||
if (excelRef == null)
|
if (excelRef == null)
|
||||||
|
|
@ -1040,6 +1104,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "EasterMowingResult", EasterMowingResultPostSetup);
|
||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "HousingSelectBlock", HousingSelectBlockPostSetup);
|
||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "PointMenu", PointMenuPostSetup);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "PointMenu", PointMenuPostSetup);
|
||||||
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "DifficultySelectYesNo", DifficultySelectYesNoPostSetup);
|
_addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "DifficultySelectYesNo", DifficultySelectYesNoPostSetup);
|
||||||
|
|
|
||||||
|
|
@ -54,68 +54,37 @@ internal sealed class MovementOverrideController
|
||||||
List<IBlacklistedLocation> list = new List<IBlacklistedLocation>(num);
|
List<IBlacklistedLocation> list = new List<IBlacklistedLocation>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<IBlacklistedLocation> span = CollectionsMarshal.AsSpan(list);
|
Span<IBlacklistedLocation> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = new BlacklistedArea(1191, new Vector3(-223.0412f, 31.937134f, -584.03906f), 5f, 7.75f);
|
||||||
span[num2] = new BlacklistedArea(1191, new Vector3(-223.0412f, 31.937134f, -584.03906f), 5f, 7.75f);
|
span[1] = new BlacklistedPoint(128, new Vector3(2f, 40.25f, 36.5f), new Vector3(0.25f, 40.25f, 36.5f));
|
||||||
num2++;
|
span[2] = new BlacklistedPoint(132, new Vector3(29f, -8f, 120.5f), new Vector3(28.265165f, -8.000001f, 120.149734f));
|
||||||
span[num2] = new BlacklistedPoint(128, new Vector3(2f, 40.25f, 36.5f), new Vector3(0.25f, 40.25f, 36.5f));
|
span[3] = new BlacklistedPoint(132, new Vector3(28.25f, -8f, 125f), new Vector3(27.372725f, -8.200001f, 125.55859f));
|
||||||
num2++;
|
span[4] = new BlacklistedPoint(132, new Vector3(32.25f, -8f, 126.5f), new Vector3(32.022232f, -8.200011f, 126.86095f));
|
||||||
span[num2] = new BlacklistedPoint(132, new Vector3(29f, -8f, 120.5f), new Vector3(28.265165f, -8.000001f, 120.149734f));
|
span[5] = new BlacklistedPoint(205, new Vector3(26.75f, 0.5f, 20.75f), new Vector3(27.179117f, 0.26728272f, 19.714373f));
|
||||||
num2++;
|
span[6] = new BlacklistedPoint(130, new Vector3(59.5f, 4.25f, -118f), new Vector3(60.551353f, 4f, -119.76446f));
|
||||||
span[num2] = new BlacklistedPoint(132, new Vector3(28.25f, -8f, 125f), new Vector3(27.372725f, -8.200001f, 125.55859f));
|
span[7] = new BlacklistedPoint(145, new Vector3(-139.75f, -32.25f, 75.25f), new Vector3(-139.57748f, -33.785175f, 77.87906f));
|
||||||
num2++;
|
span[8] = new BlacklistedPoint(146, new Vector3(-201.75f, 10.5f, -265.5f), new Vector3(-203.75235f, 10.130764f, -265.15314f));
|
||||||
span[num2] = new BlacklistedPoint(132, new Vector3(32.25f, -8f, 126.5f), new Vector3(32.022232f, -8.200011f, 126.86095f));
|
span[9] = new BlacklistedArea(135, new Vector3(156.11499f, 15.518433f, 673.21277f), 0.5f, 5f);
|
||||||
num2++;
|
span[10] = new BlacklistedPoint(139, new Vector3(366f, -2.5f, 95.5f), new Vector3(362.65973f, -3.4f, 96.6896f), 2f);
|
||||||
span[num2] = new BlacklistedPoint(205, new Vector3(26.75f, 0.5f, 20.75f), new Vector3(27.179117f, 0.26728272f, 19.714373f));
|
span[11] = new BlacklistedPoint(155, new Vector3(-478.75f, 149.25f, -305.75f), new Vector3(-476.1802f, 149.06573f, -304.7811f));
|
||||||
num2++;
|
span[12] = new BlacklistedPoint(351, new Vector3(3.25f, 0.75f, 8.5f), new Vector3(4f, 0f, 9.5f));
|
||||||
span[num2] = new BlacklistedPoint(130, new Vector3(59.5f, 4.25f, -118f), new Vector3(60.551353f, 4f, -119.76446f));
|
span[13] = new BlacklistedPoint(418, new Vector3(-136.75f, 2.75f, 9f), new Vector3(-138.66408f, 2.0333426f, 8.860787f), 1f);
|
||||||
num2++;
|
span[14] = new BlacklistedPoint(401, new Vector3(-14.75f, -136.75f, 515.75f), new Vector3(-17.631899f, -137.39148f, 512.6676f), 2f);
|
||||||
span[num2] = new BlacklistedPoint(145, new Vector3(-139.75f, -32.25f, 75.25f), new Vector3(-139.57748f, -33.785175f, 77.87906f));
|
span[15] = new BlacklistedPoint(397, new Vector3(-93.75f, 87.75f, -715.5f), new Vector3(-87.78183f, 87.188995f, -713.3343f), 2f);
|
||||||
num2++;
|
span[16] = new BlacklistedPoint(400, new Vector3(384f, -74f, 648.75f), new Vector3(386.0543f, -72.409454f, 652.0184f), 3f);
|
||||||
span[num2] = new BlacklistedPoint(146, new Vector3(-201.75f, 10.5f, -265.5f), new Vector3(-203.75235f, 10.130764f, -265.15314f));
|
span[17] = new BlacklistedPoint(399, new Vector3(-514.4851f, 149.63762f, -480.58087f), new Vector3(-528.78656f, 151.17374f, -473.07077f), 5f, RecalculateNavmesh: true);
|
||||||
num2++;
|
span[18] = new BlacklistedPoint(399, new Vector3(-534.5f, 153f, -476.75f), new Vector3(-528.78656f, 151.17374f, -473.07077f), 5f, RecalculateNavmesh: true);
|
||||||
span[num2] = new BlacklistedArea(135, new Vector3(156.11499f, 15.518433f, 673.21277f), 0.5f, 5f);
|
span[19] = new BlacklistedPoint(478, new Vector3(14.5f, 215.25f, -101.5f), new Vector3(18.133032f, 215.44998f, -107.83075f), 5f);
|
||||||
num2++;
|
span[20] = new BlacklistedPoint(478, new Vector3(11f, 215.5f, -104.5f), new Vector3(18.133032f, 215.44998f, -107.83075f), 5f);
|
||||||
span[num2] = new BlacklistedPoint(139, new Vector3(366f, -2.5f, 95.5f), new Vector3(362.65973f, -3.4f, 96.6896f), 2f);
|
span[21] = new BlacklistedPoint(1189, new Vector3(574f, -142.25f, 504.25f), new Vector3(574.44183f, -142.12766f, 507.60065f));
|
||||||
num2++;
|
span[22] = new BlacklistedPoint(814, new Vector3(-324f, 348.75f, -181.75f), new Vector3(-322.75076f, 347.0529f, -177.69328f), 3f);
|
||||||
span[num2] = new BlacklistedPoint(155, new Vector3(-478.75f, 149.25f, -305.75f), new Vector3(-476.1802f, 149.06573f, -304.7811f));
|
span[23] = new BlacklistedPoint(956, new Vector3(6.25f, -27.75f, -41.5f), new Vector3(5.0831127f, -28.213453f, -42.239136f));
|
||||||
num2++;
|
span[24] = new BlacklistedPoint(1189, new Vector3(-115.75f, -213.75f, 336.5f), new Vector3(-112.40265f, -215.01514f, 339.0067f), 2f);
|
||||||
span[num2] = new BlacklistedPoint(351, new Vector3(3.25f, 0.75f, 8.5f), new Vector3(4f, 0f, 9.5f));
|
span[25] = new BlacklistedPoint(1190, new Vector3(-292.29004f, 18.598045f, -133.83907f), new Vector3(-288.20895f, 18.652182f, -132.67445f), 4f);
|
||||||
num2++;
|
span[26] = new BlacklistedPoint(1191, new Vector3(-108f, 29.25f, -350.75f), new Vector3(-107.56289f, 29.008266f, -348.80087f));
|
||||||
span[num2] = new BlacklistedPoint(418, new Vector3(-136.75f, 2.75f, 9f), new Vector3(-138.66408f, 2.0333426f, 8.860787f), 1f);
|
span[27] = new BlacklistedPoint(1191, new Vector3(-105.75f, 29.75f, -351f), new Vector3(-105.335304f, 29.017048f, -348.85077f));
|
||||||
num2++;
|
span[28] = new BlacklistedPoint(1186, new Vector3(284.25f, 50.75f, 171.25f), new Vector3(284.25f, 50.75f, 166.25f));
|
||||||
span[num2] = new BlacklistedPoint(401, new Vector3(-14.75f, -136.75f, 515.75f), new Vector3(-17.631899f, -137.39148f, 512.6676f), 2f);
|
span[29] = new BlacklistedPoint(1186, new Vector3(283.75f, 50.75f, 167.25f), new Vector3(284.25f, 50.75f, 166.25f));
|
||||||
num2++;
|
span[30] = new BlacklistedPoint(1186, new Vector3(287.75f, 51.25f, 172f), new Vector3(288.875f, 50.75f, 166.25f));
|
||||||
span[num2] = new BlacklistedPoint(397, new Vector3(-93.75f, 87.75f, -715.5f), new Vector3(-87.78183f, 87.188995f, -713.3343f), 2f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(400, new Vector3(384f, -74f, 648.75f), new Vector3(386.0543f, -72.409454f, 652.0184f), 3f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(399, new Vector3(-514.4851f, 149.63762f, -480.58087f), new Vector3(-528.78656f, 151.17374f, -473.07077f), 5f, RecalculateNavmesh: true);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(399, new Vector3(-534.5f, 153f, -476.75f), new Vector3(-528.78656f, 151.17374f, -473.07077f), 5f, RecalculateNavmesh: true);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(478, new Vector3(14.5f, 215.25f, -101.5f), new Vector3(18.133032f, 215.44998f, -107.83075f), 5f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(478, new Vector3(11f, 215.5f, -104.5f), new Vector3(18.133032f, 215.44998f, -107.83075f), 5f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1189, new Vector3(574f, -142.25f, 504.25f), new Vector3(574.44183f, -142.12766f, 507.60065f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(814, new Vector3(-324f, 348.75f, -181.75f), new Vector3(-322.75076f, 347.0529f, -177.69328f), 3f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(956, new Vector3(6.25f, -27.75f, -41.5f), new Vector3(5.0831127f, -28.213453f, -42.239136f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1189, new Vector3(-115.75f, -213.75f, 336.5f), new Vector3(-112.40265f, -215.01514f, 339.0067f), 2f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1190, new Vector3(-292.29004f, 18.598045f, -133.83907f), new Vector3(-288.20895f, 18.652182f, -132.67445f), 4f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1191, new Vector3(-108f, 29.25f, -350.75f), new Vector3(-107.56289f, 29.008266f, -348.80087f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1191, new Vector3(-105.75f, 29.75f, -351f), new Vector3(-105.335304f, 29.017048f, -348.85077f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1186, new Vector3(284.25f, 50.75f, 171.25f), new Vector3(284.25f, 50.75f, 166.25f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1186, new Vector3(283.75f, 50.75f, 167.25f), new Vector3(284.25f, 50.75f, 166.25f));
|
|
||||||
num2++;
|
|
||||||
span[num2] = new BlacklistedPoint(1186, new Vector3(287.75f, 51.25f, 172f), new Vector3(288.875f, 50.75f, 166.25f));
|
|
||||||
BlacklistedLocations = list;
|
BlacklistedLocations = list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ internal static class Action
|
||||||
{
|
{
|
||||||
return Array.Empty<ITask>();
|
return Array.Empty<ITask>();
|
||||||
}
|
}
|
||||||
|
if (step.DataIds.Count > 0)
|
||||||
|
{
|
||||||
|
return Array.Empty<ITask>();
|
||||||
|
}
|
||||||
ArgumentNullException.ThrowIfNull(step.Action, "step.Action");
|
ArgumentNullException.ThrowIfNull(step.Action, "step.Action");
|
||||||
ITask task = OnObject(step.DataId, quest, step.Action.Value, step.CompletionQuestVariablesFlags);
|
ITask task = OnObject(step.DataId, quest, step.Action.Value, step.CompletionQuestVariablesFlags);
|
||||||
if (step.Action.Value.RequiresMount())
|
if (step.Action.Value.RequiresMount())
|
||||||
|
|
@ -86,6 +90,9 @@ internal static class Action
|
||||||
_continueAt = DateTime.Now.AddSeconds(0.5);
|
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
logger.LogInformation("Object {DataId} is untargetable, using action {Action} without target", base.Task.DataId, base.Task.Action);
|
||||||
|
_usedAction = gameFunctions.UseAction(base.Task.Action);
|
||||||
|
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
_usedAction = gameFunctions.UseAction(base.Task.Action);
|
_usedAction = gameFunctions.UseAction(base.Task.Action);
|
||||||
|
|
@ -104,11 +111,18 @@ internal static class Action
|
||||||
if (base.Task.DataId.HasValue)
|
if (base.Task.DataId.HasValue)
|
||||||
{
|
{
|
||||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.DataId.Value);
|
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.DataId.Value);
|
||||||
if (gameObject == null || !gameObject.IsTargetable)
|
if (gameObject == null)
|
||||||
{
|
{
|
||||||
return ETaskResult.StillRunning;
|
return ETaskResult.StillRunning;
|
||||||
}
|
}
|
||||||
|
if (gameObject.IsTargetable)
|
||||||
|
{
|
||||||
_usedAction = gameFunctions.UseAction(gameObject, base.Task.Action);
|
_usedAction = gameFunctions.UseAction(gameObject, base.Task.Action);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_usedAction = gameFunctions.UseAction(base.Task.Action);
|
||||||
|
}
|
||||||
_continueAt = DateTime.Now.AddSeconds(0.5);
|
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,347 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Questionable.Functions;
|
||||||
|
using Questionable.Model;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
|
||||||
|
namespace Questionable.Controller.Steps.Interactions;
|
||||||
|
|
||||||
|
internal static class ClearObjectsWithAction
|
||||||
|
{
|
||||||
|
internal sealed class Factory : ITaskFactory
|
||||||
|
{
|
||||||
|
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||||
|
{
|
||||||
|
if (step.InteractionType != EInteractionType.Action)
|
||||||
|
{
|
||||||
|
return Array.Empty<ITask>();
|
||||||
|
}
|
||||||
|
if (step.DataIds.Count == 0)
|
||||||
|
{
|
||||||
|
return Array.Empty<ITask>();
|
||||||
|
}
|
||||||
|
if (!step.Action.HasValue)
|
||||||
|
{
|
||||||
|
return Array.Empty<ITask>();
|
||||||
|
}
|
||||||
|
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new ClearTask(step.DataIds, step.Action.Value, step.TerritoryId, step.CalculateActualStopDistance(), step.WaypointPositions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed record ClearTask(List<uint> DataIds, EAction Action, ushort TerritoryId, float StopDistance, List<Vector3> WaypointPositions) : ITask
|
||||||
|
{
|
||||||
|
public bool ShouldRedoOnInterrupt()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"ClearObjects({Action}, {DataIds.Count} types)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ClearTaskExecutor(MovementController movementController, GameFunctions gameFunctions, IClientState clientState, IObjectTable objectTable, ILogger<ClearTaskExecutor> logger) : TaskExecutor<ClearTask>()
|
||||||
|
{
|
||||||
|
private enum State
|
||||||
|
{
|
||||||
|
FindingObject,
|
||||||
|
MovingToObject,
|
||||||
|
UsingAction,
|
||||||
|
WaitingAfterAction,
|
||||||
|
MovingToWaypoint,
|
||||||
|
WaitingForTransition
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float VisitedPositionRadius = 5f;
|
||||||
|
|
||||||
|
private State _state;
|
||||||
|
|
||||||
|
private DateTime _noObjectFoundSince = DateTime.MaxValue;
|
||||||
|
|
||||||
|
private DateTime _waitUntil = DateTime.MinValue;
|
||||||
|
|
||||||
|
private DateTime _waypointReachedAt = DateTime.MaxValue;
|
||||||
|
|
||||||
|
private Vector3 _lastPlayerPosition;
|
||||||
|
|
||||||
|
private readonly List<Vector3> _visitedPositions = new List<Vector3>();
|
||||||
|
|
||||||
|
private readonly List<int> _triedWaypointIndices = new List<int>();
|
||||||
|
|
||||||
|
protected override bool Start()
|
||||||
|
{
|
||||||
|
if (clientState.TerritoryType != base.Task.TerritoryId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return TryFindAndMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsVisitedPosition(Vector3 position)
|
||||||
|
{
|
||||||
|
foreach (Vector3 visitedPosition in _visitedPositions)
|
||||||
|
{
|
||||||
|
if (Vector3.Distance(visitedPosition, position) <= 5f)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IGameObject? FindNearestUnvisitedObject()
|
||||||
|
{
|
||||||
|
IGameObject gameObject = objectTable[0];
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
IGameObject result = null;
|
||||||
|
float num = float.MaxValue;
|
||||||
|
foreach (IGameObject item in objectTable)
|
||||||
|
{
|
||||||
|
ObjectKind objectKind = item.ObjectKind;
|
||||||
|
if ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool flag = false;
|
||||||
|
foreach (uint dataId in base.Task.DataIds)
|
||||||
|
{
|
||||||
|
if (item.BaseId == dataId)
|
||||||
|
{
|
||||||
|
flag = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag && !IsVisitedPosition(item.Position))
|
||||||
|
{
|
||||||
|
float num2 = Vector3.Distance(gameObject.Position, item.Position);
|
||||||
|
if (num2 < num)
|
||||||
|
{
|
||||||
|
result = item;
|
||||||
|
num = num2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AnyMatchingObjectsExist()
|
||||||
|
{
|
||||||
|
foreach (IGameObject item in objectTable)
|
||||||
|
{
|
||||||
|
ObjectKind objectKind = item.ObjectKind;
|
||||||
|
if ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (uint dataId in base.Task.DataIds)
|
||||||
|
{
|
||||||
|
if (item.BaseId == dataId)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryFindAndMove()
|
||||||
|
{
|
||||||
|
IGameObject gameObject = FindNearestUnvisitedObject();
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
_state = State.FindingObject;
|
||||||
|
if (_noObjectFoundSince == DateTime.MaxValue)
|
||||||
|
{
|
||||||
|
_noObjectFoundSince = DateTime.Now;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_noObjectFoundSince = DateTime.MaxValue;
|
||||||
|
Vector3 position = gameObject.Position;
|
||||||
|
logger.LogInformation("Moving to object {DataId} at {Position}", gameObject.BaseId, position);
|
||||||
|
movementController.NavigateTo(EMovementType.Quest, gameObject.BaseId, position, fly: false, sprint: true, base.Task.StopDistance);
|
||||||
|
_state = State.MovingToObject;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (Vector3 Position, int Index)? FindNextWaypoint()
|
||||||
|
{
|
||||||
|
IGameObject gameObject = objectTable[0];
|
||||||
|
if (gameObject == null || base.Task.WaypointPositions.Count == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
(Vector3, int)? result = null;
|
||||||
|
float num = float.MaxValue;
|
||||||
|
for (int i = 0; i < base.Task.WaypointPositions.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_triedWaypointIndices.Contains(i))
|
||||||
|
{
|
||||||
|
float num2 = Vector3.Distance(gameObject.Position, base.Task.WaypointPositions[i]);
|
||||||
|
if (num2 < num)
|
||||||
|
{
|
||||||
|
result = (base.Task.WaypointPositions[i], i);
|
||||||
|
num = num2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavigateToNextWaypoint()
|
||||||
|
{
|
||||||
|
(Vector3, int)? tuple = FindNextWaypoint();
|
||||||
|
if (!tuple.HasValue)
|
||||||
|
{
|
||||||
|
logger.LogInformation("All waypoints tried without transition, resetting");
|
||||||
|
_triedWaypointIndices.Clear();
|
||||||
|
tuple = FindNextWaypoint();
|
||||||
|
if (!tuple.HasValue)
|
||||||
|
{
|
||||||
|
logger.LogWarning("No waypoint positions configured, waiting for transition");
|
||||||
|
_state = State.WaitingForTransition;
|
||||||
|
_lastPlayerPosition = objectTable[0]?.Position ?? Vector3.Zero;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_triedWaypointIndices.Add(tuple.Value.Item2);
|
||||||
|
logger.LogInformation("Moving to waypoint {Index} at {Position}", tuple.Value.Item2, tuple.Value.Item1);
|
||||||
|
movementController.NavigateTo(EMovementType.Quest, null, tuple.Value.Item1, fly: false, sprint: true, 0f);
|
||||||
|
_state = State.MovingToWaypoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ETaskResult Update()
|
||||||
|
{
|
||||||
|
if (clientState.TerritoryType != base.Task.TerritoryId)
|
||||||
|
{
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case State.FindingObject:
|
||||||
|
if (_noObjectFoundSince != DateTime.MaxValue && DateTime.Now > _noObjectFoundSince.AddSeconds(3.0))
|
||||||
|
{
|
||||||
|
if (AnyMatchingObjectsExist())
|
||||||
|
{
|
||||||
|
logger.LogInformation("Matching objects still exist, clearing visited positions and retrying");
|
||||||
|
_visitedPositions.Clear();
|
||||||
|
_noObjectFoundSince = DateTime.MaxValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.LogInformation("No matching objects remain, moving to waypoint");
|
||||||
|
NavigateToNextWaypoint();
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
TryFindAndMove();
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
case State.MovingToObject:
|
||||||
|
{
|
||||||
|
if (movementController.IsPathfinding || movementController.IsPathRunning)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
DateTime movementStartedAt = movementController.MovementStartedAt;
|
||||||
|
if (movementStartedAt == DateTime.MaxValue || movementStartedAt.AddSeconds(2.0) >= DateTime.Now)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
IGameObject gameObject2 = FindNearestUnvisitedObject();
|
||||||
|
IGameObject gameObject3 = objectTable[0];
|
||||||
|
if (gameObject2 != null && gameObject3 != null && Vector3.Distance(gameObject3.Position, gameObject2.Position) <= 5f)
|
||||||
|
{
|
||||||
|
_visitedPositions.Add(gameObject2.Position);
|
||||||
|
_state = State.UsingAction;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.LogInformation("Target no longer valid at destination, finding next");
|
||||||
|
TryFindAndMove();
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
case State.UsingAction:
|
||||||
|
if (gameFunctions.UseAction(base.Task.Action))
|
||||||
|
{
|
||||||
|
logger.LogInformation("Used action {Action}", base.Task.Action);
|
||||||
|
_waitUntil = DateTime.Now.AddSeconds(1.0);
|
||||||
|
_state = State.WaitingAfterAction;
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
case State.WaitingAfterAction:
|
||||||
|
if (DateTime.Now < _waitUntil)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
TryFindAndMove();
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
case State.MovingToWaypoint:
|
||||||
|
{
|
||||||
|
if (movementController.IsPathfinding || movementController.IsPathRunning)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
DateTime movementStartedAt2 = movementController.MovementStartedAt;
|
||||||
|
if (movementStartedAt2 == DateTime.MaxValue || movementStartedAt2.AddSeconds(2.0) >= DateTime.Now)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
logger.LogInformation("Reached waypoint, waiting for zone transition");
|
||||||
|
_state = State.WaitingForTransition;
|
||||||
|
_lastPlayerPosition = objectTable[0]?.Position ?? Vector3.Zero;
|
||||||
|
_waypointReachedAt = DateTime.Now;
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
case State.WaitingForTransition:
|
||||||
|
{
|
||||||
|
IGameObject gameObject = objectTable[0];
|
||||||
|
if (gameObject != null)
|
||||||
|
{
|
||||||
|
float num = Vector3.Distance(_lastPlayerPosition, gameObject.Position);
|
||||||
|
if (num > 50f)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Zone transition detected (moved {Distance}), resuming plant clearing", num);
|
||||||
|
_visitedPositions.Clear();
|
||||||
|
_triedWaypointIndices.Clear();
|
||||||
|
_noObjectFoundSince = DateTime.MaxValue;
|
||||||
|
_state = State.FindingObject;
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FindNearestUnvisitedObject() != null)
|
||||||
|
{
|
||||||
|
logger.LogInformation("New objects detected, resuming plant clearing");
|
||||||
|
_visitedPositions.Clear();
|
||||||
|
_triedWaypointIndices.Clear();
|
||||||
|
_noObjectFoundSince = DateTime.MaxValue;
|
||||||
|
TryFindAndMove();
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
if (_waypointReachedAt != DateTime.MaxValue && DateTime.Now > _waypointReachedAt.AddSeconds(3.0))
|
||||||
|
{
|
||||||
|
logger.LogInformation("No transition at this waypoint, trying next");
|
||||||
|
NavigateToNextWaypoint();
|
||||||
|
}
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldInterruptOnDamage()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -130,10 +130,8 @@ internal static class Dive
|
||||||
List<List<nint>> list = new List<List<nint>>(num);
|
List<List<nint>> list = new List<List<nint>>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<List<nint>> span = CollectionsMarshal.AsSpan(list);
|
Span<List<nint>> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = GetKeysToPress(key, keyModifier);
|
||||||
span[num2] = GetKeysToPress(key, keyModifier);
|
span[1] = GetKeysToPress(key2, keyModifier2);
|
||||||
num2++;
|
|
||||||
span[num2] = GetKeysToPress(key2, keyModifier2);
|
|
||||||
List<nint> list2 = (from x in list
|
List<nint> list2 = (from x in list
|
||||||
where x != null
|
where x != null
|
||||||
select (x)).MinBy((List<nint> x) => x.Count);
|
select (x)).MinBy((List<nint> x) => x.Count);
|
||||||
|
|
@ -144,12 +142,12 @@ internal static class Dive
|
||||||
foreach (nint item in list2)
|
foreach (nint item in list2)
|
||||||
{
|
{
|
||||||
_keysToPress.Enqueue((256u, item));
|
_keysToPress.Enqueue((256u, item));
|
||||||
for (int num3 = 0; num3 < 15; num3++)
|
for (int num2 = 0; num2 < 15; num2++)
|
||||||
{
|
{
|
||||||
_keysToPress.Enqueue((0u, 0));
|
_keysToPress.Enqueue((0u, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int num4 = 0; num4 < 5; num4++)
|
for (int num3 = 0; num3 < 5; num3++)
|
||||||
{
|
{
|
||||||
_keysToPress.Enqueue((0u, 0));
|
_keysToPress.Enqueue((0u, 0));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,12 +175,10 @@ internal static class EquipItem
|
||||||
case 10u:
|
case 10u:
|
||||||
case 11u:
|
case 11u:
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ushort> list4 = new List<ushort>(index);
|
List<ushort> list4 = new List<ushort>(num);
|
||||||
CollectionsMarshal.SetCount(list4, index);
|
CollectionsMarshal.SetCount(list4, num);
|
||||||
Span<ushort> span4 = CollectionsMarshal.AsSpan(list4);
|
CollectionsMarshal.AsSpan(list4)[0] = (ushort)(item.Value.EquipSlotCategory.RowId - 1);
|
||||||
int num = 0;
|
|
||||||
span4[num] = (ushort)(item.Value.EquipSlotCategory.RowId - 1);
|
|
||||||
return list4;
|
return list4;
|
||||||
}
|
}
|
||||||
case 12u:
|
case 12u:
|
||||||
|
|
@ -188,21 +186,17 @@ internal static class EquipItem
|
||||||
int num = 2;
|
int num = 2;
|
||||||
List<ushort> list3 = new List<ushort>(num);
|
List<ushort> list3 = new List<ushort>(num);
|
||||||
CollectionsMarshal.SetCount(list3, num);
|
CollectionsMarshal.SetCount(list3, num);
|
||||||
Span<ushort> span3 = CollectionsMarshal.AsSpan(list3);
|
Span<ushort> span = CollectionsMarshal.AsSpan(list3);
|
||||||
int index = 0;
|
span[0] = 11;
|
||||||
span3[index] = 11;
|
span[1] = 12;
|
||||||
index++;
|
|
||||||
span3[index] = 12;
|
|
||||||
return list3;
|
return list3;
|
||||||
}
|
}
|
||||||
case 13u:
|
case 13u:
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ushort> list2 = new List<ushort>(index);
|
List<ushort> list2 = new List<ushort>(num);
|
||||||
CollectionsMarshal.SetCount(list2, index);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<ushort> span2 = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = 0;
|
||||||
int num = 0;
|
|
||||||
span2[num] = 0;
|
|
||||||
return list2;
|
return list2;
|
||||||
}
|
}
|
||||||
case 17u:
|
case 17u:
|
||||||
|
|
@ -210,9 +204,7 @@ internal static class EquipItem
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ushort> list = new List<ushort>(num);
|
List<ushort> list = new List<ushort>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<ushort> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = 13;
|
||||||
int index = 0;
|
|
||||||
span[index] = 13;
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,8 @@ internal static class FateFarming
|
||||||
|
|
||||||
private ushort _trackedFateId;
|
private ushort _trackedFateId;
|
||||||
|
|
||||||
|
private bool _fateWasActive;
|
||||||
|
|
||||||
protected override bool Start()
|
protected override bool Start()
|
||||||
{
|
{
|
||||||
_trackedFateId = gameFunctions.GetCurrentFateId();
|
_trackedFateId = gameFunctions.GetCurrentFateId();
|
||||||
|
|
@ -138,6 +140,13 @@ internal static class FateFarming
|
||||||
logger.LogInformation("Required status {StatusId} lost during FATE action loop, ending cycle to re-apply", base.Task.RequiredStatusId.Value);
|
logger.LogInformation("Required status {StatusId} lost during FATE action loop, ending cycle to re-apply", base.Task.RequiredStatusId.Value);
|
||||||
return ETaskResult.TaskComplete;
|
return ETaskResult.TaskComplete;
|
||||||
}
|
}
|
||||||
|
bool flag = gameFunctions.GetCurrentFateId() != 0;
|
||||||
|
if (_fateWasActive && !flag)
|
||||||
|
{
|
||||||
|
logger.LogInformation("FATE {FateId} is no longer active, cycle complete", _trackedFateId);
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
_fateWasActive = flag;
|
||||||
if (_trackedFateId == 0)
|
if (_trackedFateId == 0)
|
||||||
{
|
{
|
||||||
_trackedFateId = gameFunctions.GetCurrentFateId();
|
_trackedFateId = gameFunctions.GetCurrentFateId();
|
||||||
|
|
@ -156,8 +165,8 @@ internal static class FateFarming
|
||||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId, null, warnIfMissing: false);
|
IGameObject gameObject = gameFunctions.FindObjectByDataId(target.DataId, null, warnIfMissing: false);
|
||||||
if (gameObject != null && gameObject.IsTargetable)
|
if (gameObject != null && gameObject.IsTargetable)
|
||||||
{
|
{
|
||||||
bool flag = gameFunctions.UseAction(gameObject, target.Action);
|
bool flag2 = gameFunctions.UseAction(gameObject, target.Action);
|
||||||
_nextActionAt = (flag ? DateTime.Now.AddSeconds(2.5) : DateTime.Now.AddSeconds(0.5));
|
_nextActionAt = (flag2 ? DateTime.Now.AddSeconds(2.5) : DateTime.Now.AddSeconds(0.5));
|
||||||
return ETaskResult.StillRunning;
|
return ETaskResult.StillRunning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,9 +67,7 @@ internal static class Jump
|
||||||
int num2 = 1;
|
int num2 = 1;
|
||||||
List<Vector3> list = new List<Vector3>(num2);
|
List<Vector3> list = new List<Vector3>(num2);
|
||||||
CollectionsMarshal.SetCount(list, num2);
|
CollectionsMarshal.SetCount(list, num2);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = base.Task.JumpDestination.Position;
|
||||||
int index = 0;
|
|
||||||
span[index] = base.Task.JumpDestination.Position;
|
|
||||||
movementController.NavigateTo(EMovementType.Quest, dataId, list, fly: false, sprint: false, base.Task.JumpDestination.StopDistance ?? num);
|
movementController.NavigateTo(EMovementType.Quest, dataId, list, fly: false, sprint: false, base.Task.JumpDestination.StopDistance ?? num);
|
||||||
_003Cframework_003EP.RunOnTick(delegate
|
_003Cframework_003EP.RunOnTick(delegate
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,7 @@ internal sealed class MoveExecutor : TaskExecutor<MoveTask>, IToastAware, ITaskE
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<Vector3> list = new List<Vector3>(num);
|
List<Vector3> list = new List<Vector3>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = _destination;
|
||||||
int index = 0;
|
|
||||||
span[index] = _destination;
|
|
||||||
movementController.NavigateTo(EMovementType.Quest, dataId, list, base.Task.Fly, base.Task.Sprint ?? (!_mountDuringMovement.HasValue), base.Task.StopDistance, base.Task.IgnoreDistanceToObject ? new float?(float.MaxValue) : ((float?)null), base.Task.Land);
|
movementController.NavigateTo(EMovementType.Quest, dataId, list, base.Task.Fly, base.Task.Sprint ?? (!_mountDuringMovement.HasValue), base.Task.StopDistance, base.Task.IgnoreDistanceToObject ? new float?(float.MaxValue) : ((float?)null), base.Task.Land);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ internal static class MoveTo
|
||||||
{
|
{
|
||||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||||
{
|
{
|
||||||
|
if (step.DataIds.Count > 0)
|
||||||
|
{
|
||||||
|
return Array.Empty<ITask>();
|
||||||
|
}
|
||||||
if (step.Position.HasValue)
|
if (step.Position.HasValue)
|
||||||
{
|
{
|
||||||
return CreateMoveTasks(step, step.Position.Value);
|
return CreateMoveTasks(step, step.Position.Value);
|
||||||
|
|
@ -26,6 +30,10 @@ internal static class MoveTo
|
||||||
{
|
{
|
||||||
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new WaitForNearDataId(step.DataId.Value, step.StopDistance.Value));
|
return new global::_003C_003Ez__ReadOnlySingleElementList<ITask>(new WaitForNearDataId(step.DataId.Value, step.StopDistance.Value));
|
||||||
}
|
}
|
||||||
|
if (step != null && step.DataId.HasValue && !step.Position.HasValue)
|
||||||
|
{
|
||||||
|
return CreateMoveToObjectTasks(step);
|
||||||
|
}
|
||||||
EAetheryteLocation valueOrDefault = default(EAetheryteLocation);
|
EAetheryteLocation valueOrDefault = default(EAetheryteLocation);
|
||||||
bool flag;
|
bool flag;
|
||||||
if (step != null)
|
if (step != null)
|
||||||
|
|
@ -38,13 +46,13 @@ internal static class MoveTo
|
||||||
{
|
{
|
||||||
valueOrDefault = aetheryte.GetValueOrDefault();
|
valueOrDefault = aetheryte.GetValueOrDefault();
|
||||||
flag = true;
|
flag = true;
|
||||||
goto IL_00a3;
|
goto IL_00e2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flag = false;
|
flag = false;
|
||||||
goto IL_00a3;
|
goto IL_00e2;
|
||||||
IL_00a3:
|
IL_00e2:
|
||||||
if (flag)
|
if (flag)
|
||||||
{
|
{
|
||||||
return CreateMoveTasks(step, aetheryteData.Locations[valueOrDefault]);
|
return CreateMoveTasks(step, aetheryteData.Locations[valueOrDefault]);
|
||||||
|
|
@ -61,6 +69,16 @@ internal static class MoveTo
|
||||||
return Array.Empty<ITask>();
|
return Array.Empty<ITask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<ITask> CreateMoveToObjectTasks(QuestStep step)
|
||||||
|
{
|
||||||
|
yield return new WaitCondition.Task(() => clientState.TerritoryType == step.TerritoryId, "Wait(territory: " + territoryData.GetNameAndId(step.TerritoryId) + ")");
|
||||||
|
if (!step.DisableNavmesh)
|
||||||
|
{
|
||||||
|
yield return new WaitNavmesh.Task();
|
||||||
|
}
|
||||||
|
yield return new MoveToObject(step);
|
||||||
|
}
|
||||||
|
|
||||||
private IEnumerable<ITask> CreateMoveTasks(QuestStep step, Vector3 destination)
|
private IEnumerable<ITask> CreateMoveTasks(QuestStep step, Vector3 destination)
|
||||||
{
|
{
|
||||||
IGameObject gameObject = objectTable[0];
|
IGameObject gameObject = objectTable[0];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
|
||||||
|
namespace Questionable.Controller.Steps.Movement;
|
||||||
|
|
||||||
|
internal sealed record MoveToObject(QuestStep Step) : ITask
|
||||||
|
{
|
||||||
|
public bool ShouldRedoOnInterrupt()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"MoveToObject({Step.DataId})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Questionable.Functions;
|
||||||
|
using Questionable.Model;
|
||||||
|
|
||||||
|
namespace Questionable.Controller.Steps.Movement;
|
||||||
|
|
||||||
|
internal sealed class MoveToObjectExecutor(MovementController movementController, GameFunctions gameFunctions, IClientState clientState, IObjectTable objectTable, ILogger<MoveToObjectExecutor> logger) : TaskExecutor<MoveToObject>()
|
||||||
|
{
|
||||||
|
private DateTime _startedLookingAt = DateTime.MaxValue;
|
||||||
|
|
||||||
|
private Vector3 _destination;
|
||||||
|
|
||||||
|
private bool _moving;
|
||||||
|
|
||||||
|
protected override bool Start()
|
||||||
|
{
|
||||||
|
if (!base.Task.Step.DataId.HasValue)
|
||||||
|
{
|
||||||
|
logger.LogWarning("MoveToObject task has no DataId");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (clientState.TerritoryType != base.Task.Step.TerritoryId)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Not in correct territory yet, waiting");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_startedLookingAt = DateTime.Now;
|
||||||
|
return TryStartMovement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IGameObject? FindDistantObjectByDataId(uint dataId)
|
||||||
|
{
|
||||||
|
IGameObject gameObject = objectTable[0];
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
float num = base.Task.Step.CalculateActualStopDistance();
|
||||||
|
IGameObject result = null;
|
||||||
|
float num2 = float.MaxValue;
|
||||||
|
foreach (IGameObject item in objectTable)
|
||||||
|
{
|
||||||
|
ObjectKind objectKind = item.ObjectKind;
|
||||||
|
bool flag = ((objectKind == ObjectKind.Player || objectKind - 8 <= ObjectKind.BattleNpc || objectKind == ObjectKind.Housing) ? true : false);
|
||||||
|
if (!flag && item.BaseId == dataId)
|
||||||
|
{
|
||||||
|
float num3 = Vector3.Distance(gameObject.Position, item.Position);
|
||||||
|
if (!(num3 <= num) && num3 < num2)
|
||||||
|
{
|
||||||
|
result = item;
|
||||||
|
num2 = num3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryStartMovement()
|
||||||
|
{
|
||||||
|
IGameObject gameObject = FindDistantObjectByDataId(base.Task.Step.DataId.Value);
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
gameObject = gameFunctions.FindObjectByDataId(base.Task.Step.DataId.Value, null, warnIfMissing: false);
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Object {DataId} not found yet, waiting", base.Task.Step.DataId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
IGameObject gameObject2 = objectTable[0];
|
||||||
|
float num = base.Task.Step.CalculateActualStopDistance();
|
||||||
|
if (gameObject2 != null && Vector3.Distance(gameObject2.Position, gameObject.Position) <= num)
|
||||||
|
{
|
||||||
|
logger.LogInformation("Only nearby objects with DataId {DataId} remain, skipping", base.Task.Step.DataId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_destination = gameObject.Position;
|
||||||
|
logger.LogInformation("Moving to object {DataId} at {Position}", base.Task.Step.DataId, _destination);
|
||||||
|
movementController.NavigateTo(EMovementType.Quest, base.Task.Step.DataId, _destination, fly: false, base.Task.Step.Sprint ?? true, base.Task.Step.CalculateActualStopDistance());
|
||||||
|
_moving = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ETaskResult Update()
|
||||||
|
{
|
||||||
|
if (clientState.TerritoryType != base.Task.Step.TerritoryId)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
if (!_moving)
|
||||||
|
{
|
||||||
|
if (_startedLookingAt != DateTime.MaxValue && DateTime.Now > _startedLookingAt.AddSeconds(3.0))
|
||||||
|
{
|
||||||
|
logger.LogInformation("Object {DataId} not found after timeout, skipping step", base.Task.Step.DataId);
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
if (!TryStartMovement())
|
||||||
|
{
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
if (!_moving)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (movementController.IsPathfinding || movementController.IsPathRunning)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
DateTime movementStartedAt = movementController.MovementStartedAt;
|
||||||
|
if (movementStartedAt == DateTime.MaxValue || movementStartedAt.AddSeconds(2.0) >= DateTime.Now)
|
||||||
|
{
|
||||||
|
return ETaskResult.StillRunning;
|
||||||
|
}
|
||||||
|
return ETaskResult.TaskComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldInterruptOnDamage()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -119,14 +119,10 @@ internal static class AethernetShortcut
|
||||||
List<Vector3> list = new List<Vector3>(num);
|
List<Vector3> list = new List<Vector3>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = new Vector3(0f, 8.442986f, 9f);
|
||||||
span[num2] = new Vector3(0f, 8.442986f, 9f);
|
span[1] = new Vector3(9f, 8.442986f, 0f);
|
||||||
num2++;
|
span[2] = new Vector3(-9f, 8.442986f, 0f);
|
||||||
span[num2] = new Vector3(9f, 8.442986f, 0f);
|
span[3] = new Vector3(0f, 8.442986f, -9f);
|
||||||
num2++;
|
|
||||||
span[num2] = new Vector3(-9f, 8.442986f, 0f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new Vector3(0f, 8.442986f, -9f);
|
|
||||||
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
|
Vector3 to = list.MinBy((Vector3 x) => Vector3.Distance(playerPosition, x));
|
||||||
_moving = true;
|
_moving = true;
|
||||||
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
|
movementController.NavigateTo(EMovementType.Quest, (uint)base.Task.From, to, fly: false, sprint: true, 0.25f);
|
||||||
|
|
|
||||||
|
|
@ -257,14 +257,10 @@ internal static class AetheryteShortcut
|
||||||
List<Vector3> list = new List<Vector3>(num);
|
List<Vector3> list = new List<Vector3>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = new Vector3(0f, 8.8f, 15.5f);
|
||||||
span[num2] = new Vector3(0f, 8.8f, 15.5f);
|
span[1] = new Vector3(0f, 8.8f, -15.5f);
|
||||||
num2++;
|
span[2] = new Vector3(15.5f, 8.8f, 0f);
|
||||||
span[num2] = new Vector3(0f, 8.8f, -15.5f);
|
span[3] = new Vector3(-15.5f, 8.8f, 0f);
|
||||||
num2++;
|
|
||||||
span[num2] = new Vector3(15.5f, 8.8f, 0f);
|
|
||||||
num2++;
|
|
||||||
span[num2] = new Vector3(-15.5f, 8.8f, 0f);
|
|
||||||
dictionary.Add(EAetheryteLocation.SolutionNine, list);
|
dictionary.Add(EAetheryteLocation.SolutionNine, list);
|
||||||
AetherytesToMoveFrom = dictionary;
|
AetherytesToMoveFrom = dictionary;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,15 @@ internal sealed class TaskCreator
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ITask> list = new List<ITask>(num);
|
List<ITask> list = new List<ITask>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<ITask> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = new WaitAtEnd.WaitNextStepOrSequence();
|
||||||
int index = 0;
|
|
||||||
span[index] = new WaitAtEnd.WaitNextStepOrSequence();
|
|
||||||
list2 = list;
|
list2 = list;
|
||||||
}
|
}
|
||||||
else if (step == null)
|
else if (step == null)
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ITask> list3 = new List<ITask>(index);
|
List<ITask> list3 = new List<ITask>(num);
|
||||||
CollectionsMarshal.SetCount(list3, index);
|
CollectionsMarshal.SetCount(list3, num);
|
||||||
Span<ITask> span2 = CollectionsMarshal.AsSpan(list3);
|
CollectionsMarshal.AsSpan(list3)[0] = new WaitAtEnd.WaitNextStepOrSequence();
|
||||||
int num = 0;
|
|
||||||
span2[num] = new WaitAtEnd.WaitNextStepOrSequence();
|
|
||||||
list2 = list3;
|
list2 = list3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -515,9 +515,7 @@ internal sealed class CombatController : IDisposable
|
||||||
int num4 = 1;
|
int num4 = 1;
|
||||||
List<Vector3> list = new List<Vector3>(num4);
|
List<Vector3> list = new List<Vector3>(num4);
|
||||||
CollectionsMarshal.SetCount(list, num4);
|
CollectionsMarshal.SetCount(list, num4);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = gameObject.Position;
|
||||||
int index = 0;
|
|
||||||
span[index] = gameObject.Position;
|
|
||||||
movementController.NavigateTo(EMovementType.Combat, null, list, fly: false, sprint: false, num3 + num - 0.25f, float.MaxValue);
|
movementController.NavigateTo(EMovementType.Combat, null, list, fly: false, sprint: false, num3 + num - 0.25f, float.MaxValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Questionable.Functions;
|
using Questionable.Functions;
|
||||||
|
|
@ -36,8 +37,12 @@ internal sealed class CommandHandler : IDisposable
|
||||||
|
|
||||||
private readonly FateController _fateController;
|
private readonly FateController _fateController;
|
||||||
|
|
||||||
|
private readonly SeasonalDutyController _seasonalDutyController;
|
||||||
|
|
||||||
private readonly FateSelectionWindow _fateSelectionWindow;
|
private readonly FateSelectionWindow _fateSelectionWindow;
|
||||||
|
|
||||||
|
private readonly SeasonalDutySelectionWindow _seasonalDutySelectionWindow;
|
||||||
|
|
||||||
private readonly ITargetManager _targetManager;
|
private readonly ITargetManager _targetManager;
|
||||||
|
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
|
|
@ -46,13 +51,14 @@ internal sealed class CommandHandler : IDisposable
|
||||||
|
|
||||||
private readonly ChangelogWindow _changelogWindow;
|
private readonly ChangelogWindow _changelogWindow;
|
||||||
|
|
||||||
public CommandHandler(ICommandManager commandManager, IChatGui chatGui, QuestController questController, MovementController movementController, FateController fateController, QuestRegistry questRegistry, ConfigWindow configWindow, DebugOverlay debugOverlay, OneTimeSetupWindow oneTimeSetupWindow, QuestWindow questWindow, QuestSelectionWindow questSelectionWindow, QuestSequenceWindow questSequenceWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, FateSelectionWindow fateSelectionWindow, ITargetManager targetManager, QuestFunctions questFunctions, GameFunctions gameFunctions, AetheryteFunctions aetheryteFunctions, IDataManager dataManager, IClientState clientState, IObjectTable objectTable, Configuration configuration, ChangelogWindow changelogWindow)
|
public CommandHandler(ICommandManager commandManager, IChatGui chatGui, QuestController questController, MovementController movementController, FateController fateController, SeasonalDutyController seasonalDutyController, QuestRegistry questRegistry, ConfigWindow configWindow, DebugOverlay debugOverlay, OneTimeSetupWindow oneTimeSetupWindow, QuestWindow questWindow, QuestSelectionWindow questSelectionWindow, QuestSequenceWindow questSequenceWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, FateSelectionWindow fateSelectionWindow, SeasonalDutySelectionWindow seasonalDutySelectionWindow, ITargetManager targetManager, QuestFunctions questFunctions, GameFunctions gameFunctions, AetheryteFunctions aetheryteFunctions, IDataManager dataManager, IClientState clientState, IObjectTable objectTable, Configuration configuration, ChangelogWindow changelogWindow)
|
||||||
{
|
{
|
||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
_chatGui = chatGui;
|
_chatGui = chatGui;
|
||||||
_questController = questController;
|
_questController = questController;
|
||||||
_movementController = movementController;
|
_movementController = movementController;
|
||||||
_fateController = fateController;
|
_fateController = fateController;
|
||||||
|
_seasonalDutyController = seasonalDutyController;
|
||||||
_configWindow = configWindow;
|
_configWindow = configWindow;
|
||||||
_oneTimeSetupWindow = oneTimeSetupWindow;
|
_oneTimeSetupWindow = oneTimeSetupWindow;
|
||||||
_questWindow = questWindow;
|
_questWindow = questWindow;
|
||||||
|
|
@ -61,6 +67,7 @@ internal sealed class CommandHandler : IDisposable
|
||||||
_journalProgressWindow = journalProgressWindow;
|
_journalProgressWindow = journalProgressWindow;
|
||||||
_priorityWindow = priorityWindow;
|
_priorityWindow = priorityWindow;
|
||||||
_fateSelectionWindow = fateSelectionWindow;
|
_fateSelectionWindow = fateSelectionWindow;
|
||||||
|
_seasonalDutySelectionWindow = seasonalDutySelectionWindow;
|
||||||
_targetManager = targetManager;
|
_targetManager = targetManager;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
|
|
@ -69,15 +76,15 @@ internal sealed class CommandHandler : IDisposable
|
||||||
ICommandManager commandManager2 = _commandManager;
|
ICommandManager commandManager2 = _commandManager;
|
||||||
CommandInfo commandInfo = new CommandInfo(ProcessCommand);
|
CommandInfo commandInfo = new CommandInfo(ProcessCommand);
|
||||||
string separator = Environment.NewLine + "\t";
|
string separator = Environment.NewLine + "\t";
|
||||||
_003C_003Ey__InlineArray7<string> buffer = default(_003C_003Ey__InlineArray7<string>);
|
InlineArray7<string> buffer = default(InlineArray7<string>);
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 0) = "Opens the Questing window";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 0) = "Opens the Questing window";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 1) = "/qst help - displays simplified commands";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 1) = "/qst help - displays simplified commands";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 2) = "/qst help-all - displays all available commands";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 2) = "/qst help-all - displays all available commands";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 3) = "/qst config - opens the configuration window";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 3) = "/qst config - opens the configuration window";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 4) = "/qst changelog - opens the changelog window";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 4) = "/qst changelog - opens the changelog window";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 5) = "/qst start - starts doing quests";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 5) = "/qst start - starts doing quests";
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<_003C_003Ey__InlineArray7<string>, string>(ref buffer, 6) = "/qst stop - stops doing quests";
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray7<string>, string>(ref buffer, 6) = "/qst stop - stops doing quests";
|
||||||
commandInfo.HelpMessage = string.Join(separator, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<_003C_003Ey__InlineArray7<string>, string>(in buffer, 7));
|
commandInfo.HelpMessage = string.Join(separator, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<InlineArray7<string>, string>(in buffer, 7));
|
||||||
commandManager2.AddHandler("/qst", commandInfo);
|
commandManager2.AddHandler("/qst", commandInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,7 +106,7 @@ internal sealed class CommandHandler : IDisposable
|
||||||
_chatGui.Print("/qst start - starts doing quests", "Questionable", 576);
|
_chatGui.Print("/qst start - starts doing quests", "Questionable", 576);
|
||||||
_chatGui.Print("/qst stop - stops doing quests", "Questionable", 576);
|
_chatGui.Print("/qst stop - stops doing quests", "Questionable", 576);
|
||||||
_chatGui.Print("/qst reload - reload all quest data", "Questionable", 576);
|
_chatGui.Print("/qst reload - reload all quest data", "Questionable", 576);
|
||||||
_chatGui.Print("/qst fate - toggles the FATE farming window", "Questionable", 576);
|
_chatGui.Print("/qst fate / duty - toggles the farming window", "Questionable", 576);
|
||||||
break;
|
break;
|
||||||
case "ha":
|
case "ha":
|
||||||
case "help-all":
|
case "help-all":
|
||||||
|
|
@ -116,7 +123,7 @@ internal sealed class CommandHandler : IDisposable
|
||||||
_chatGui.Print("/qst zone - shows all quests starting in the current zone (only includes quests with a known quest path, and currently visible unaccepted quests)", "Questionable", 576);
|
_chatGui.Print("/qst zone - shows all quests starting in the current zone (only includes quests with a known quest path, and currently visible unaccepted quests)", "Questionable", 576);
|
||||||
_chatGui.Print("/qst journal - toggles the Journal Progress window", "Questionable", 576);
|
_chatGui.Print("/qst journal - toggles the Journal Progress window", "Questionable", 576);
|
||||||
_chatGui.Print("/qst priority - toggles the Priority window", "Questionable", 576);
|
_chatGui.Print("/qst priority - toggles the Priority window", "Questionable", 576);
|
||||||
_chatGui.Print("/qst fate - toggles the FATE farming window", "Questionable", 576);
|
_chatGui.Print("/qst fate / duty - toggles the farming window", "Questionable", 576);
|
||||||
_chatGui.Print("/qst handle-interrupt - makes Questionable handle queued interrupts immediately (useful if you manually start combat)", "Questionable", 576);
|
_chatGui.Print("/qst handle-interrupt - makes Questionable handle queued interrupts immediately (useful if you manually start combat)", "Questionable", 576);
|
||||||
break;
|
break;
|
||||||
case "c":
|
case "c":
|
||||||
|
|
@ -135,6 +142,7 @@ internal sealed class CommandHandler : IDisposable
|
||||||
_movementController.Stop();
|
_movementController.Stop();
|
||||||
_questController.Stop("Stop command");
|
_questController.Stop("Stop command");
|
||||||
_fateController.Stop("Stop command");
|
_fateController.Stop("Stop command");
|
||||||
|
_seasonalDutyController.Stop("Stop command");
|
||||||
break;
|
break;
|
||||||
case "reload":
|
case "reload":
|
||||||
_questWindow.Reload();
|
_questWindow.Reload();
|
||||||
|
|
@ -158,6 +166,10 @@ internal sealed class CommandHandler : IDisposable
|
||||||
case "fate":
|
case "fate":
|
||||||
_fateSelectionWindow.ToggleOrUncollapse();
|
_fateSelectionWindow.ToggleOrUncollapse();
|
||||||
break;
|
break;
|
||||||
|
case "d":
|
||||||
|
case "duty":
|
||||||
|
_seasonalDutySelectionWindow.ToggleOrUncollapse();
|
||||||
|
break;
|
||||||
case "handle-interrupt":
|
case "handle-interrupt":
|
||||||
_questController.InterruptQueueWithCombat();
|
_questController.InterruptQueueWithCombat();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -200,9 +200,7 @@ internal sealed class ContextMenuController : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<GatheredItem> list = new List<GatheredItem>(num);
|
List<GatheredItem> list = new List<GatheredItem>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<GatheredItem> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = new GatheredItem
|
||||||
int index = 0;
|
|
||||||
span[index] = new GatheredItem
|
|
||||||
{
|
{
|
||||||
ItemId = itemId,
|
ItemId = itemId,
|
||||||
ItemCount = quantity,
|
ItemCount = quantity,
|
||||||
|
|
|
||||||
|
|
@ -179,9 +179,7 @@ internal abstract class MiniTaskController<T> : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ITask> list2 = new List<ITask>(num);
|
List<ITask> list2 = new List<ITask>(num);
|
||||||
CollectionsMarshal.SetCount(list2, num);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<ITask> span = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = new WaitAtEnd.WaitDelay();
|
||||||
int index = 0;
|
|
||||||
span[index] = new WaitAtEnd.WaitDelay();
|
|
||||||
taskQueue.InterruptWith(list2);
|
taskQueue.InterruptWith(list2);
|
||||||
}
|
}
|
||||||
LogTasksAfterInterruption();
|
LogTasksAfterInterruption();
|
||||||
|
|
@ -196,9 +194,7 @@ internal abstract class MiniTaskController<T> : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ITask> list = new List<ITask>(num);
|
List<ITask> list = new List<ITask>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<ITask> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = new WaitAtEnd.WaitDelay();
|
||||||
int index = 0;
|
|
||||||
span[index] = new WaitAtEnd.WaitDelay();
|
|
||||||
taskQueue.InterruptWith(list);
|
taskQueue.InterruptWith(list);
|
||||||
LogTasksAfterInterruption();
|
LogTasksAfterInterruption();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -431,9 +431,7 @@ internal sealed class MovementController : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<Vector3> list = new List<Vector3>(num);
|
List<Vector3> list = new List<Vector3>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<Vector3> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = destination.Position;
|
||||||
int index = 0;
|
|
||||||
span[index] = destination.Position;
|
|
||||||
NavigateTo(EMovementType.None, dataId, list, fly: false, sprint: false, destination.StopDistance, destination.VerticalStopDistance);
|
NavigateTo(EMovementType.None, dataId, list, fly: false, sprint: false, destination.StopDistance, destination.VerticalStopDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
151
Questionable/Questionable.Controller/SeasonalDutyController.cs
Normal file
151
Questionable/Questionable.Controller/SeasonalDutyController.cs
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Questionable.Controller.Steps;
|
||||||
|
using Questionable.Controller.Steps.Common;
|
||||||
|
using Questionable.Controller.Steps.Interactions;
|
||||||
|
using Questionable.Controller.Steps.Movement;
|
||||||
|
using Questionable.Controller.Steps.Shared;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
|
||||||
|
namespace Questionable.Controller;
|
||||||
|
|
||||||
|
internal sealed class SeasonalDutyController : MiniTaskController<SeasonalDutyController>
|
||||||
|
{
|
||||||
|
private readonly MovementController _movementController;
|
||||||
|
|
||||||
|
private readonly IClientState _clientState;
|
||||||
|
|
||||||
|
private readonly ILogger<SeasonalDutyController> _logger;
|
||||||
|
|
||||||
|
private SeasonalDutyDefinition? _currentDuty;
|
||||||
|
|
||||||
|
private int _completedCycles;
|
||||||
|
|
||||||
|
private int? _cycleLimit;
|
||||||
|
|
||||||
|
private DateTime _startTime;
|
||||||
|
|
||||||
|
public bool IsRunning => _currentDuty != null;
|
||||||
|
|
||||||
|
public SeasonalDutyDefinition? CurrentDuty => _currentDuty;
|
||||||
|
|
||||||
|
public int CompletedCycles => _completedCycles;
|
||||||
|
|
||||||
|
public int? CycleLimit => _cycleLimit;
|
||||||
|
|
||||||
|
public TimeSpan ElapsedTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsRunning)
|
||||||
|
{
|
||||||
|
return TimeSpan.Zero;
|
||||||
|
}
|
||||||
|
return DateTime.UtcNow - _startTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SeasonalDutyController(IChatGui chatGui, ICondition condition, IServiceProvider serviceProvider, InterruptHandler interruptHandler, IDataManager dataManager, ILogger<SeasonalDutyController> logger, MovementController movementController, IClientState clientState)
|
||||||
|
: base(chatGui, condition, serviceProvider, interruptHandler, dataManager, logger)
|
||||||
|
{
|
||||||
|
_movementController = movementController;
|
||||||
|
_clientState = clientState;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(SeasonalDutyDefinition duty, int? cycleLimit = null)
|
||||||
|
{
|
||||||
|
_currentDuty = duty;
|
||||||
|
_completedCycles = 0;
|
||||||
|
_cycleLimit = cycleLimit;
|
||||||
|
_startTime = DateTime.UtcNow;
|
||||||
|
_logger.LogInformation("Starting seasonal duty farming: {DutyName} (limit: {Limit})", duty.Name, cycleLimit?.ToString(CultureInfo.InvariantCulture) ?? "unlimited");
|
||||||
|
EnqueueDutyCycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (_currentDuty == null || _movementController.IsPathfinding || _movementController.IsPathRunning)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_taskQueue.AllTasksComplete)
|
||||||
|
{
|
||||||
|
_completedCycles++;
|
||||||
|
if (_cycleLimit.HasValue && _completedCycles >= _cycleLimit.Value)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Seasonal duty cycle limit reached ({Cycles}/{Limit})", _completedCycles, _cycleLimit.Value);
|
||||||
|
Stop("Cycle limit reached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EnqueueDutyCycle();
|
||||||
|
}
|
||||||
|
UpdateCurrentTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnqueueDutyCycle()
|
||||||
|
{
|
||||||
|
if (_currentDuty != null)
|
||||||
|
{
|
||||||
|
SeasonalDutyDefinition currentDuty = _currentDuty;
|
||||||
|
_logger.LogInformation("Enqueuing seasonal duty cycle for {DutyName}", currentDuty.Name);
|
||||||
|
if (_clientState.TerritoryType != currentDuty.TerritoryId && _clientState.TerritoryType != currentDuty.DutyTerritoryId)
|
||||||
|
{
|
||||||
|
_taskQueue.Enqueue(new AetheryteShortcut.Task(null, null, currentDuty.Aetheryte, currentDuty.TerritoryId));
|
||||||
|
}
|
||||||
|
if (currentDuty.AethernetShortcut != null)
|
||||||
|
{
|
||||||
|
_taskQueue.Enqueue(new AethernetShortcut.Task(currentDuty.AethernetShortcut.From, currentDuty.AethernetShortcut.To));
|
||||||
|
}
|
||||||
|
_taskQueue.Enqueue(new MoveTask(currentDuty.TerritoryId, currentDuty.NpcPosition, null, 3f));
|
||||||
|
_taskQueue.Enqueue(new Mount.UnmountTask());
|
||||||
|
_taskQueue.Enqueue(new Interact.Task(currentDuty.NpcDataId, null, EInteractionType.Interact, SkipMarkerCheck: true));
|
||||||
|
_taskQueue.Enqueue(new WaitCondition.Task(() => _clientState.TerritoryType == _currentDuty.DutyTerritoryId, $"Wait(territory: {currentDuty.DutyTerritoryId})"));
|
||||||
|
_taskQueue.Enqueue(new ClearObjectsWithAction.ClearTask(currentDuty.DataIds, currentDuty.Action, currentDuty.DutyTerritoryId, currentDuty.StopDistance, currentDuty.WaypointPositions));
|
||||||
|
_taskQueue.Enqueue(new WaitCondition.Task(() => _clientState.TerritoryType != _currentDuty.DutyTerritoryId, "Wait(duty end)"));
|
||||||
|
_taskQueue.Enqueue(new WaitAtEnd.WaitDelay(TimeSpan.FromSeconds(3L)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Stop(string label)
|
||||||
|
{
|
||||||
|
if (_currentDuty != null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Stopping seasonal duty farming: {Label} (completed {Cycles} cycles)", label, _completedCycles);
|
||||||
|
_currentDuty = null;
|
||||||
|
_completedCycles = 0;
|
||||||
|
_cycleLimit = null;
|
||||||
|
_taskQueue.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IList<string> GetRemainingTaskNames()
|
||||||
|
{
|
||||||
|
ITask task = _taskQueue.CurrentTaskExecutor?.CurrentTask;
|
||||||
|
if (task != null)
|
||||||
|
{
|
||||||
|
string text = task.ToString() ?? "?";
|
||||||
|
IList<string> remainingTaskNames = base.GetRemainingTaskNames();
|
||||||
|
int num = 1 + remainingTaskNames.Count;
|
||||||
|
List<string> list = new List<string>(num);
|
||||||
|
CollectionsMarshal.SetCount(list, num);
|
||||||
|
Span<string> span = CollectionsMarshal.AsSpan(list);
|
||||||
|
int num2 = 0;
|
||||||
|
span[num2] = text;
|
||||||
|
num2++;
|
||||||
|
{
|
||||||
|
foreach (string item in remainingTaskNames)
|
||||||
|
{
|
||||||
|
span[num2] = item;
|
||||||
|
num2++;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base.GetRemainingTaskNames();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
#define RELEASE
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
using Questionable.SeasonalDutyPaths;
|
||||||
|
using Questionable.Windows.QuestComponents;
|
||||||
|
|
||||||
|
namespace Questionable.Controller;
|
||||||
|
|
||||||
|
internal sealed class SeasonalDutyDefinitionRegistry
|
||||||
|
{
|
||||||
|
private readonly IDalamudPluginInterface _pluginInterface;
|
||||||
|
|
||||||
|
private readonly ILogger<SeasonalDutyDefinitionRegistry> _logger;
|
||||||
|
|
||||||
|
private readonly Dictionary<ushort, SeasonalDutyDefinition> _definitions = new Dictionary<ushort, SeasonalDutyDefinition>();
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<ushort, SeasonalDutyDefinition> Definitions => _definitions;
|
||||||
|
|
||||||
|
public SeasonalDutyDefinitionRegistry(IDalamudPluginInterface pluginInterface, ILogger<SeasonalDutyDefinitionRegistry> logger)
|
||||||
|
{
|
||||||
|
_pluginInterface = pluginInterface;
|
||||||
|
_logger = logger;
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reload()
|
||||||
|
{
|
||||||
|
_definitions.Clear();
|
||||||
|
LoadFromAssembly();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoadFromDirectory(new DirectoryInfo(Path.Combine(_pluginInterface.ConfigDirectory.FullName, "SeasonalDutyDefinitions")));
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.LogError(exception, "Failed to load seasonal duty definitions from user directory (some may have been successfully loaded)");
|
||||||
|
}
|
||||||
|
RemoveExpiredDefinitions();
|
||||||
|
_logger.LogInformation("Loaded {Count} seasonal duty definitions in total", _definitions.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional("RELEASE")]
|
||||||
|
private void LoadFromAssembly()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Loading seasonal duty definitions from assembly");
|
||||||
|
IReadOnlyDictionary<ushort, SeasonalDutyDefinition> definitions = AssemblySeasonalDutyDefinitionLoader.GetDefinitions();
|
||||||
|
_logger.LogInformation("AssemblySeasonalDutyDefinitionLoader returned {Count} definitions", definitions.Count);
|
||||||
|
foreach (var (key, value) in definitions)
|
||||||
|
{
|
||||||
|
_definitions[key] = value;
|
||||||
|
}
|
||||||
|
_logger.LogInformation("Loaded {Count} seasonal duty definitions from assembly", _definitions.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Conditional("DEBUG")]
|
||||||
|
private void LoadFromProjectDirectory()
|
||||||
|
{
|
||||||
|
DirectoryInfo directoryInfo = _pluginInterface.AssemblyLocation.Directory?.Parent?.Parent;
|
||||||
|
if (directoryInfo == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DirectoryInfo directoryInfo2 = new DirectoryInfo(Path.Combine(directoryInfo.FullName, "SeasonalDutyPaths"));
|
||||||
|
if (directoryInfo2.Exists)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoadFromDirectory(directoryInfo2);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_definitions.Clear();
|
||||||
|
_logger.LogError(exception, "Failed to load seasonal duty definitions from project directory");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFromDirectory(DirectoryInfo directory)
|
||||||
|
{
|
||||||
|
if (!directory.Exists)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Not loading seasonal duty definitions from {DirectoryName} (doesn't exist)", directory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FileInfo[] files = directory.GetFiles("*.json");
|
||||||
|
foreach (FileInfo fileInfo in files)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ushort? num = ExtractIdFromName(fileInfo.Name);
|
||||||
|
if (!num.HasValue)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
using FileStream utf8Json = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read);
|
||||||
|
SeasonalDutyDefinition seasonalDutyDefinition = JsonSerializer.Deserialize<SeasonalDutyDefinition>(utf8Json);
|
||||||
|
if (seasonalDutyDefinition != null)
|
||||||
|
{
|
||||||
|
_definitions[num.Value] = seasonalDutyDefinition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
_logger.LogError(exception, "Unable to load seasonal duty definition file {FileName}", fileInfo.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveExpiredDefinitions()
|
||||||
|
{
|
||||||
|
foreach (ushort item in (from kvp in _definitions.Where<KeyValuePair<ushort, SeasonalDutyDefinition>>(delegate(KeyValuePair<ushort, SeasonalDutyDefinition> kvp)
|
||||||
|
{
|
||||||
|
DateTime? eventExpiry = kvp.Value.EventExpiry;
|
||||||
|
if (eventExpiry.HasValue)
|
||||||
|
{
|
||||||
|
DateTime valueOrDefault = eventExpiry.GetValueOrDefault();
|
||||||
|
return EventInfoComponent.NormalizeExpiry(valueOrDefault) < DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
select kvp.Key).ToList())
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Removing expired seasonal duty definition {Id} '{Name}'", item, _definitions[item].Name);
|
||||||
|
_definitions.Remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ushort? ExtractIdFromName(string fileName)
|
||||||
|
{
|
||||||
|
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
|
||||||
|
if (!fileNameWithoutExtension.Contains('_', StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (ushort.TryParse(fileNameWithoutExtension.Split('_', 2)[0], out var result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -846,20 +846,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list15 = new List<ElementId>(num);
|
List<ElementId> list15 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list15, num);
|
CollectionsMarshal.SetCount(list15, num);
|
||||||
Span<ElementId> span15 = CollectionsMarshal.AsSpan(list15);
|
CollectionsMarshal.AsSpan(list15)[0] = new AethernetId(1);
|
||||||
int index = 0;
|
|
||||||
span15[index] = new AethernetId(1);
|
|
||||||
source = list15;
|
source = list15;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_gridania":
|
case "aethernet_gridania":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list14 = new List<ElementId>(index);
|
List<ElementId> list14 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list14, index);
|
CollectionsMarshal.SetCount(list14, num);
|
||||||
Span<ElementId> span14 = CollectionsMarshal.AsSpan(list14);
|
CollectionsMarshal.AsSpan(list14)[0] = new AethernetId(2);
|
||||||
int num = 0;
|
|
||||||
span14[num] = new AethernetId(2);
|
|
||||||
source = list14;
|
source = list14;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -868,20 +864,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list13 = new List<ElementId>(num);
|
List<ElementId> list13 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list13, num);
|
CollectionsMarshal.SetCount(list13, num);
|
||||||
Span<ElementId> span13 = CollectionsMarshal.AsSpan(list13);
|
CollectionsMarshal.AsSpan(list13)[0] = new AethernetId(3);
|
||||||
int index = 0;
|
|
||||||
span13[index] = new AethernetId(3);
|
|
||||||
source = list13;
|
source = list13;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_goldsaucer":
|
case "aethernet_goldsaucer":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list12 = new List<ElementId>(index);
|
List<ElementId> list12 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list12, index);
|
CollectionsMarshal.SetCount(list12, num);
|
||||||
Span<ElementId> span12 = CollectionsMarshal.AsSpan(list12);
|
CollectionsMarshal.AsSpan(list12)[0] = new AethernetId(4);
|
||||||
int num = 0;
|
|
||||||
span12[num] = new AethernetId(4);
|
|
||||||
source = list12;
|
source = list12;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -890,20 +882,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list11 = new List<ElementId>(num);
|
List<ElementId> list11 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list11, num);
|
CollectionsMarshal.SetCount(list11, num);
|
||||||
Span<ElementId> span11 = CollectionsMarshal.AsSpan(list11);
|
CollectionsMarshal.AsSpan(list11)[0] = new AethernetId(5);
|
||||||
int index = 0;
|
|
||||||
span11[index] = new AethernetId(5);
|
|
||||||
source = list11;
|
source = list11;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_idyllshire":
|
case "aethernet_idyllshire":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list10 = new List<ElementId>(index);
|
List<ElementId> list10 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list10, index);
|
CollectionsMarshal.SetCount(list10, num);
|
||||||
Span<ElementId> span10 = CollectionsMarshal.AsSpan(list10);
|
CollectionsMarshal.AsSpan(list10)[0] = new AethernetId(6);
|
||||||
int num = 0;
|
|
||||||
span10[num] = new AethernetId(6);
|
|
||||||
source = list10;
|
source = list10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -912,20 +900,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list9 = new List<ElementId>(num);
|
List<ElementId> list9 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list9, num);
|
CollectionsMarshal.SetCount(list9, num);
|
||||||
Span<ElementId> span9 = CollectionsMarshal.AsSpan(list9);
|
CollectionsMarshal.AsSpan(list9)[0] = new AethernetId(7);
|
||||||
int index = 0;
|
|
||||||
span9[index] = new AethernetId(7);
|
|
||||||
source = list9;
|
source = list9;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_kugane":
|
case "aethernet_kugane":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list8 = new List<ElementId>(index);
|
List<ElementId> list8 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list8, index);
|
CollectionsMarshal.SetCount(list8, num);
|
||||||
Span<ElementId> span8 = CollectionsMarshal.AsSpan(list8);
|
CollectionsMarshal.AsSpan(list8)[0] = new AethernetId(8);
|
||||||
int num = 0;
|
|
||||||
span8[num] = new AethernetId(8);
|
|
||||||
source = list8;
|
source = list8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -934,20 +918,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list7 = new List<ElementId>(num);
|
List<ElementId> list7 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list7, num);
|
CollectionsMarshal.SetCount(list7, num);
|
||||||
Span<ElementId> span7 = CollectionsMarshal.AsSpan(list7);
|
CollectionsMarshal.AsSpan(list7)[0] = new AethernetId(9);
|
||||||
int index = 0;
|
|
||||||
span7[index] = new AethernetId(9);
|
|
||||||
source = list7;
|
source = list7;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_the_crystarium":
|
case "aethernet_the_crystarium":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list6 = new List<ElementId>(index);
|
List<ElementId> list6 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list6, index);
|
CollectionsMarshal.SetCount(list6, num);
|
||||||
Span<ElementId> span6 = CollectionsMarshal.AsSpan(list6);
|
CollectionsMarshal.AsSpan(list6)[0] = new AethernetId(10);
|
||||||
int num = 0;
|
|
||||||
span6[num] = new AethernetId(10);
|
|
||||||
source = list6;
|
source = list6;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -956,20 +936,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list5 = new List<ElementId>(num);
|
List<ElementId> list5 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list5, num);
|
CollectionsMarshal.SetCount(list5, num);
|
||||||
Span<ElementId> span5 = CollectionsMarshal.AsSpan(list5);
|
CollectionsMarshal.AsSpan(list5)[0] = new AethernetId(11);
|
||||||
int index = 0;
|
|
||||||
span5[index] = new AethernetId(11);
|
|
||||||
source = list5;
|
source = list5;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_old_sharlayan":
|
case "aethernet_old_sharlayan":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list4 = new List<ElementId>(index);
|
List<ElementId> list4 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list4, index);
|
CollectionsMarshal.SetCount(list4, num);
|
||||||
Span<ElementId> span4 = CollectionsMarshal.AsSpan(list4);
|
CollectionsMarshal.AsSpan(list4)[0] = new AethernetId(12);
|
||||||
int num = 0;
|
|
||||||
span4[num] = new AethernetId(12);
|
|
||||||
source = list4;
|
source = list4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -978,20 +954,16 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list3 = new List<ElementId>(num);
|
List<ElementId> list3 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list3, num);
|
CollectionsMarshal.SetCount(list3, num);
|
||||||
Span<ElementId> span3 = CollectionsMarshal.AsSpan(list3);
|
CollectionsMarshal.AsSpan(list3)[0] = new AethernetId(13);
|
||||||
int index = 0;
|
|
||||||
span3[index] = new AethernetId(13);
|
|
||||||
source = list3;
|
source = list3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "aethernet_tuliyollal":
|
case "aethernet_tuliyollal":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list2 = new List<ElementId>(index);
|
List<ElementId> list2 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list2, index);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<ElementId> span2 = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = new AethernetId(14);
|
||||||
int num = 0;
|
|
||||||
span2[num] = new AethernetId(14);
|
|
||||||
source = list2;
|
source = list2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1000,9 +972,7 @@ internal sealed class QuestionableIpc : IDisposable
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list = new List<ElementId>(num);
|
List<ElementId> list = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<ElementId> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = new AethernetId(15);
|
||||||
int index = 0;
|
|
||||||
span[index] = new AethernetId(15);
|
|
||||||
source = list;
|
source = list;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,7 @@ internal sealed class AlliedSocietyQuestFunctions
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<NpcData> list = new List<NpcData>(num);
|
List<NpcData> list = new List<NpcData>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<NpcData> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = npcData;
|
||||||
int index = 0;
|
|
||||||
span[index] = npcData;
|
|
||||||
questsByAlliedSociety[item] = list;
|
questsByAlliedSociety[item] = list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Lumina.Excel;
|
using Lumina.Excel;
|
||||||
using Lumina.Excel.Sheets;
|
using Lumina.Excel.Sheets;
|
||||||
using Lumina.Text.ReadOnly;
|
using Lumina.Text.ReadOnly;
|
||||||
|
|
@ -184,10 +185,10 @@ public readonly struct QuestEx : IExcelRow<QuestEx>
|
||||||
{
|
{
|
||||||
ExcelModule module = _003Cpage_003EP.Module;
|
ExcelModule module = _003Cpage_003EP.Module;
|
||||||
uint rowId = _003Cpage_003EP.ReadUInt32(_003Coffset_003EP + 2712);
|
uint rowId = _003Cpage_003EP.ReadUInt32(_003Coffset_003EP + 2712);
|
||||||
global::_003C_003Ey__InlineArray2<Type> buffer = default(global::_003C_003Ey__InlineArray2<Type>);
|
InlineArray2<Type> buffer = default(InlineArray2<Type>);
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<global::_003C_003Ey__InlineArray2<Type>, Type>(ref buffer, 0) = typeof(EObjName);
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray2<Type>, Type>(ref buffer, 0) = typeof(EObjName);
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<global::_003C_003Ey__InlineArray2<Type>, Type>(ref buffer, 1) = typeof(ENpcResident);
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray2<Type>, Type>(ref buffer, 1) = typeof(ENpcResident);
|
||||||
return RowRef.GetFirstValidRowOrUntyped(module, rowId, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<global::_003C_003Ey__InlineArray2<Type>, Type>(in buffer, 2), -965341264, _003Cpage_003EP.Language);
|
return RowRef.GetFirstValidRowOrUntyped(module, rowId, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<InlineArray2<Type>, Type>(in buffer, 2), -965341264, _003Cpage_003EP.Language);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,10 +200,10 @@ public readonly struct QuestEx : IExcelRow<QuestEx>
|
||||||
{
|
{
|
||||||
ExcelModule module = _003Cpage_003EP.Module;
|
ExcelModule module = _003Cpage_003EP.Module;
|
||||||
uint rowId = _003Cpage_003EP.ReadUInt32(_003Coffset_003EP + 2720);
|
uint rowId = _003Cpage_003EP.ReadUInt32(_003Coffset_003EP + 2720);
|
||||||
global::_003C_003Ey__InlineArray2<Type> buffer = default(global::_003C_003Ey__InlineArray2<Type>);
|
InlineArray2<Type> buffer = default(InlineArray2<Type>);
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<global::_003C_003Ey__InlineArray2<Type>, Type>(ref buffer, 0) = typeof(EObjName);
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray2<Type>, Type>(ref buffer, 0) = typeof(EObjName);
|
||||||
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<global::_003C_003Ey__InlineArray2<Type>, Type>(ref buffer, 1) = typeof(ENpcResident);
|
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray2<Type>, Type>(ref buffer, 1) = typeof(ENpcResident);
|
||||||
return RowRef.GetFirstValidRowOrUntyped(module, rowId, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<global::_003C_003Ey__InlineArray2<Type>, Type>(in buffer, 2), -965341264, _003Cpage_003EP.Language);
|
return RowRef.GetFirstValidRowOrUntyped(module, rowId, global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<InlineArray2<Type>, Type>(in buffer, 2), -965341264, _003Cpage_003EP.Language);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -480,16 +480,12 @@ internal sealed class GeneralConfigComponent : ConfigComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<(uint, string)> list = new List<(uint, string)>(num);
|
List<(uint, string)> list = new List<(uint, string)>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<(uint, string)> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = (0u, "Mount Roulette");
|
||||||
int index = 0;
|
|
||||||
span[index] = (0u, "Mount Roulette");
|
|
||||||
DefaultMounts = list;
|
DefaultMounts = list;
|
||||||
index = 1;
|
num = 1;
|
||||||
List<(EClassJob, string)> list2 = new List<(EClassJob, string)>(index);
|
List<(EClassJob, string)> list2 = new List<(EClassJob, string)>(num);
|
||||||
CollectionsMarshal.SetCount(list2, index);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<(EClassJob, string)> span2 = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = (EClassJob.Adventurer, "Auto (highest level/item level)");
|
||||||
num = 0;
|
|
||||||
span2[num] = (EClassJob.Adventurer, "Auto (highest level/item level)");
|
|
||||||
DefaultClassJobs = list2;
|
DefaultClassJobs = list2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -898,16 +898,11 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||||
List<(EClassJob, string)> list = new List<(EClassJob, string)>(num);
|
List<(EClassJob, string)> list = new List<(EClassJob, string)>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<(EClassJob, string)> span = CollectionsMarshal.AsSpan(list);
|
Span<(EClassJob, string)> span = CollectionsMarshal.AsSpan(list);
|
||||||
int num2 = 0;
|
span[0] = (EClassJob.Paladin, "Tank Role Quests");
|
||||||
span[num2] = (EClassJob.Paladin, "Tank Role Quests");
|
span[1] = (EClassJob.WhiteMage, "Healer Role Quests");
|
||||||
num2++;
|
span[2] = (EClassJob.Lancer, "Melee Role Quests");
|
||||||
span[num2] = (EClassJob.WhiteMage, "Healer Role Quests");
|
span[3] = (EClassJob.Bard, "Physical Ranged Role Quests");
|
||||||
num2++;
|
span[4] = (EClassJob.BlackMage, "Magical Ranged Role Quests");
|
||||||
span[num2] = (EClassJob.Lancer, "Melee Role Quests");
|
|
||||||
num2++;
|
|
||||||
span[num2] = (EClassJob.Bard, "Physical Ranged Role Quests");
|
|
||||||
num2++;
|
|
||||||
span[num2] = (EClassJob.BlackMage, "Magical Ranged Role Quests");
|
|
||||||
RoleQuestCategories = list;
|
RoleQuestCategories = list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ internal sealed class ActiveQuestComponent
|
||||||
public event EventHandler? Reload;
|
public event EventHandler? Reload;
|
||||||
|
|
||||||
[GeneratedRegex("\\s\\s+", RegexOptions.IgnoreCase, "en-US")]
|
[GeneratedRegex("\\s\\s+", RegexOptions.IgnoreCase, "en-US")]
|
||||||
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.7603")]
|
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.15411")]
|
||||||
private static Regex MultipleWhitespaceRegex()
|
private static Regex MultipleWhitespaceRegex()
|
||||||
{
|
{
|
||||||
return _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0.Instance;
|
return _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0.Instance;
|
||||||
|
|
|
||||||
|
|
@ -615,19 +615,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list15 = new List<ElementId>(num);
|
List<ElementId> list15 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list15, num);
|
CollectionsMarshal.SetCount(list15, num);
|
||||||
Span<ElementId> span15 = CollectionsMarshal.AsSpan(list15);
|
CollectionsMarshal.AsSpan(list15)[0] = new AethernetId(1);
|
||||||
int index = 0;
|
|
||||||
span15[index] = new AethernetId(1);
|
|
||||||
return list15;
|
return list15;
|
||||||
}
|
}
|
||||||
case "Gridania":
|
case "Gridania":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list14 = new List<ElementId>(index);
|
List<ElementId> list14 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list14, index);
|
CollectionsMarshal.SetCount(list14, num);
|
||||||
Span<ElementId> span14 = CollectionsMarshal.AsSpan(list14);
|
CollectionsMarshal.AsSpan(list14)[0] = new AethernetId(2);
|
||||||
int num = 0;
|
|
||||||
span14[num] = new AethernetId(2);
|
|
||||||
return list14;
|
return list14;
|
||||||
}
|
}
|
||||||
case "Uldah":
|
case "Uldah":
|
||||||
|
|
@ -635,19 +631,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list13 = new List<ElementId>(num);
|
List<ElementId> list13 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list13, num);
|
CollectionsMarshal.SetCount(list13, num);
|
||||||
Span<ElementId> span13 = CollectionsMarshal.AsSpan(list13);
|
CollectionsMarshal.AsSpan(list13)[0] = new AethernetId(3);
|
||||||
int index = 0;
|
|
||||||
span13[index] = new AethernetId(3);
|
|
||||||
return list13;
|
return list13;
|
||||||
}
|
}
|
||||||
case "GoldSaucer":
|
case "GoldSaucer":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list12 = new List<ElementId>(index);
|
List<ElementId> list12 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list12, index);
|
CollectionsMarshal.SetCount(list12, num);
|
||||||
Span<ElementId> span12 = CollectionsMarshal.AsSpan(list12);
|
CollectionsMarshal.AsSpan(list12)[0] = new AethernetId(4);
|
||||||
int num = 0;
|
|
||||||
span12[num] = new AethernetId(4);
|
|
||||||
return list12;
|
return list12;
|
||||||
}
|
}
|
||||||
case "Ishgard":
|
case "Ishgard":
|
||||||
|
|
@ -655,19 +647,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list11 = new List<ElementId>(num);
|
List<ElementId> list11 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list11, num);
|
CollectionsMarshal.SetCount(list11, num);
|
||||||
Span<ElementId> span11 = CollectionsMarshal.AsSpan(list11);
|
CollectionsMarshal.AsSpan(list11)[0] = new AethernetId(5);
|
||||||
int index = 0;
|
|
||||||
span11[index] = new AethernetId(5);
|
|
||||||
return list11;
|
return list11;
|
||||||
}
|
}
|
||||||
case "Idyllshire":
|
case "Idyllshire":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list10 = new List<ElementId>(index);
|
List<ElementId> list10 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list10, index);
|
CollectionsMarshal.SetCount(list10, num);
|
||||||
Span<ElementId> span10 = CollectionsMarshal.AsSpan(list10);
|
CollectionsMarshal.AsSpan(list10)[0] = new AethernetId(6);
|
||||||
int num = 0;
|
|
||||||
span10[num] = new AethernetId(6);
|
|
||||||
return list10;
|
return list10;
|
||||||
}
|
}
|
||||||
case "Rhalgr's Reach":
|
case "Rhalgr's Reach":
|
||||||
|
|
@ -675,19 +663,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list9 = new List<ElementId>(num);
|
List<ElementId> list9 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list9, num);
|
CollectionsMarshal.SetCount(list9, num);
|
||||||
Span<ElementId> span9 = CollectionsMarshal.AsSpan(list9);
|
CollectionsMarshal.AsSpan(list9)[0] = new AethernetId(7);
|
||||||
int index = 0;
|
|
||||||
span9[index] = new AethernetId(7);
|
|
||||||
return list9;
|
return list9;
|
||||||
}
|
}
|
||||||
case "Kugane":
|
case "Kugane":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list8 = new List<ElementId>(index);
|
List<ElementId> list8 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list8, index);
|
CollectionsMarshal.SetCount(list8, num);
|
||||||
Span<ElementId> span8 = CollectionsMarshal.AsSpan(list8);
|
CollectionsMarshal.AsSpan(list8)[0] = new AethernetId(8);
|
||||||
int num = 0;
|
|
||||||
span8[num] = new AethernetId(8);
|
|
||||||
return list8;
|
return list8;
|
||||||
}
|
}
|
||||||
case "Doman Enclave":
|
case "Doman Enclave":
|
||||||
|
|
@ -695,19 +679,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list7 = new List<ElementId>(num);
|
List<ElementId> list7 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list7, num);
|
CollectionsMarshal.SetCount(list7, num);
|
||||||
Span<ElementId> span7 = CollectionsMarshal.AsSpan(list7);
|
CollectionsMarshal.AsSpan(list7)[0] = new AethernetId(9);
|
||||||
int index = 0;
|
|
||||||
span7[index] = new AethernetId(9);
|
|
||||||
return list7;
|
return list7;
|
||||||
}
|
}
|
||||||
case "The Crystarium":
|
case "The Crystarium":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list6 = new List<ElementId>(index);
|
List<ElementId> list6 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list6, index);
|
CollectionsMarshal.SetCount(list6, num);
|
||||||
Span<ElementId> span6 = CollectionsMarshal.AsSpan(list6);
|
CollectionsMarshal.AsSpan(list6)[0] = new AethernetId(10);
|
||||||
int num = 0;
|
|
||||||
span6[num] = new AethernetId(10);
|
|
||||||
return list6;
|
return list6;
|
||||||
}
|
}
|
||||||
case "Eulmore":
|
case "Eulmore":
|
||||||
|
|
@ -715,19 +695,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list5 = new List<ElementId>(num);
|
List<ElementId> list5 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list5, num);
|
CollectionsMarshal.SetCount(list5, num);
|
||||||
Span<ElementId> span5 = CollectionsMarshal.AsSpan(list5);
|
CollectionsMarshal.AsSpan(list5)[0] = new AethernetId(11);
|
||||||
int index = 0;
|
|
||||||
span5[index] = new AethernetId(11);
|
|
||||||
return list5;
|
return list5;
|
||||||
}
|
}
|
||||||
case "Old Sharlayan":
|
case "Old Sharlayan":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list4 = new List<ElementId>(index);
|
List<ElementId> list4 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list4, index);
|
CollectionsMarshal.SetCount(list4, num);
|
||||||
Span<ElementId> span4 = CollectionsMarshal.AsSpan(list4);
|
CollectionsMarshal.AsSpan(list4)[0] = new AethernetId(12);
|
||||||
int num = 0;
|
|
||||||
span4[num] = new AethernetId(12);
|
|
||||||
return list4;
|
return list4;
|
||||||
}
|
}
|
||||||
case "Radz-at-Han":
|
case "Radz-at-Han":
|
||||||
|
|
@ -735,19 +711,15 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list3 = new List<ElementId>(num);
|
List<ElementId> list3 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list3, num);
|
CollectionsMarshal.SetCount(list3, num);
|
||||||
Span<ElementId> span3 = CollectionsMarshal.AsSpan(list3);
|
CollectionsMarshal.AsSpan(list3)[0] = new AethernetId(13);
|
||||||
int index = 0;
|
|
||||||
span3[index] = new AethernetId(13);
|
|
||||||
return list3;
|
return list3;
|
||||||
}
|
}
|
||||||
case "Tuliyollal":
|
case "Tuliyollal":
|
||||||
{
|
{
|
||||||
int index = 1;
|
int num = 1;
|
||||||
List<ElementId> list2 = new List<ElementId>(index);
|
List<ElementId> list2 = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list2, index);
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
Span<ElementId> span2 = CollectionsMarshal.AsSpan(list2);
|
CollectionsMarshal.AsSpan(list2)[0] = new AethernetId(14);
|
||||||
int num = 0;
|
|
||||||
span2[num] = new AethernetId(14);
|
|
||||||
return list2;
|
return list2;
|
||||||
}
|
}
|
||||||
case "Solution Nine":
|
case "Solution Nine":
|
||||||
|
|
@ -755,9 +727,7 @@ internal sealed class PresetBuilderComponent
|
||||||
int num = 1;
|
int num = 1;
|
||||||
List<ElementId> list = new List<ElementId>(num);
|
List<ElementId> list = new List<ElementId>(num);
|
||||||
CollectionsMarshal.SetCount(list, num);
|
CollectionsMarshal.SetCount(list, num);
|
||||||
Span<ElementId> span = CollectionsMarshal.AsSpan(list);
|
CollectionsMarshal.AsSpan(list)[0] = new AethernetId(15);
|
||||||
int index = 0;
|
|
||||||
span[index] = new AethernetId(15);
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
424
Questionable/Questionable.Windows/SeasonalDutySelectionWindow.cs
Normal file
424
Questionable/Questionable.Windows/SeasonalDutySelectionWindow.cs
Normal file
|
|
@ -0,0 +1,424 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Colors;
|
||||||
|
using Dalamud.Interface.Components;
|
||||||
|
using Dalamud.Interface.Utility.Raii;
|
||||||
|
using Dalamud.Interface.Windowing;
|
||||||
|
using LLib.ImGui;
|
||||||
|
using Questionable.Controller;
|
||||||
|
using Questionable.Data;
|
||||||
|
using Questionable.Functions;
|
||||||
|
using Questionable.Model;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
using Questionable.Windows.QuestComponents;
|
||||||
|
|
||||||
|
namespace Questionable.Windows;
|
||||||
|
|
||||||
|
internal sealed class SeasonalDutySelectionWindow : LWindow
|
||||||
|
{
|
||||||
|
private readonly SeasonalDutyController _seasonalDutyController;
|
||||||
|
|
||||||
|
private readonly SeasonalDutyDefinitionRegistry _seasonalDutyDefinitionRegistry;
|
||||||
|
|
||||||
|
private readonly QuestController _questController;
|
||||||
|
|
||||||
|
private readonly FateController _fateController;
|
||||||
|
|
||||||
|
private readonly MovementController _movementController;
|
||||||
|
|
||||||
|
private readonly QuestFunctions _questFunctions;
|
||||||
|
|
||||||
|
private readonly QuestData _questData;
|
||||||
|
|
||||||
|
private readonly TerritoryData _territoryData;
|
||||||
|
|
||||||
|
private int _cycleLimit;
|
||||||
|
|
||||||
|
public SeasonalDutySelectionWindow(SeasonalDutyController seasonalDutyController, SeasonalDutyDefinitionRegistry seasonalDutyDefinitionRegistry, QuestController questController, FateController fateController, MovementController movementController, QuestFunctions questFunctions, QuestData questData, TerritoryData territoryData)
|
||||||
|
: base("Seasonal Duty Farming###QuestionableSeasonalDutyFarming")
|
||||||
|
{
|
||||||
|
_seasonalDutyController = seasonalDutyController;
|
||||||
|
_seasonalDutyDefinitionRegistry = seasonalDutyDefinitionRegistry;
|
||||||
|
_questController = questController;
|
||||||
|
_fateController = fateController;
|
||||||
|
_movementController = movementController;
|
||||||
|
_questFunctions = questFunctions;
|
||||||
|
_questData = questData;
|
||||||
|
_territoryData = territoryData;
|
||||||
|
base.Size = new Vector2(600f, 400f);
|
||||||
|
base.SizeCondition = ImGuiCond.FirstUseEver;
|
||||||
|
base.SizeConstraints = new WindowSizeConstraints
|
||||||
|
{
|
||||||
|
MinimumSize = new Vector2(500f, 300f),
|
||||||
|
MaximumSize = new Vector2(900f, 700f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawContent()
|
||||||
|
{
|
||||||
|
if (_seasonalDutyController.IsRunning)
|
||||||
|
{
|
||||||
|
DrawRunningHeader();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawControlsStrip();
|
||||||
|
}
|
||||||
|
if (_seasonalDutyDefinitionRegistry.Definitions.Count == 0)
|
||||||
|
{
|
||||||
|
DrawEmptyState();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawDutyTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawRunningHeader()
|
||||||
|
{
|
||||||
|
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
|
||||||
|
float x = ImGui.GetContentRegionAvail().X;
|
||||||
|
float num = ImGui.GetTextLineHeightWithSpacing() * 3f + ImGui.GetStyle().ItemSpacing.Y * 3f;
|
||||||
|
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
|
||||||
|
windowDrawList.AddRectFilledMultiColor(cursorScreenPos, cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(new Vector4(0.18f, 0.26f, 0.2f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.14f, 0.22f, 0.16f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.14f, 0.22f, 0.16f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.18f, 0.26f, 0.2f, 0.85f)));
|
||||||
|
windowDrawList.AddLine(cursorScreenPos + new Vector2(0f, num), cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(new Vector4(0.3f, 0.8f, 0.4f, 0.5f)), 2f);
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().ItemSpacing.Y);
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 8f);
|
||||||
|
float num2 = (float)ImGui.GetTime();
|
||||||
|
float num3 = 0.85f + MathF.Sin(num2 * 3f) * 0.15f;
|
||||||
|
Vector4 col = new Vector4(0f, 1f * num3, 0.3f * num3, 1f);
|
||||||
|
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||||
|
{
|
||||||
|
ImGui.TextColored(in col, FontAwesomeIcon.Leaf.ToIconString());
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextColored(ImGuiColors.ParsedGreen, _seasonalDutyController.CurrentDuty.Name);
|
||||||
|
ImGui.SameLine(x - 35f);
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero))
|
||||||
|
{
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, new Vector4(0.8f, 0.3f, 0.3f, 0.4f)))
|
||||||
|
{
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.ButtonActive, new Vector4(0.9f, 0.2f, 0.2f, 0.6f)))
|
||||||
|
{
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Stop))
|
||||||
|
{
|
||||||
|
_seasonalDutyController.Stop("UI stop");
|
||||||
|
_movementController.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 8f);
|
||||||
|
string value = (_seasonalDutyController.CycleLimit.HasValue ? $"Cycle {_seasonalDutyController.CompletedCycles + 1} / {_seasonalDutyController.CycleLimit}" : $"Cycle {_seasonalDutyController.CompletedCycles + 1}");
|
||||||
|
string value2 = FormatElapsed(_seasonalDutyController.ElapsedTime);
|
||||||
|
IList<string> remainingTaskNames = _seasonalDutyController.GetRemainingTaskNames();
|
||||||
|
string text = ((remainingTaskNames.Count > 0) ? remainingTaskNames.First() : "");
|
||||||
|
if (text.Length > 0)
|
||||||
|
{
|
||||||
|
Vector4 col2 = ImGuiColors.DalamudGrey3;
|
||||||
|
ImU8String text2 = new ImU8String(10, 3);
|
||||||
|
text2.AppendFormatted(value);
|
||||||
|
text2.AppendLiteral(" · ");
|
||||||
|
text2.AppendFormatted(value2);
|
||||||
|
text2.AppendLiteral(" · ");
|
||||||
|
text2.AppendFormatted(text);
|
||||||
|
ImGui.TextColored(in col2, text2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector4 col2 = ImGuiColors.DalamudGrey3;
|
||||||
|
ImU8String text3 = new ImU8String(5, 2);
|
||||||
|
text3.AppendFormatted(value);
|
||||||
|
text3.AppendLiteral(" · ");
|
||||||
|
text3.AppendFormatted(value2);
|
||||||
|
ImGui.TextColored(in col2, text3);
|
||||||
|
}
|
||||||
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 8f);
|
||||||
|
using (ImRaii.Disabled(disabled: true))
|
||||||
|
{
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.TextUnformatted("Cycles:");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetNextItemWidth(100f);
|
||||||
|
ImGui.InputInt("##CycleLimitRunning", ref _cycleLimit, 1, 5);
|
||||||
|
}
|
||||||
|
ImGui.SetCursorPosY(cursorScreenPos.Y + num - ImGui.GetCursorScreenPos().Y + ImGui.GetCursorPosY() + 4f);
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawControlsStrip()
|
||||||
|
{
|
||||||
|
using (ImRaii.Disabled(_seasonalDutyController.IsRunning))
|
||||||
|
{
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.TextUnformatted("Cycles:");
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetNextItemWidth(100f);
|
||||||
|
ImGui.InputInt("##CycleLimit", ref _cycleLimit, 1, 5);
|
||||||
|
if (_cycleLimit < 0)
|
||||||
|
{
|
||||||
|
_cycleLimit = 0;
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudGrey, (_cycleLimit == 0) ? "(unlimited)" : "");
|
||||||
|
}
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawEmptyState()
|
||||||
|
{
|
||||||
|
float y = ImGui.GetContentRegionAvail().Y;
|
||||||
|
float x = ImGui.GetContentRegionAvail().X;
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + y * 0.25f);
|
||||||
|
Vector4 col = new Vector4(0.3f, 0.65f, 0.4f, 0.7f);
|
||||||
|
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
|
||||||
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
|
string text = FontAwesomeIcon.Search.ToIconString();
|
||||||
|
Vector2 vector = ImGui.CalcTextSize(text);
|
||||||
|
vector *= 2.5f;
|
||||||
|
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
|
||||||
|
Vector2 vector2 = new Vector2(x * 0.5f, 0f) + cursorScreenPos + new Vector2(0f, vector.Y * 0.5f);
|
||||||
|
for (int num = 3; num > 0; num--)
|
||||||
|
{
|
||||||
|
Vector4 col2 = new Vector4(col.X, col.Y, col.Z, col.W * 0.1f * (float)num);
|
||||||
|
ImGui.SetCursorScreenPos(vector2 - vector * 0.5f - new Vector2(num * 2, num * 2));
|
||||||
|
ImGui.TextColored(in col2, text);
|
||||||
|
}
|
||||||
|
ImGui.SetCursorScreenPos(vector2 - vector * 0.5f);
|
||||||
|
ImGui.TextColored(in col, text);
|
||||||
|
ImGui.PopFont();
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + vector.Y * 0.5f + 20f);
|
||||||
|
string text2 = "No Seasonal Duty Definitions";
|
||||||
|
Vector2 vector3 = ImGui.CalcTextSize(text2);
|
||||||
|
Vector2 vector4 = new Vector2((x - vector3.X) * 0.5f, 0f) + ImGui.GetCursorScreenPos();
|
||||||
|
windowDrawList.AddText(vector4 + new Vector2(1f, 1f), ImGui.ColorConvertFloat4ToU32(new Vector4(0f, 0f, 0f, 0.5f)), text2);
|
||||||
|
ImGui.SetCursorPosX((x - vector3.X) * 0.5f);
|
||||||
|
ImGui.TextColored(new Vector4(0.95f, 0.95f, 1f, 1f), text2);
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.Spacing();
|
||||||
|
string text3 = "Add definitions to the SeasonalDutyPaths folder to get started.";
|
||||||
|
ImGui.SetCursorPosX((x - ImGui.CalcTextSize(text3).X) * 0.5f);
|
||||||
|
ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.8f, 1f), text3);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawDutyTable()
|
||||||
|
{
|
||||||
|
List<SeasonalDutyDefinition> list = _seasonalDutyDefinitionRegistry.Definitions.Values.OrderBy(delegate(SeasonalDutyDefinition d)
|
||||||
|
{
|
||||||
|
DateTime? eventExpiry = d.EventExpiry;
|
||||||
|
if (eventExpiry.HasValue)
|
||||||
|
{
|
||||||
|
DateTime valueOrDefault = eventExpiry.GetValueOrDefault();
|
||||||
|
if (EventInfoComponent.NormalizeExpiry(valueOrDefault) - DateTime.UtcNow > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}).ThenBy(delegate(SeasonalDutyDefinition d)
|
||||||
|
{
|
||||||
|
DateTime? eventExpiry = d.EventExpiry;
|
||||||
|
if (eventExpiry.HasValue)
|
||||||
|
{
|
||||||
|
DateTime valueOrDefault = eventExpiry.GetValueOrDefault();
|
||||||
|
TimeSpan timeSpan = EventInfoComponent.NormalizeExpiry(valueOrDefault) - DateTime.UtcNow;
|
||||||
|
if (timeSpan > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return timeSpan.TotalSeconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return double.MaxValue;
|
||||||
|
}).ThenBy<SeasonalDutyDefinition, string>((SeasonalDutyDefinition d) => d.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToList();
|
||||||
|
using ImRaii.IEndObject endObject = ImRaii.Table("SeasonalDutyTable", 4, ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerH | ImGuiTableFlags.ScrollY);
|
||||||
|
if (!endObject)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.None, 3f);
|
||||||
|
ImGui.TableSetupColumn("Zone", ImGuiTableColumnFlags.None, 2f);
|
||||||
|
ImGui.TableSetupColumn("Expiry", ImGuiTableColumnFlags.WidthFixed, 80f);
|
||||||
|
ImGui.TableSetupColumn("##Actions", ImGuiTableColumnFlags.WidthFixed, 30f);
|
||||||
|
ImGui.TableHeadersRow();
|
||||||
|
foreach (SeasonalDutyDefinition item in list)
|
||||||
|
{
|
||||||
|
ImGui.TableNextRow();
|
||||||
|
bool flag = _seasonalDutyController.IsRunning && _seasonalDutyController.CurrentDuty == item;
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
float num = (float)ImGui.GetTime();
|
||||||
|
float w = 0.1f + MathF.Sin(num * 2.5f) * 0.05f;
|
||||||
|
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, ImGui.GetColorU32(new Vector4(0f, 0.85f, 0.3f, w)));
|
||||||
|
}
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
DrawDutyRowName(item, flag);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TextUnformatted(_territoryData.GetName(item.TerritoryId) ?? item.Name);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
DrawDutyRowExpiry(item);
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
bool disabled = _seasonalDutyController.IsRunning || _fateController.IsRunning || _questController.AutomationType != QuestController.EAutomationType.Manual;
|
||||||
|
DrawDutyRowActions(item, disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawDutyRowName(SeasonalDutyDefinition duty, bool isActive)
|
||||||
|
{
|
||||||
|
if (isActive)
|
||||||
|
{
|
||||||
|
float num = (float)ImGui.GetTime();
|
||||||
|
float num2 = 0.85f + MathF.Sin(num * 3f) * 0.15f;
|
||||||
|
ImGui.TextColored(new Vector4(0f, 1f * num2, 0.3f * num2, 1f), duty.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(duty.Name);
|
||||||
|
}
|
||||||
|
if (!ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (ImRaii.Tooltip())
|
||||||
|
{
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudWhite, duty.Name);
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Spacing();
|
||||||
|
string nameAndId = _territoryData.GetNameAndId(duty.TerritoryId);
|
||||||
|
Vector4 col = ImGuiColors.DalamudGrey;
|
||||||
|
ImU8String text = new ImU8String(6, 1);
|
||||||
|
text.AppendLiteral("Zone: ");
|
||||||
|
text.AppendFormatted(nameAndId);
|
||||||
|
ImGui.TextColored(in col, text);
|
||||||
|
DateTime? eventExpiry = duty.EventExpiry;
|
||||||
|
if (eventExpiry.HasValue)
|
||||||
|
{
|
||||||
|
DateTime valueOrDefault = eventExpiry.GetValueOrDefault();
|
||||||
|
TimeSpan timeSpan = EventInfoComponent.NormalizeExpiry(valueOrDefault) - DateTime.UtcNow;
|
||||||
|
if (timeSpan > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
string text2 = EventInfoComponent.FormatRemainingFull(timeSpan);
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudOrange, text2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DrawDutyRowExpiry(SeasonalDutyDefinition duty)
|
||||||
|
{
|
||||||
|
DateTime? eventExpiry = duty.EventExpiry;
|
||||||
|
if (eventExpiry.HasValue)
|
||||||
|
{
|
||||||
|
DateTime valueOrDefault = eventExpiry.GetValueOrDefault();
|
||||||
|
TimeSpan timeSpan = EventInfoComponent.NormalizeExpiry(valueOrDefault) - DateTime.UtcNow;
|
||||||
|
if (timeSpan > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
string text = EventInfoComponent.FormatRemainingDays(timeSpan);
|
||||||
|
ImGui.TextColored((timeSpan.TotalDays < 3.0) ? ImGuiColors.DalamudOrange : ImGuiColors.DalamudGrey, text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudGrey3, "Expired");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudGrey3, "--");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawDutyRowActions(SeasonalDutyDefinition duty, bool disabled)
|
||||||
|
{
|
||||||
|
bool flag = duty.RequiredQuestId.HasValue && !_questFunctions.IsQuestComplete(new QuestId(duty.RequiredQuestId.Value));
|
||||||
|
ImU8String id = new ImU8String(5, 1);
|
||||||
|
id.AppendLiteral("duty_");
|
||||||
|
id.AppendFormatted(duty.Name);
|
||||||
|
using (ImRaii.PushId(id))
|
||||||
|
{
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||||
|
{
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudRed, FontAwesomeIcon.Times.ToIconString());
|
||||||
|
}
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
IQuestInfo questInfo;
|
||||||
|
string value = (_questData.TryGetQuestInfo(new QuestId(duty.RequiredQuestId.Value), out questInfo) ? questInfo.Name : duty.RequiredQuestId.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
ImU8String tooltip = new ImU8String(33, 1);
|
||||||
|
tooltip.AppendLiteral("Requires \"");
|
||||||
|
tooltip.AppendFormatted(value);
|
||||||
|
tooltip.AppendLiteral("\" to be completed first");
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
using (ImRaii.Disabled(disabled))
|
||||||
|
{
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Play))
|
||||||
|
{
|
||||||
|
_questController.Stop("Seasonal duty farming start");
|
||||||
|
_fateController.Stop("Seasonal duty farming start");
|
||||||
|
_movementController.Stop();
|
||||||
|
int? cycleLimit = ((_cycleLimit > 0) ? new int?(_cycleLimit) : ((int?)null));
|
||||||
|
_seasonalDutyController.Start(duty, cycleLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (disabled && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
if (_seasonalDutyController.IsRunning)
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip("Already farming a seasonal duty");
|
||||||
|
}
|
||||||
|
else if (_fateController.IsRunning)
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip("Stop FATE farming first");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.SetTooltip("Stop quest automation first");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatElapsed(TimeSpan elapsed)
|
||||||
|
{
|
||||||
|
IFormatProvider invariantCulture;
|
||||||
|
if (elapsed.TotalHours >= 1.0)
|
||||||
|
{
|
||||||
|
invariantCulture = CultureInfo.InvariantCulture;
|
||||||
|
IFormatProvider provider = invariantCulture;
|
||||||
|
DefaultInterpolatedStringHandler handler = new DefaultInterpolatedStringHandler(5, 3, invariantCulture);
|
||||||
|
handler.AppendFormatted((int)elapsed.TotalHours);
|
||||||
|
handler.AppendLiteral("h ");
|
||||||
|
handler.AppendFormatted(elapsed.Minutes, "D2");
|
||||||
|
handler.AppendLiteral("m ");
|
||||||
|
handler.AppendFormatted(elapsed.Seconds, "D2");
|
||||||
|
handler.AppendLiteral("s");
|
||||||
|
return string.Create(provider, ref handler);
|
||||||
|
}
|
||||||
|
if (elapsed.TotalMinutes >= 1.0)
|
||||||
|
{
|
||||||
|
invariantCulture = CultureInfo.InvariantCulture;
|
||||||
|
IFormatProvider provider2 = invariantCulture;
|
||||||
|
DefaultInterpolatedStringHandler handler2 = new DefaultInterpolatedStringHandler(3, 2, invariantCulture);
|
||||||
|
handler2.AppendFormatted((int)elapsed.TotalMinutes);
|
||||||
|
handler2.AppendLiteral("m ");
|
||||||
|
handler2.AppendFormatted(elapsed.Seconds, "D2");
|
||||||
|
handler2.AppendLiteral("s");
|
||||||
|
return string.Create(provider2, ref handler2);
|
||||||
|
}
|
||||||
|
invariantCulture = CultureInfo.InvariantCulture;
|
||||||
|
IFormatProvider provider3 = invariantCulture;
|
||||||
|
DefaultInterpolatedStringHandler handler3 = new DefaultInterpolatedStringHandler(1, 1, invariantCulture);
|
||||||
|
handler3.AppendFormatted(elapsed.Seconds);
|
||||||
|
handler3.AppendLiteral("s");
|
||||||
|
return string.Create(provider3, ref handler3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -74,6 +74,9 @@
|
||||||
<Reference Include="GatheringPaths">
|
<Reference Include="GatheringPaths">
|
||||||
<HintPath>..\..\GatheringPaths.dll</HintPath>
|
<HintPath>..\..\GatheringPaths.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="SeasonalDutyPaths">
|
||||||
|
<HintPath>..\..\SeasonalDutyPaths.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="JsonPointer.Net">
|
<Reference Include="JsonPointer.Net">
|
||||||
<HintPath>..\..\JsonPointer.Net.dll</HintPath>
|
<HintPath>..\..\JsonPointer.Net.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,20 @@ internal sealed class DalamudInitializer : IDisposable
|
||||||
|
|
||||||
private readonly FateController _fateController;
|
private readonly FateController _fateController;
|
||||||
|
|
||||||
|
private readonly SeasonalDutyController _seasonalDutyController;
|
||||||
|
|
||||||
private readonly PartyWatchdog _partyWatchdog;
|
private readonly PartyWatchdog _partyWatchdog;
|
||||||
|
|
||||||
private readonly ILogger<DalamudInitializer> _logger;
|
private readonly ILogger<DalamudInitializer> _logger;
|
||||||
|
|
||||||
public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework, QuestController questController, MovementController movementController, FateController fateController, WindowSystem windowSystem, OneTimeSetupWindow oneTimeSetupWindow, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow, QuestSelectionWindow questSelectionWindow, QuestSequenceWindow questSequenceWindow, QuestValidationWindow questValidationWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, FateSelectionWindow fateSelectionWindow, ChangelogWindow changelogWindow, IToastGui toastGui, Configuration configuration, PartyWatchdog partyWatchdog, ILogger<DalamudInitializer> logger)
|
public DalamudInitializer(IDalamudPluginInterface pluginInterface, IFramework framework, QuestController questController, MovementController movementController, FateController fateController, SeasonalDutyController seasonalDutyController, WindowSystem windowSystem, OneTimeSetupWindow oneTimeSetupWindow, QuestWindow questWindow, DebugOverlay debugOverlay, ConfigWindow configWindow, QuestSelectionWindow questSelectionWindow, QuestSequenceWindow questSequenceWindow, QuestValidationWindow questValidationWindow, JournalProgressWindow journalProgressWindow, PriorityWindow priorityWindow, FateSelectionWindow fateSelectionWindow, SeasonalDutySelectionWindow seasonalDutySelectionWindow, ChangelogWindow changelogWindow, IToastGui toastGui, Configuration configuration, PartyWatchdog partyWatchdog, ILogger<DalamudInitializer> logger)
|
||||||
{
|
{
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_framework = framework;
|
_framework = framework;
|
||||||
_questController = questController;
|
_questController = questController;
|
||||||
_movementController = movementController;
|
_movementController = movementController;
|
||||||
_fateController = fateController;
|
_fateController = fateController;
|
||||||
|
_seasonalDutyController = seasonalDutyController;
|
||||||
_windowSystem = windowSystem;
|
_windowSystem = windowSystem;
|
||||||
_oneTimeSetupWindow = oneTimeSetupWindow;
|
_oneTimeSetupWindow = oneTimeSetupWindow;
|
||||||
_questWindow = questWindow;
|
_questWindow = questWindow;
|
||||||
|
|
@ -64,6 +67,7 @@ internal sealed class DalamudInitializer : IDisposable
|
||||||
_windowSystem.AddWindow(journalProgressWindow);
|
_windowSystem.AddWindow(journalProgressWindow);
|
||||||
_windowSystem.AddWindow(priorityWindow);
|
_windowSystem.AddWindow(priorityWindow);
|
||||||
_windowSystem.AddWindow(fateSelectionWindow);
|
_windowSystem.AddWindow(fateSelectionWindow);
|
||||||
|
_windowSystem.AddWindow(seasonalDutySelectionWindow);
|
||||||
_windowSystem.AddWindow(changelogWindow);
|
_windowSystem.AddWindow(changelogWindow);
|
||||||
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
_pluginInterface.UiBuilder.Draw += _windowSystem.Draw;
|
||||||
_pluginInterface.UiBuilder.OpenMainUi += ToggleQuestWindow;
|
_pluginInterface.UiBuilder.OpenMainUi += ToggleQuestWindow;
|
||||||
|
|
@ -79,6 +83,7 @@ internal sealed class DalamudInitializer : IDisposable
|
||||||
_partyWatchdog.Update();
|
_partyWatchdog.Update();
|
||||||
_questController.Update();
|
_questController.Update();
|
||||||
_fateController.Update();
|
_fateController.Update();
|
||||||
|
_seasonalDutyController.Update();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_movementController.Update();
|
_movementController.Update();
|
||||||
|
|
@ -87,6 +92,7 @@ internal sealed class DalamudInitializer : IDisposable
|
||||||
{
|
{
|
||||||
_questController.Stop("Pathfinding failed");
|
_questController.Stop("Pathfinding failed");
|
||||||
_fateController.Stop("Pathfinding failed");
|
_fateController.Stop("Pathfinding failed");
|
||||||
|
_seasonalDutyController.Stop("Pathfinding failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,6 +104,8 @@ internal sealed class DalamudInitializer : IDisposable
|
||||||
private void OnErrorToast(ref SeString message, ref bool isHandled)
|
private void OnErrorToast(ref SeString message, ref bool isHandled)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Error Toast: {Message}", message);
|
_logger.LogTrace("Error Toast: {Message}", message);
|
||||||
|
_fateController.OnErrorToast(ref message, ref isHandled);
|
||||||
|
_seasonalDutyController.OnErrorToast(ref message, ref isHandled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnQuestToast(ref SeString message, ref QuestToastOptions options, ref bool isHandled)
|
private void OnQuestToast(ref SeString message, ref QuestToastOptions options, ref bool isHandled)
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin, IDisposable
|
||||||
serviceCollection.AddTaskFactoryAndExecutor<WaitAtStart.WaitDelay, WaitAtStart.Factory, WaitAtStart.WaitDelayExecutor>();
|
serviceCollection.AddTaskFactoryAndExecutor<WaitAtStart.WaitDelay, WaitAtStart.Factory, WaitAtStart.WaitDelayExecutor>();
|
||||||
serviceCollection.AddTaskFactoryAndExecutor<MoveTask, MoveTo.Factory, MoveExecutor>();
|
serviceCollection.AddTaskFactoryAndExecutor<MoveTask, MoveTo.Factory, MoveExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<WaitForNearDataId, WaitForNearDataIdExecutor>();
|
serviceCollection.AddTaskExecutor<WaitForNearDataId, WaitForNearDataIdExecutor>();
|
||||||
|
serviceCollection.AddTaskExecutor<MoveToObject, MoveToObjectExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<LandTask, LandExecutor>();
|
serviceCollection.AddTaskExecutor<LandTask, LandExecutor>();
|
||||||
serviceCollection.AddTaskFactoryAndExecutor<SendNotification.Task, SendNotification.Factory, SendNotification.Executor>();
|
serviceCollection.AddTaskFactoryAndExecutor<SendNotification.Task, SendNotification.Factory, SendNotification.Executor>();
|
||||||
serviceCollection.AddTaskFactoryAndExecutor<NextQuest.SetQuestTask, NextQuest.Factory, NextQuest.NextQuestExecutor>();
|
serviceCollection.AddTaskFactoryAndExecutor<NextQuest.SetQuestTask, NextQuest.Factory, NextQuest.NextQuestExecutor>();
|
||||||
|
|
@ -165,6 +166,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin, IDisposable
|
||||||
serviceCollection.AddTaskFactory<Emote.Factory>();
|
serviceCollection.AddTaskFactory<Emote.Factory>();
|
||||||
serviceCollection.AddTaskExecutor<Emote.UseOnObject, Emote.UseOnObjectExecutor>();
|
serviceCollection.AddTaskExecutor<Emote.UseOnObject, Emote.UseOnObjectExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Emote.UseOnSelf, Emote.UseOnSelfExecutor>();
|
serviceCollection.AddTaskExecutor<Emote.UseOnSelf, Emote.UseOnSelfExecutor>();
|
||||||
|
serviceCollection.AddTaskFactoryAndExecutor<ClearObjectsWithAction.ClearTask, ClearObjectsWithAction.Factory, ClearObjectsWithAction.ClearTaskExecutor>();
|
||||||
serviceCollection.AddTaskFactoryAndExecutor<Questionable.Controller.Steps.Interactions.Action.UseOnObject, Questionable.Controller.Steps.Interactions.Action.Factory, Questionable.Controller.Steps.Interactions.Action.UseOnObjectExecutor>();
|
serviceCollection.AddTaskFactoryAndExecutor<Questionable.Controller.Steps.Interactions.Action.UseOnObject, Questionable.Controller.Steps.Interactions.Action.Factory, Questionable.Controller.Steps.Interactions.Action.UseOnObjectExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Questionable.Controller.Steps.Interactions.Action.UseMudraOnObject, Questionable.Controller.Steps.Interactions.Action.UseMudraOnObjectExecutor>();
|
serviceCollection.AddTaskExecutor<Questionable.Controller.Steps.Interactions.Action.UseMudraOnObject, Questionable.Controller.Steps.Interactions.Action.UseMudraOnObjectExecutor>();
|
||||||
serviceCollection.AddTaskExecutor<Questionable.Controller.Steps.Interactions.Action.TriggerStatusIfMissing, Questionable.Controller.Steps.Interactions.Action.TriggerStatusIfMissingExecutor>();
|
serviceCollection.AddTaskExecutor<Questionable.Controller.Steps.Interactions.Action.TriggerStatusIfMissing, Questionable.Controller.Steps.Interactions.Action.TriggerStatusIfMissingExecutor>();
|
||||||
|
|
@ -221,6 +223,8 @@ public sealed class QuestionablePlugin : IDalamudPlugin, IDisposable
|
||||||
serviceCollection.AddSingleton<CombatController>();
|
serviceCollection.AddSingleton<CombatController>();
|
||||||
serviceCollection.AddSingleton<GatheringController>();
|
serviceCollection.AddSingleton<GatheringController>();
|
||||||
serviceCollection.AddSingleton<FateController>();
|
serviceCollection.AddSingleton<FateController>();
|
||||||
|
serviceCollection.AddSingleton<SeasonalDutyDefinitionRegistry>();
|
||||||
|
serviceCollection.AddSingleton<SeasonalDutyController>();
|
||||||
serviceCollection.AddSingleton<ContextMenuController>();
|
serviceCollection.AddSingleton<ContextMenuController>();
|
||||||
serviceCollection.AddSingleton<ShopController>();
|
serviceCollection.AddSingleton<ShopController>();
|
||||||
serviceCollection.AddSingleton<InterruptHandler>();
|
serviceCollection.AddSingleton<InterruptHandler>();
|
||||||
|
|
@ -273,6 +277,7 @@ public sealed class QuestionablePlugin : IDalamudPlugin, IDisposable
|
||||||
serviceCollection.AddSingleton<JournalProgressWindow>();
|
serviceCollection.AddSingleton<JournalProgressWindow>();
|
||||||
serviceCollection.AddSingleton<PriorityWindow>();
|
serviceCollection.AddSingleton<PriorityWindow>();
|
||||||
serviceCollection.AddSingleton<FateSelectionWindow>();
|
serviceCollection.AddSingleton<FateSelectionWindow>();
|
||||||
|
serviceCollection.AddSingleton<SeasonalDutySelectionWindow>();
|
||||||
serviceCollection.AddSingleton<GeneralConfigComponent>();
|
serviceCollection.AddSingleton<GeneralConfigComponent>();
|
||||||
serviceCollection.AddSingleton<PluginConfigComponent>();
|
serviceCollection.AddSingleton<PluginConfigComponent>();
|
||||||
serviceCollection.AddSingleton<DutyConfigComponent>();
|
serviceCollection.AddSingleton<DutyConfigComponent>();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace System.Text.RegularExpressions.Generated;
|
namespace System.Text.RegularExpressions.Generated;
|
||||||
|
|
||||||
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.7603")]
|
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.15411")]
|
||||||
[SkipLocalsInit]
|
[SkipLocalsInit]
|
||||||
internal sealed class _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0 : Regex
|
internal sealed class _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__MultipleWhitespaceRegex_0 : Regex
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.CodeDom.Compiler;
|
||||||
|
|
||||||
namespace System.Text.RegularExpressions.Generated;
|
namespace System.Text.RegularExpressions.Generated;
|
||||||
|
|
||||||
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.7603")]
|
[GeneratedCode("System.Text.RegularExpressions.Generator", "10.0.14.15411")]
|
||||||
internal static class _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__Utilities
|
internal static class _003CRegexGenerator_g_003EFBB8301322196CF81C64F1652C2FA6E1D6BF3907141F781E9D97ABED51BF056C4__Utilities
|
||||||
{
|
{
|
||||||
internal static readonly TimeSpan s_defaultTimeout = ((AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeSpan) ? timeSpan : Regex.InfiniteMatchTimeout);
|
internal static readonly TimeSpan s_defaultTimeout = ((AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeSpan) ? timeSpan : Regex.InfiniteMatchTimeout);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/SeasonalDutyPaths/seasonaldutydefinition-v1.json",
|
||||||
|
"title": "Seasonal Duty Definition V1",
|
||||||
|
"description": "A seasonal duty farming definition",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"$schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Name": {
|
||||||
|
"description": "Display name of the seasonal duty",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"TerritoryId": {
|
||||||
|
"description": "Territory ID where the NPC is located",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"Aetheryte": {
|
||||||
|
"description": "Nearest aetheryte for teleporting",
|
||||||
|
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-aetheryte.json"
|
||||||
|
},
|
||||||
|
"AethernetShortcut": {
|
||||||
|
"description": "Aethernet shortcut to use after teleporting",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"minItems": 2,
|
||||||
|
"maxItems": 2
|
||||||
|
},
|
||||||
|
"NpcDataId": {
|
||||||
|
"description": "Data ID of the NPC to interact with",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"NpcPosition": {
|
||||||
|
"description": "Position of the NPC",
|
||||||
|
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
|
||||||
|
},
|
||||||
|
"DialogueChoices": {
|
||||||
|
"description": "Dialogue choices when interacting with the NPC to enter the duty",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DutyTerritoryId": {
|
||||||
|
"description": "Territory ID of the duty instance",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"DataIds": {
|
||||||
|
"description": "Data IDs of objects to interact with inside the duty",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"WaypointPositions": {
|
||||||
|
"description": "Waypoint positions to navigate through inside the duty",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "https://github.com/WigglyMuffin/Questionable/raw/refs/heads/main/Questionable.Model/common-vector3.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Action": {
|
||||||
|
"description": "Action to perform on each object",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"StopDistance": {
|
||||||
|
"description": "Distance at which to stop and perform the action",
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"RequiredQuestId": {
|
||||||
|
"description": "Quest ID that must be completed before this duty can be farmed",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"EventExpiry": {
|
||||||
|
"description": "Date and time (in UTC) when the seasonal event ends",
|
||||||
|
"format": "date-time",
|
||||||
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"$schema",
|
||||||
|
"Name",
|
||||||
|
"TerritoryId",
|
||||||
|
"NpcDataId",
|
||||||
|
"NpcPosition",
|
||||||
|
"DutyTerritoryId",
|
||||||
|
"DataIds",
|
||||||
|
"Action"
|
||||||
|
],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Questionable.Model.Common;
|
||||||
|
using Questionable.Model.Questing;
|
||||||
|
|
||||||
|
namespace Questionable.SeasonalDutyPaths;
|
||||||
|
|
||||||
|
public static class AssemblySeasonalDutyDefinitionLoader
|
||||||
|
{
|
||||||
|
private static Dictionary<ushort, SeasonalDutyDefinition>? _definitions;
|
||||||
|
|
||||||
|
public static Stream SeasonalDutyDefinitionSchema => typeof(AssemblySeasonalDutyDefinitionLoader).Assembly.GetManifestResourceStream("Questionable.SeasonalDutyPaths.SeasonalDutyDefinitionSchema");
|
||||||
|
|
||||||
|
public static IReadOnlyDictionary<ushort, SeasonalDutyDefinition> GetDefinitions()
|
||||||
|
{
|
||||||
|
if (_definitions == null)
|
||||||
|
{
|
||||||
|
_definitions = new Dictionary<ushort, SeasonalDutyDefinition>();
|
||||||
|
LoadDefinitions();
|
||||||
|
}
|
||||||
|
return _definitions ?? throw new InvalidOperationException("seasonal duty definition data is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddDefinition(ushort id, SeasonalDutyDefinition definition)
|
||||||
|
{
|
||||||
|
_definitions[id] = definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadDefinitions()
|
||||||
|
{
|
||||||
|
LoadDefinition0();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadDefinition0()
|
||||||
|
{
|
||||||
|
SeasonalDutyDefinition obj = new SeasonalDutyDefinition
|
||||||
|
{
|
||||||
|
Name = "Hatching-tide (2026)",
|
||||||
|
TerritoryId = 133,
|
||||||
|
Aetheryte = EAetheryteLocation.Gridania,
|
||||||
|
AethernetShortcut = new AethernetShortcut
|
||||||
|
{
|
||||||
|
From = EAetheryteLocation.Gridania,
|
||||||
|
To = EAetheryteLocation.GridaniaAmphitheatre
|
||||||
|
},
|
||||||
|
NpcDataId = 1056067u,
|
||||||
|
NpcPosition = new Vector3(-54.551025f, 6.851239f, -110.948364f)
|
||||||
|
};
|
||||||
|
int num = 1;
|
||||||
|
List<DialogueChoice> list = new List<DialogueChoice>(num);
|
||||||
|
CollectionsMarshal.SetCount(list, num);
|
||||||
|
CollectionsMarshal.AsSpan(list)[0] = new DialogueChoice
|
||||||
|
{
|
||||||
|
Type = EDialogChoiceType.List,
|
||||||
|
ExcelSheet = "custom/009/FesEst2026Entrance_00960",
|
||||||
|
Prompt = new ExcelRef("TEXT_FESEST2026ENTRANCE_00960_Q1_000_000"),
|
||||||
|
Answer = new ExcelRef("TEXT_FESEST2026ENTRANCE_00960_A1_000_001"),
|
||||||
|
PromptIsRegularExpression = true
|
||||||
|
};
|
||||||
|
obj.DialogueChoices = list;
|
||||||
|
obj.DutyTerritoryId = 1336;
|
||||||
|
num = 8;
|
||||||
|
List<uint> list2 = new List<uint>(num);
|
||||||
|
CollectionsMarshal.SetCount(list2, num);
|
||||||
|
Span<uint> span = CollectionsMarshal.AsSpan(list2);
|
||||||
|
span[0] = 2015072u;
|
||||||
|
span[1] = 2015073u;
|
||||||
|
span[2] = 2015074u;
|
||||||
|
span[3] = 2015075u;
|
||||||
|
span[4] = 2015076u;
|
||||||
|
span[5] = 2015077u;
|
||||||
|
span[6] = 2015078u;
|
||||||
|
span[7] = 2015079u;
|
||||||
|
obj.DataIds = list2;
|
||||||
|
num = 9;
|
||||||
|
List<Vector3> list3 = new List<Vector3>(num);
|
||||||
|
CollectionsMarshal.SetCount(list3, num);
|
||||||
|
Span<Vector3> span2 = CollectionsMarshal.AsSpan(list3);
|
||||||
|
span2[0] = new Vector3(-700.0023f, -0.15729797f, -721.67926f);
|
||||||
|
span2[1] = new Vector3(-700.1704f, -0.0301615f, 77.54147f);
|
||||||
|
span2[2] = new Vector3(-699.9926f, -0.021064043f, 877.55304f);
|
||||||
|
span2[3] = new Vector3(99.99213f, -0.100738764f, -721.9226f);
|
||||||
|
span2[4] = new Vector3(99.92716f, 4.7683716E-07f, 77.599335f);
|
||||||
|
span2[5] = new Vector3(100.40486f, 0.20596194f, 877.50397f);
|
||||||
|
span2[6] = new Vector3(899.93384f, 0.03615737f, -722.4109f);
|
||||||
|
span2[7] = new Vector3(900.052f, 0.23717809f, 77.897415f);
|
||||||
|
span2[8] = new Vector3(900.26733f, -0.30200624f, 877.5144f);
|
||||||
|
obj.WaypointPositions = list3;
|
||||||
|
obj.Action = EAction.PruningPirouette;
|
||||||
|
obj.RequiredQuestId = (ushort)5425;
|
||||||
|
obj.EventExpiry = new DateTime(2026, 4, 6, 14, 59, 0, DateTimeKind.Utc);
|
||||||
|
AddDefinition(1, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
SeasonalDutyPaths/SeasonalDutyPaths.csproj
Normal file
24
SeasonalDutyPaths/SeasonalDutyPaths.csproj
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<AssemblyName>SeasonalDutyPaths</AssemblyName>
|
||||||
|
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
|
||||||
|
<TargetFramework>netcoreapp1.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<LangVersion>12.0</LangVersion>
|
||||||
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace />
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Questionable.SeasonalDutyPaths.SeasonalDutyDefinitionSchema" />
|
||||||
|
<EmbeddedResource Include="Questionable.SeasonalDutyPaths.SeasonalDutyDefinitionSchema" LogicalName="Questionable.SeasonalDutyPaths.SeasonalDutyDefinitionSchema" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Questionable.Model">
|
||||||
|
<HintPath>..\..\Questionable.Model.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue