using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; using Dalamud.Plugin.Services; using LLib.GameData; using Lumina.Excel.Sheets; using Microsoft.Extensions.Logging; using Questionable.Controller.Utils; using Questionable.Model; using Questionable.Model.Questing; namespace Questionable.Data; internal sealed class QuestData { private sealed record RoleQuestData(IReadOnlyList Chapters, IReadOnlyList FinalQuests, Func JobMatch); public static readonly IReadOnlyList HardModePrimals = new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(1048), new QuestId(1157), new QuestId(1158) }); private static readonly Dictionary GcRankRequirements = new Dictionary { { 1128, 8 }, { 1129, 8 }, { 1130, 8 }, { 1131, 9 }, { 1132, 9 }, { 1133, 9 } }; public static readonly IReadOnlyList CrystalTowerQuests = new global::_003C_003Ez__ReadOnlyArray(new QuestId[8] { new QuestId(1709), new QuestId(1200), new QuestId(1201), new QuestId(1202), new QuestId(1203), new QuestId(1474), new QuestId(494), new QuestId(495) }); public static readonly ImmutableDictionary> AetherCurrentQuestsByTerritory; private static readonly IReadOnlyList TankRoleQuestChapters; private static readonly IReadOnlyList HealerRoleQuestChapters; private static readonly IReadOnlyList MeleeRoleQuestChapters; private static readonly IReadOnlyList PhysicalRangedRoleQuestChapters; private static readonly IReadOnlyList CasterRoleQuestChapters; public static readonly IReadOnlyList> AllRoleQuestChapters; public static readonly IReadOnlyList FinalShadowbringersRoleQuests; private static readonly RoleQuestData TankData; private static readonly RoleQuestData HealerData; private static readonly RoleQuestData MeleeData; private static readonly RoleQuestData PhysicalRangedData; private static readonly RoleQuestData CasterData; private static readonly Dictionary RoleDataByPreference; private static readonly IReadOnlyList AllRoleData; private readonly ConcurrentDictionary _quests; private readonly ILogger _logger; private static byte _cachedFirstClass; private static List _cachedLockedClassQuests; public static ImmutableHashSet AetherCurrentQuests { get; } public IReadOnlyList MainScenarioQuests { get; } public ImmutableHashSet RedeemableItems { get; } public QuestId LastMainScenarioQuestId { get; } public IReadOnlyDictionary AllQuests => _quests; public static byte GetRequiredGCRank(QuestId questId) { return GcRankRequirements.GetValueOrDefault(questId.Value, 1); } public QuestData(IDataManager dataManager, ILogger logger) { _logger = logger ?? throw new ArgumentNullException("logger"); Dictionary questChapters = (from x in dataManager.GetExcelSheet() where x.RowId != 0 && x.Quest.RowId != 0 select x).ToDictionary((QuestChapter x) => x.Quest.RowId, (QuestChapter x) => x.Redo.RowId); Dictionary startingCities = new Dictionary(); for (byte b = 1; b <= 3; b++) { foreach (QuestRedo.QuestRedoParamStruct item in dataManager.GetExcelSheet().GetRow(b).QuestRedoParam.Where((QuestRedo.QuestRedoParamStruct x) => x.Quest.IsValid)) { startingCities[item.Quest.RowId] = b; } } List list = ((IEnumerable)(from x in dataManager.GetExcelSheet() where x.RowId != 0 where !x.Name.IsEmpty where x.IssuerLocation.RowId != 0 select new QuestInfo(x, questChapters.GetValueOrDefault(x.RowId), startingCities.GetValueOrDefault(x.RowId)))).ToList(); _quests = new ConcurrentDictionary(); foreach (IQuestInfo item2 in list) { if (!_quests.TryAdd(item2.QuestId, item2)) { _logger.LogDebug("Duplicate QuestId {QuestId}, keeping first entry", item2.QuestId); } } AddPreviousQuest(425, 495); AddPreviousQuest(1480, 2373); AddPreviousQuest(1717, 1619); AddPreviousQuest(2088, 1619); AddPreviousQuest(2062, 1617); AddPreviousQuest(2063, 1619); AddPreviousQuest(2257, 1655); AddPreviousQuest(2608, 2534); AddPreviousQuest(2600, 2466); AddPreviousQuest(2622, 2490); AddPreviousQuest(2624, 2534); AddPreviousQuest(2898, 2490); AddPreviousQuest(2974, 2491); AddPreviousQuest(2975, 2630); AddPreviousQuest(2912, 2490); AddPreviousQuest(2914, 2537); AddPreviousQuest(2919, 2455); AddPreviousQuest(2952, 2518); AddPreviousQuest(2904, 2503); AddPreviousQuest(3038, 2534); AddPreviousQuest(3087, 100); AddPreviousQuest(3246, 3314); AddPreviousQuest(3247, 3320); AddPreviousQuest(3270, 3333); AddPreviousQuest(3271, 3634); AddPreviousQuest(3264, 2247); AddPreviousQuest(3253, 2247); AddPreviousQuest(3254, 2537); AddPreviousQuest(3228, 3320); AddPreviousQuest(3234, 3320); AddPreviousQuest(3237, 3320); AddPreviousQuest(3238, 3634); AddPreviousQuest(3240, 3320); AddPreviousQuest(3241, 3648); AddPreviousQuest(3628, 3301); AddPreviousQuest(3655, 2095); AddPreviousQuest(3771, 495); AddPreviousQuest(4068, 1658); AddPreviousQuest(4078, 1583); AddPreviousQuest(4150, 4417); AddPreviousQuest(4155, 4383); AddPreviousQuest(4156, 3326); AddPreviousQuest(4158, 4434); AddPreviousQuest(4159, 4464); AddPreviousQuest(4163, 4398); AddPreviousQuest(4165, 4438); AddPreviousQuest(4473, 2095); AddPreviousQuest(4650, 2374); AddPreviousQuest(4662, 3166); AddPreviousQuest(4761, 4032); AddPreviousQuest(4812, 4750); AddPreviousQuest(4851, 2446); AddPreviousQuest(4856, 1669); AddPreviousQuest(4857, 2553); AddPreviousQuest(4979, 4896); AddPreviousQuest(4980, 4911); AddPreviousQuest(4985, 4903); AddPreviousQuest(4987, 4912); AddPreviousQuest(4988, 4942); AddPreviousQuest(4992, 4912); AddPreviousQuest(4999, 4908); AddPreviousQuest(4966, 2095); AddPreviousQuest(5000, 4908); AddPreviousQuest(5001, 4912); AddPreviousQuest(3629, 3248); AddPreviousQuest(3629, 3272); AddPreviousQuest(3629, 3278); AddPreviousQuest(3629, 3628); AddPreviousQuest(3986, 2115); AddPreviousQuest(3986, 2116); AddPreviousQuest(3986, 2281); AddPreviousQuest(3986, 2333); AddPreviousQuest(3986, 2395); AddPreviousQuest(3986, 3985); AddPreviousQuest(5188, 4841); AddPreviousQuest(5188, 4847); AddPreviousQuest(5188, 4959); ushort[] array = new ushort[20] { 107, 111, 112, 122, 663, 475, 472, 476, 470, 473, 474, 477, 486, 478, 479, 59, 400, 401, 693, 405 }; foreach (ushort questId in array) { SetStartingCity(questId, 1); } array = new ushort[11] { 39, 1, 32, 34, 37, 172, 127, 130, 60, 220, 378 }; foreach (ushort questId2 in array) { SetStartingCity(questId2, 2); } array = new ushort[19] { 594, 389, 390, 321, 304, 322, 388, 308, 326, 58, 687, 341, 504, 531, 506, 530, 573, 342, 505 }; foreach (ushort questId3 in array) { SetStartingCity(questId3, 3); } AddGcFollowUpQuests(); MainScenarioQuests = _quests.Values.Where((IQuestInfo x) => x is QuestInfo questInfo && questInfo.IsMainScenarioQuest).Cast().ToList(); LastMainScenarioQuestId = (from x in MainScenarioQuests where !MainScenarioQuests.Any((QuestInfo y) => y.PreviousQuests.Any((PreviousQuestInfo z) => z.QuestId == x.QuestId)) select (QuestId)x.QuestId).FirstOrDefault() ?? new QuestId(0); RedeemableItems = list.Where((IQuestInfo x) => x is QuestInfo).Cast().SelectMany((QuestInfo x) => x.ItemRewards) .ToImmutableHashSet(); } private void AddPreviousQuest(ushort questToUpdate, ushort requiredQuestId) { QuestId questId = new QuestId(questToUpdate); if (_quests.TryGetValue(questId, out IQuestInfo value) && value is QuestInfo questInfo) { questInfo.AddPreviousQuest(new PreviousQuestInfo(new QuestId(requiredQuestId), 0)); return; } _logger.LogWarning("AddPreviousQuest: Quest {QuestId} not found or not a QuestInfo", questId); } private void SetStartingCity(ushort questId, byte startingCity) { QuestId questId2 = new QuestId(questId); if (_quests.TryGetValue(questId2, out IQuestInfo value) && value is QuestInfo questInfo) { questInfo.StartingCity = startingCity; return; } _logger.LogWarning("SetStartingCity: Quest {QuestId} not found or not a QuestInfo", questId2); } private void AddGcFollowUpQuests() { ushort[] array = new ushort[3] { 683, 684, 685 }; ushort[] array2 = array; foreach (ushort questId in array2) { QuestId questId2 = new QuestId(questId); if (_quests.TryGetValue(questId2, out IQuestInfo value) && value is QuestInfo questInfo) { questInfo.AddQuestLocks(EQuestJoin.AtLeastOne, (from x in array where x != questId select new QuestId(x)).ToArray()); } else { _logger.LogWarning("AddGcFollowUpQuests: Quest {QuestId} not found or not a QuestInfo", questId2); } } } public IQuestInfo GetQuestInfo(ElementId elementId) { return _quests[elementId]; } public bool TryGetQuestInfo(ElementId elementId, [NotNullWhen(true)] out IQuestInfo? questInfo) { return _quests.TryGetValue(elementId, out questInfo); } public List GetAllByIssuerDataId(uint targetId) { return _quests.Values.Where((IQuestInfo x) => x.IssuerDataId == targetId).ToList(); } public bool IsIssuerOfAnyQuest(uint targetId) { return _quests.Values.Any((IQuestInfo x) => x.IssuerDataId == targetId); } public List GetAllByJournalGenre(uint journalGenre) { return (from x in _quests.Values where x.JournalGenre == journalGenre orderby x.SortKey, x.QuestId select x).ToList(); } public List GetAllByAlliedSociety(EAlliedSociety alliedSociety) { return (from QuestInfo x in _quests.Values.Where((IQuestInfo x) => x is QuestInfo) where x.AlliedSociety == alliedSociety orderby x.QuestId select x).ToList(); } public List GetClassJobQuests(EClassJob classJob, bool includeRoleQuests = false) { List list2; switch (classJob) { case EClassJob.Adventurer: throw new ArgumentOutOfRangeException("classJob"); case EClassJob.Gladiator: { int num = 1; List list43 = new List(num); CollectionsMarshal.SetCount(list43, num); CollectionsMarshal.AsSpan(list43)[0] = 63u; list2 = list43; break; } case EClassJob.Paladin: { int num = 3; List list42 = new List(num); CollectionsMarshal.SetCount(list42, num); Span span27 = CollectionsMarshal.AsSpan(list42); span27[0] = 72u; span27[1] = 73u; span27[2] = 74u; list2 = list42; break; } case EClassJob.Marauder: { int num = 1; List list41 = new List(num); CollectionsMarshal.SetCount(list41, num); CollectionsMarshal.AsSpan(list41)[0] = 64u; list2 = list41; break; } case EClassJob.Warrior: { int num = 3; List list40 = new List(num); CollectionsMarshal.SetCount(list40, num); Span span26 = CollectionsMarshal.AsSpan(list40); span26[0] = 76u; span26[1] = 77u; span26[2] = 78u; list2 = list40; break; } case EClassJob.Conjurer: { int num = 1; List list39 = new List(num); CollectionsMarshal.SetCount(list39, num); CollectionsMarshal.AsSpan(list39)[0] = 65u; list2 = list39; break; } case EClassJob.WhiteMage: { int num = 3; List list38 = new List(num); CollectionsMarshal.SetCount(list38, num); Span span25 = CollectionsMarshal.AsSpan(list38); span25[0] = 86u; span25[1] = 87u; span25[2] = 88u; list2 = list38; break; } case EClassJob.Arcanist: { int num = 1; List list37 = new List(num); CollectionsMarshal.SetCount(list37, num); CollectionsMarshal.AsSpan(list37)[0] = 66u; list2 = list37; break; } case EClassJob.Summoner: { int num = 3; List list36 = new List(num); CollectionsMarshal.SetCount(list36, num); Span span24 = CollectionsMarshal.AsSpan(list36); span24[0] = 127u; span24[1] = 128u; span24[2] = 129u; list2 = list36; break; } case EClassJob.Scholar: { int num = 3; List list35 = new List(num); CollectionsMarshal.SetCount(list35, num); Span span23 = CollectionsMarshal.AsSpan(list35); span23[0] = 90u; span23[1] = 91u; span23[2] = 92u; list2 = list35; break; } case EClassJob.Pugilist: { int num = 1; List list34 = new List(num); CollectionsMarshal.SetCount(list34, num); CollectionsMarshal.AsSpan(list34)[0] = 67u; list2 = list34; break; } case EClassJob.Monk: { int num = 3; List list33 = new List(num); CollectionsMarshal.SetCount(list33, num); Span span22 = CollectionsMarshal.AsSpan(list33); span22[0] = 98u; span22[1] = 99u; span22[2] = 100u; list2 = list33; break; } case EClassJob.Lancer: { int num = 1; List list32 = new List(num); CollectionsMarshal.SetCount(list32, num); CollectionsMarshal.AsSpan(list32)[0] = 68u; list2 = list32; break; } case EClassJob.Dragoon: { int num = 3; List list31 = new List(num); CollectionsMarshal.SetCount(list31, num); Span span21 = CollectionsMarshal.AsSpan(list31); span21[0] = 102u; span21[1] = 103u; span21[2] = 104u; list2 = list31; break; } case EClassJob.Rogue: { int num = 1; List list30 = new List(num); CollectionsMarshal.SetCount(list30, num); CollectionsMarshal.AsSpan(list30)[0] = 69u; list2 = list30; break; } case EClassJob.Ninja: { int num = 3; List list29 = new List(num); CollectionsMarshal.SetCount(list29, num); Span span20 = CollectionsMarshal.AsSpan(list29); span20[0] = 106u; span20[1] = 107u; span20[2] = 108u; list2 = list29; break; } case EClassJob.Archer: { int num = 1; List list28 = new List(num); CollectionsMarshal.SetCount(list28, num); CollectionsMarshal.AsSpan(list28)[0] = 70u; list2 = list28; break; } case EClassJob.Bard: { int num = 3; List list27 = new List(num); CollectionsMarshal.SetCount(list27, num); Span span19 = CollectionsMarshal.AsSpan(list27); span19[0] = 113u; span19[1] = 114u; span19[2] = 115u; list2 = list27; break; } case EClassJob.Thaumaturge: { int num = 1; List list26 = new List(num); CollectionsMarshal.SetCount(list26, num); CollectionsMarshal.AsSpan(list26)[0] = 71u; list2 = list26; break; } case EClassJob.BlackMage: { int num = 3; List list25 = new List(num); CollectionsMarshal.SetCount(list25, num); Span span18 = CollectionsMarshal.AsSpan(list25); span18[0] = 123u; span18[1] = 124u; span18[2] = 125u; list2 = list25; break; } case EClassJob.DarkKnight: { int num = 3; List list24 = new List(num); CollectionsMarshal.SetCount(list24, num); Span span17 = CollectionsMarshal.AsSpan(list24); span17[0] = 80u; span17[1] = 81u; span17[2] = 82u; list2 = list24; break; } case EClassJob.Astrologian: { int num = 3; List list23 = new List(num); CollectionsMarshal.SetCount(list23, num); Span span16 = CollectionsMarshal.AsSpan(list23); span16[0] = 94u; span16[1] = 95u; span16[2] = 96u; list2 = list23; break; } case EClassJob.Machinist: { int num = 3; List list22 = new List(num); CollectionsMarshal.SetCount(list22, num); Span span15 = CollectionsMarshal.AsSpan(list22); span15[0] = 117u; span15[1] = 118u; span15[2] = 119u; list2 = list22; break; } case EClassJob.Samurai: { int num = 2; List list21 = new List(num); CollectionsMarshal.SetCount(list21, num); Span span14 = CollectionsMarshal.AsSpan(list21); span14[0] = 110u; span14[1] = 111u; list2 = list21; break; } case EClassJob.RedMage: { int num = 2; List list20 = new List(num); CollectionsMarshal.SetCount(list20, num); Span span13 = CollectionsMarshal.AsSpan(list20); span13[0] = 131u; span13[1] = 132u; list2 = list20; break; } case EClassJob.BlueMage: { int num = 4; List list19 = new List(num); CollectionsMarshal.SetCount(list19, num); Span span12 = CollectionsMarshal.AsSpan(list19); span12[0] = 134u; span12[1] = 135u; span12[2] = 146u; span12[3] = 170u; list2 = list19; break; } case EClassJob.Gunbreaker: { int num = 1; List list18 = new List(num); CollectionsMarshal.SetCount(list18, num); CollectionsMarshal.AsSpan(list18)[0] = 84u; list2 = list18; break; } case EClassJob.Dancer: { int num = 1; List list17 = new List(num); CollectionsMarshal.SetCount(list17, num); CollectionsMarshal.AsSpan(list17)[0] = 121u; list2 = list17; break; } case EClassJob.Sage: { int num = 1; List list16 = new List(num); CollectionsMarshal.SetCount(list16, num); CollectionsMarshal.AsSpan(list16)[0] = 152u; list2 = list16; break; } case EClassJob.Reaper: { int num = 1; List list15 = new List(num); CollectionsMarshal.SetCount(list15, num); CollectionsMarshal.AsSpan(list15)[0] = 153u; list2 = list15; break; } case EClassJob.Viper: { int num = 1; List list14 = new List(num); CollectionsMarshal.SetCount(list14, num); CollectionsMarshal.AsSpan(list14)[0] = 176u; list2 = list14; break; } case EClassJob.Pictomancer: { int num = 1; List list13 = new List(num); CollectionsMarshal.SetCount(list13, num); CollectionsMarshal.AsSpan(list13)[0] = 177u; list2 = list13; break; } case EClassJob.Beastmaster: list2 = new List(); break; case EClassJob.Alchemist: { int num = 3; List list12 = new List(num); CollectionsMarshal.SetCount(list12, num); Span span11 = CollectionsMarshal.AsSpan(list12); span11[0] = 48u; span11[1] = 49u; span11[2] = 50u; list2 = list12; break; } case EClassJob.Armorer: { int num = 3; List list11 = new List(num); CollectionsMarshal.SetCount(list11, num); Span span10 = CollectionsMarshal.AsSpan(list11); span10[0] = 36u; span10[1] = 37u; span10[2] = 38u; list2 = list11; break; } case EClassJob.Blacksmith: { int num = 3; List list10 = new List(num); CollectionsMarshal.SetCount(list10, num); Span span9 = CollectionsMarshal.AsSpan(list10); span9[0] = 33u; span9[1] = 34u; span9[2] = 35u; list2 = list10; break; } case EClassJob.Carpenter: { int num = 3; List list9 = new List(num); CollectionsMarshal.SetCount(list9, num); Span span8 = CollectionsMarshal.AsSpan(list9); span8[0] = 30u; span8[1] = 31u; span8[2] = 32u; list2 = list9; break; } case EClassJob.Culinarian: { int num = 3; List list8 = new List(num); CollectionsMarshal.SetCount(list8, num); Span span7 = CollectionsMarshal.AsSpan(list8); span7[0] = 51u; span7[1] = 52u; span7[2] = 53u; list2 = list8; break; } case EClassJob.Goldsmith: { int num = 3; List list7 = new List(num); CollectionsMarshal.SetCount(list7, num); Span span6 = CollectionsMarshal.AsSpan(list7); span6[0] = 39u; span6[1] = 40u; span6[2] = 41u; list2 = list7; break; } case EClassJob.Leatherworker: { int num = 3; List list6 = new List(num); CollectionsMarshal.SetCount(list6, num); Span span5 = CollectionsMarshal.AsSpan(list6); span5[0] = 42u; span5[1] = 43u; span5[2] = 44u; list2 = list6; break; } case EClassJob.Weaver: { int num = 3; List list5 = new List(num); CollectionsMarshal.SetCount(list5, num); Span span4 = CollectionsMarshal.AsSpan(list5); span4[0] = 45u; span4[1] = 46u; span4[2] = 47u; list2 = list5; break; } case EClassJob.Miner: { int num = 3; List list4 = new List(num); CollectionsMarshal.SetCount(list4, num); Span span3 = CollectionsMarshal.AsSpan(list4); span3[0] = 54u; span3[1] = 55u; span3[2] = 56u; list2 = list4; break; } case EClassJob.Botanist: { int num = 3; List list3 = new List(num); CollectionsMarshal.SetCount(list3, num); Span span2 = CollectionsMarshal.AsSpan(list3); span2[0] = 57u; span2[1] = 58u; span2[2] = 59u; list2 = list3; break; } case EClassJob.Fisher: { int num = 3; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = 60u; span[1] = 61u; span[2] = 62u; list2 = list; break; } default: throw new ArgumentOutOfRangeException("classJob"); } List list44 = list2; if (includeRoleQuests) { list44.AddRange(GetRoleQuestIds(classJob)); } return GetQuestsInNewGamePlusChapters(list44); } public List GetRoleQuests(EClassJob referenceClassJob) { return GetQuestsInNewGamePlusChapters(GetRoleQuestIds(referenceClassJob).ToList()); } public List GetRoleQuestsByChapter(uint chapterId) { int num = 1; List list = new List(num); CollectionsMarshal.SetCount(list, num); CollectionsMarshal.AsSpan(list)[0] = chapterId; return GetQuestsInNewGamePlusChapters(list); } private static IEnumerable GetRoleQuestIds(EClassJob classJob) { return ResolveRoleDataForJob(classJob)?.Chapters ?? Array.Empty(); } public static IReadOnlyList GetFinalRoleQuests(ERoleQuestPreference preference, EClassJob currentJob) { return ResolveRoleData(preference, currentJob)?.FinalQuests ?? Array.Empty(); } public static IReadOnlyList GetRoleQuestChaptersForPreference(ERoleQuestPreference preference, EClassJob currentJob) { return ResolveRoleData(preference, currentJob)?.Chapters ?? Array.Empty(); } public static bool JobMatchesRolePreference(ERoleQuestPreference preference, EClassJob classJob) { if (preference == ERoleQuestPreference.Default) { return true; } if (RoleDataByPreference.TryGetValue(preference, out RoleQuestData value)) { return value.JobMatch(classJob); } return false; } private static RoleQuestData? ResolveRoleData(ERoleQuestPreference preference, EClassJob currentJob) { if (preference != ERoleQuestPreference.Default && RoleDataByPreference.TryGetValue(preference, out RoleQuestData value)) { return value; } return ResolveRoleDataForJob(currentJob); } private static RoleQuestData? ResolveRoleDataForJob(EClassJob classJob) { return AllRoleData.FirstOrDefault((RoleQuestData d) => d.JobMatch(classJob)); } private List GetQuestsInNewGamePlusChapters(List chapterIds) { return (from QuestInfo x in _quests.Values.Where((IQuestInfo x) => x is QuestInfo) where chapterIds.Contains(x.NewGamePlusChapter) select x).ToList(); } public static List GetLockedClassQuests() { byte firstClass = PlayerStateHelper.GetFirstClass(); if (firstClass == _cachedFirstClass && _cachedLockedClassQuests.Count > 0) { return _cachedLockedClassQuests; } EClassJob eClassJob = (EClassJob)((firstClass != 0) ? firstClass : 0); if (eClassJob == EClassJob.Adventurer) { return new List(); } int num = 8; List> list = new List>(num); CollectionsMarshal.SetCount(list, num); Span> span = CollectionsMarshal.AsSpan(list); ref List reference = ref span[0]; List list2; if (eClassJob != EClassJob.Gladiator) { int num2 = 2; list2 = new List(num2); CollectionsMarshal.SetCount(list2, num2); Span span2 = CollectionsMarshal.AsSpan(list2); span2[0] = 253; span2[1] = 261; } else { int num2 = 4; list2 = new List(num2); CollectionsMarshal.SetCount(list2, num2); Span span3 = CollectionsMarshal.AsSpan(list2); span3[0] = 177; span3[1] = 285; span3[2] = 286; span3[3] = 288; } reference = list2; ref List reference2 = ref span[1]; List list3; if (eClassJob != EClassJob.Pugilist) { int num2 = 2; list3 = new List(num2); CollectionsMarshal.SetCount(list3, num2); Span span4 = CollectionsMarshal.AsSpan(list3); span4[0] = 533; span4[1] = 555; } else { int num2 = 4; list3 = new List(num2); CollectionsMarshal.SetCount(list3, num2); Span span5 = CollectionsMarshal.AsSpan(list3); span5[0] = 178; span5[1] = 532; span5[2] = 553; span5[3] = 698; } reference2 = list3; ref List reference3 = ref span[2]; List list4; if (eClassJob != EClassJob.Marauder) { int num2 = 2; list4 = new List(num2); CollectionsMarshal.SetCount(list4, num2); Span span6 = CollectionsMarshal.AsSpan(list4); span6[0] = 311; span6[1] = 314; } else { int num2 = 4; list4 = new List(num2); CollectionsMarshal.SetCount(list4, num2); Span span7 = CollectionsMarshal.AsSpan(list4); span7[0] = 179; span7[1] = 310; span7[2] = 312; span7[3] = 315; } reference3 = list4; ref List reference4 = ref span[3]; List list5; if (eClassJob != EClassJob.Lancer) { int num2 = 2; list5 = new List(num2); CollectionsMarshal.SetCount(list5, num2); Span span8 = CollectionsMarshal.AsSpan(list5); span8[0] = 23; span8[1] = 35; } else { int num2 = 4; list5 = new List(num2); CollectionsMarshal.SetCount(list5, num2); Span span9 = CollectionsMarshal.AsSpan(list5); span9[0] = 180; span9[1] = 132; span9[2] = 218; span9[3] = 143; } reference4 = list5; ref List reference5 = ref span[4]; List list6; if (eClassJob != EClassJob.Archer) { int num2 = 2; list6 = new List(num2); CollectionsMarshal.SetCount(list6, num2); Span span10 = CollectionsMarshal.AsSpan(list6); span10[0] = 21; span10[1] = 67; } else { int num2 = 4; list6 = new List(num2); CollectionsMarshal.SetCount(list6, num2); Span span11 = CollectionsMarshal.AsSpan(list6); span11[0] = 181; span11[1] = 131; span11[2] = 219; span11[3] = 134; } reference5 = list6; ref List reference6 = ref span[5]; List list7; if (eClassJob != EClassJob.Conjurer) { int num2 = 2; list7 = new List(num2); CollectionsMarshal.SetCount(list7, num2); Span span12 = CollectionsMarshal.AsSpan(list7); span12[0] = 22; span12[1] = 91; } else { int num2 = 4; list7 = new List(num2); CollectionsMarshal.SetCount(list7, num2); Span span13 = CollectionsMarshal.AsSpan(list7); span13[0] = 182; span13[1] = 133; span13[2] = 211; span13[3] = 147; } reference6 = list7; ref List reference7 = ref span[6]; List list8; if (eClassJob != EClassJob.Thaumaturge) { int num2 = 2; list8 = new List(num2); CollectionsMarshal.SetCount(list8, num2); Span span14 = CollectionsMarshal.AsSpan(list8); span14[0] = 345; span14[1] = 348; } else { int num2 = 4; list8 = new List(num2); CollectionsMarshal.SetCount(list8, num2); Span span15 = CollectionsMarshal.AsSpan(list8); span15[0] = 183; span15[1] = 344; span15[2] = 346; span15[3] = 349; } reference7 = list8; ref List reference8 = ref span[7]; List list9; if (eClassJob != EClassJob.Arcanist) { int num2 = 2; list9 = new List(num2); CollectionsMarshal.SetCount(list9, num2); Span span16 = CollectionsMarshal.AsSpan(list9); span16[0] = 453; span16[1] = 456; } else { int num2 = 4; list9 = new List(num2); CollectionsMarshal.SetCount(list9, num2); Span span17 = CollectionsMarshal.AsSpan(list9); span17[0] = 451; span17[1] = 452; span17[2] = 454; span17[3] = 457; } reference8 = list9; _cachedFirstClass = firstClass; _cachedLockedClassQuests = (from x in list.SelectMany((List x) => x) select new QuestId(x)).ToList(); return _cachedLockedClassQuests; } public void ApplySeasonalOverride(ElementId questId, bool isSeasonal, DateTime? expiry) { if (_quests.TryGetValue(questId, out IQuestInfo value) && value is QuestInfo questInfo) { DateTime? seasonalQuestExpiry = (expiry.HasValue ? new DateTime?(ExpiryUtils.NormalizeExpiry(expiry.Value)) : ((DateTime?)null)); questInfo.IsSeasonalQuest = isSeasonal; questInfo.SeasonalQuestExpiry = seasonalQuestExpiry; } else if (value is UnlockLinkQuestInfo) { _logger.LogDebug("ApplySeasonalOverride: Quest {QuestId} is UnlockLinkQuestInfo (expiry handled at construction)", questId); } else if (value != null) { _logger.LogDebug("ApplySeasonalOverride: Quest {QuestId} is {Type}, seasonal override not applicable", questId, value.GetType().Name); } else { _logger.LogWarning("ApplySeasonalOverride: Quest {QuestId} not found in QuestData", questId); } } public void AddOrReplaceQuestInfo(IQuestInfo info) { ArgumentNullException.ThrowIfNull(info, "info"); _quests[info.QuestId] = info; _logger.LogDebug("Added or replaced QuestInfo for {QuestId} in QuestData", info.QuestId); } static QuestData() { Dictionary> dictionary = new Dictionary>(); int num = 4; List list = new List(num); CollectionsMarshal.SetCount(list, num); Span span = CollectionsMarshal.AsSpan(list); span[0] = 1744; span[1] = 1759; span[2] = 1760; span[3] = 2111; dictionary.Add(397u, list); num = 4; List list2 = new List(num); CollectionsMarshal.SetCount(list2, num); Span span2 = CollectionsMarshal.AsSpan(list2); span2[0] = 1771; span2[1] = 1790; span2[2] = 1797; span2[3] = 1802; dictionary.Add(398u, list2); num = 4; List list3 = new List(num); CollectionsMarshal.SetCount(list3, num); Span span3 = CollectionsMarshal.AsSpan(list3); span3[0] = 1936; span3[1] = 1945; span3[2] = 1963; span3[3] = 1966; dictionary.Add(399u, list3); num = 4; List list4 = new List(num); CollectionsMarshal.SetCount(list4, num); Span span4 = CollectionsMarshal.AsSpan(list4); span4[0] = 1819; span4[1] = 1823; span4[2] = 1828; span4[3] = 1835; dictionary.Add(400u, list4); num = 4; List list5 = new List(num); CollectionsMarshal.SetCount(list5, num); Span span5 = CollectionsMarshal.AsSpan(list5); span5[0] = 1748; span5[1] = 1874; span5[2] = 1909; span5[3] = 1910; dictionary.Add(401u, list5); num = 4; List list6 = new List(num); CollectionsMarshal.SetCount(list6, num); Span span6 = CollectionsMarshal.AsSpan(list6); span6[0] = 2639; span6[1] = 2661; span6[2] = 2816; span6[3] = 2821; dictionary.Add(612u, list6); num = 4; List list7 = new List(num); CollectionsMarshal.SetCount(list7, num); Span span7 = CollectionsMarshal.AsSpan(list7); span7[0] = 2632; span7[1] = 2673; span7[2] = 2687; span7[3] = 2693; dictionary.Add(613u, list7); num = 4; List list8 = new List(num); CollectionsMarshal.SetCount(list8, num); Span span8 = CollectionsMarshal.AsSpan(list8); span8[0] = 2724; span8[1] = 2728; span8[2] = 2730; span8[3] = 2733; dictionary.Add(614u, list8); num = 4; List list9 = new List(num); CollectionsMarshal.SetCount(list9, num); Span span9 = CollectionsMarshal.AsSpan(list9); span9[0] = 2655; span9[1] = 2842; span9[2] = 2851; span9[3] = 2860; dictionary.Add(620u, list9); num = 4; List list10 = new List(num); CollectionsMarshal.SetCount(list10, num); Span span10 = CollectionsMarshal.AsSpan(list10); span10[0] = 2877; span10[1] = 2880; span10[2] = 2881; span10[3] = 2883; dictionary.Add(621u, list10); num = 4; List list11 = new List(num); CollectionsMarshal.SetCount(list11, num); Span span11 = CollectionsMarshal.AsSpan(list11); span11[0] = 2760; span11[1] = 2771; span11[2] = 2782; span11[3] = 2791; dictionary.Add(622u, list11); num = 4; List list12 = new List(num); CollectionsMarshal.SetCount(list12, num); Span span12 = CollectionsMarshal.AsSpan(list12); span12[0] = 3380; span12[1] = 3384; span12[2] = 3385; span12[3] = 3386; dictionary.Add(813u, list12); num = 4; List list13 = new List(num); CollectionsMarshal.SetCount(list13, num); Span span13 = CollectionsMarshal.AsSpan(list13); span13[0] = 3360; span13[1] = 3371; span13[2] = 3537; span13[3] = 3556; dictionary.Add(814u, list13); num = 4; List list14 = new List(num); CollectionsMarshal.SetCount(list14, num); Span span14 = CollectionsMarshal.AsSpan(list14); span14[0] = 3375; span14[1] = 3503; span14[2] = 3511; span14[3] = 3525; dictionary.Add(815u, list14); num = 4; List list15 = new List(num); CollectionsMarshal.SetCount(list15, num); Span span15 = CollectionsMarshal.AsSpan(list15); span15[0] = 3395; span15[1] = 3398; span15[2] = 3404; span15[3] = 3427; dictionary.Add(816u, list15); num = 4; List list16 = new List(num); CollectionsMarshal.SetCount(list16, num); Span span16 = CollectionsMarshal.AsSpan(list16); span16[0] = 3444; span16[1] = 3467; span16[2] = 3478; span16[3] = 3656; dictionary.Add(817u, list16); num = 4; List list17 = new List(num); CollectionsMarshal.SetCount(list17, num); Span span17 = CollectionsMarshal.AsSpan(list17); span17[0] = 3588; span17[1] = 3592; span17[2] = 3593; span17[3] = 3594; dictionary.Add(818u, list17); num = 4; List list18 = new List(num); CollectionsMarshal.SetCount(list18, num); Span span18 = CollectionsMarshal.AsSpan(list18); span18[0] = 4320; span18[1] = 4329; span18[2] = 4480; span18[3] = 4484; dictionary.Add(956u, list18); num = 4; List list19 = new List(num); CollectionsMarshal.SetCount(list19, num); Span span19 = CollectionsMarshal.AsSpan(list19); span19[0] = 4203; span19[1] = 4257; span19[2] = 4259; span19[3] = 4489; dictionary.Add(957u, list19); num = 4; List list20 = new List(num); CollectionsMarshal.SetCount(list20, num); Span span20 = CollectionsMarshal.AsSpan(list20); span20[0] = 4216; span20[1] = 4232; span20[2] = 4498; span20[3] = 4502; dictionary.Add(958u, list20); num = 4; List list21 = new List(num); CollectionsMarshal.SetCount(list21, num); Span span21 = CollectionsMarshal.AsSpan(list21); span21[0] = 4240; span21[1] = 4241; span21[2] = 4253; span21[3] = 4516; dictionary.Add(959u, list21); num = 4; List list22 = new List(num); CollectionsMarshal.SetCount(list22, num); Span span22 = CollectionsMarshal.AsSpan(list22); span22[0] = 4342; span22[1] = 4346; span22[2] = 4354; span22[3] = 4355; dictionary.Add(960u, list22); num = 4; List list23 = new List(num); CollectionsMarshal.SetCount(list23, num); Span span23 = CollectionsMarshal.AsSpan(list23); span23[0] = 4288; span23[1] = 4313; span23[2] = 4507; span23[3] = 4511; dictionary.Add(961u, list23); num = 4; List list24 = new List(num); CollectionsMarshal.SetCount(list24, num); Span span24 = CollectionsMarshal.AsSpan(list24); span24[0] = 5039; span24[1] = 5047; span24[2] = 5051; span24[3] = 5055; dictionary.Add(1187u, list24); num = 4; List list25 = new List(num); CollectionsMarshal.SetCount(list25, num); Span span25 = CollectionsMarshal.AsSpan(list25); span25[0] = 5064; span25[1] = 5074; span25[2] = 5081; span25[3] = 5085; dictionary.Add(1188u, list25); num = 4; List list26 = new List(num); CollectionsMarshal.SetCount(list26, num); Span span26 = CollectionsMarshal.AsSpan(list26); span26[0] = 5094; span26[1] = 5103; span26[2] = 5110; span26[3] = 5114; dictionary.Add(1189u, list26); num = 4; List list27 = new List(num); CollectionsMarshal.SetCount(list27, num); Span span27 = CollectionsMarshal.AsSpan(list27); span27[0] = 5130; span27[1] = 5138; span27[2] = 5140; span27[3] = 5144; dictionary.Add(1190u, list27); num = 4; List list28 = new List(num); CollectionsMarshal.SetCount(list28, num); Span span28 = CollectionsMarshal.AsSpan(list28); span28[0] = 5153; span28[1] = 5156; span28[2] = 5159; span28[3] = 5160; dictionary.Add(1191u, list28); num = 4; List list29 = new List(num); CollectionsMarshal.SetCount(list29, num); Span span29 = CollectionsMarshal.AsSpan(list29); span29[0] = 5174; span29[1] = 5176; span29[2] = 5178; span29[3] = 5179; dictionary.Add(1192u, list29); AetherCurrentQuestsByTerritory = dictionary.ToImmutableDictionary((KeyValuePair> x) => x.Key, (KeyValuePair> x) => x.Value.Select((ushort y) => new QuestId(y)).ToImmutableList()); AetherCurrentQuests = AetherCurrentQuestsByTerritory.Values.SelectMany((ImmutableList x) => x).ToImmutableHashSet(); TankRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray(new uint[3] { 136u, 154u, 178u }); HealerRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray(new uint[3] { 137u, 155u, 179u }); MeleeRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray(new uint[3] { 138u, 156u, 180u }); PhysicalRangedRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray(new uint[3] { 138u, 157u, 181u }); CasterRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray(new uint[3] { 139u, 158u, 182u }); AllRoleQuestChapters = new global::_003C_003Ez__ReadOnlyArray>(new IReadOnlyList[5] { TankRoleQuestChapters, HealerRoleQuestChapters, MeleeRoleQuestChapters, PhysicalRangedRoleQuestChapters, CasterRoleQuestChapters }); FinalShadowbringersRoleQuests = new global::_003C_003Ez__ReadOnlyArray(new QuestId[4] { new QuestId(3248), new QuestId(3272), new QuestId(3278), new QuestId(3628) }); TankData = new RoleQuestData(TankRoleQuestChapters, new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(3248), new QuestId(4107), new QuestId(4823) }), (EClassJob j) => j.IsTank()); HealerData = new RoleQuestData(HealerRoleQuestChapters, new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(3272), new QuestId(4113), new QuestId(4829) }), (EClassJob j) => j.IsHealer()); MeleeData = new RoleQuestData(MeleeRoleQuestChapters, new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(3278), new QuestId(4119), new QuestId(4835) }), (EClassJob j) => j.IsMelee() && j != EClassJob.Beastmaster); PhysicalRangedData = new RoleQuestData(PhysicalRangedRoleQuestChapters, new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(3278), new QuestId(4125), new QuestId(4841) }), (EClassJob j) => j.IsPhysicalRanged()); CasterData = new RoleQuestData(CasterRoleQuestChapters, new global::_003C_003Ez__ReadOnlyArray(new QuestId[3] { new QuestId(3628), new QuestId(4131), new QuestId(4847) }), (EClassJob j) => j.IsCaster() && j != EClassJob.BlueMage); RoleDataByPreference = new Dictionary { [ERoleQuestPreference.Tank] = TankData, [ERoleQuestPreference.Healer] = HealerData, [ERoleQuestPreference.Melee] = MeleeData, [ERoleQuestPreference.PhysicalRanged] = PhysicalRangedData, [ERoleQuestPreference.Caster] = CasterData }; AllRoleData = new global::_003C_003Ez__ReadOnlyArray(new RoleQuestData[5] { TankData, HealerData, MeleeData, PhysicalRangedData, CasterData }); _cachedLockedClassQuests = new List(); } }