qstbak/QuestionableCompanion/QuestionableCompanion.Data/MSQExpansionData.cs
2025-12-04 04:39:08 +10:00

479 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
namespace QuestionableCompanion.Data;
public static class MSQExpansionData
{
public enum Expansion
{
ARealmReborn,
Heavensward,
Stormblood,
Shadowbringers,
Endwalker,
Dawntrail
}
private static readonly Dictionary<Expansion, HashSet<uint>> ExpansionQuests = new Dictionary<Expansion, HashSet<uint>>
{
{
Expansion.ARealmReborn,
new HashSet<uint>()
},
{
Expansion.Heavensward,
new HashSet<uint>()
},
{
Expansion.Stormblood,
new HashSet<uint>()
},
{
Expansion.Shadowbringers,
new HashSet<uint>()
},
{
Expansion.Endwalker,
new HashSet<uint>()
},
{
Expansion.Dawntrail,
new HashSet<uint>()
}
};
private static readonly Dictionary<Expansion, int> ExpectedQuestCounts = new Dictionary<Expansion, int>
{
{
Expansion.ARealmReborn,
200
},
{
Expansion.Heavensward,
100
},
{
Expansion.Stormblood,
100
},
{
Expansion.Shadowbringers,
100
},
{
Expansion.Endwalker,
100
},
{
Expansion.Dawntrail,
100
}
};
private static readonly Dictionary<Expansion, string> ExpansionNames = new Dictionary<Expansion, string>
{
{
Expansion.ARealmReborn,
"A Realm Reborn"
},
{
Expansion.Heavensward,
"Heavensward"
},
{
Expansion.Stormblood,
"Stormblood"
},
{
Expansion.Shadowbringers,
"Shadowbringers"
},
{
Expansion.Endwalker,
"Endwalker"
},
{
Expansion.Dawntrail,
"Dawntrail"
}
};
private static readonly Dictionary<Expansion, string> ExpansionShortNames = new Dictionary<Expansion, string>
{
{
Expansion.ARealmReborn,
"ARR"
},
{
Expansion.Heavensward,
"HW"
},
{
Expansion.Stormblood,
"SB"
},
{
Expansion.Shadowbringers,
"ShB"
},
{
Expansion.Endwalker,
"EW"
},
{
Expansion.Dawntrail,
"DT"
}
};
public static void RegisterQuest(uint questId, Expansion expansion)
{
if (ExpansionQuests.TryGetValue(expansion, out HashSet<uint> quests))
{
quests.Add(questId);
}
}
public static void ClearQuests()
{
foreach (HashSet<uint> value in ExpansionQuests.Values)
{
value.Clear();
}
}
public static Expansion GetExpansionForQuest(uint questId)
{
foreach (var (expansion2, hashSet2) in ExpansionQuests)
{
if (hashSet2.Contains(questId))
{
return expansion2;
}
}
return Expansion.ARealmReborn;
}
public static IReadOnlySet<uint> GetQuestsForExpansion(Expansion expansion)
{
if (!ExpansionQuests.TryGetValue(expansion, out HashSet<uint> quests))
{
return new HashSet<uint>();
}
return quests;
}
public static int GetExpectedQuestCount(Expansion expansion)
{
if (!ExpectedQuestCounts.TryGetValue(expansion, out var count))
{
return 0;
}
return count;
}
public static string GetExpansionName(Expansion expansion)
{
if (!ExpansionNames.TryGetValue(expansion, out string name))
{
return "Unknown";
}
return name;
}
public static string GetExpansionShortName(Expansion expansion)
{
if (!ExpansionShortNames.TryGetValue(expansion, out string name))
{
return "???";
}
return name;
}
public static IEnumerable<Expansion> GetAllExpansions()
{
return from e in Enum.GetValues<Expansion>()
orderby (int)e
select e;
}
public static int GetCompletedQuestCountForExpansion(IEnumerable<uint> completedQuestIds, Expansion expansion)
{
IReadOnlySet<uint> expansionQuests = GetQuestsForExpansion(expansion);
return completedQuestIds.Count((uint qId) => expansionQuests.Contains(qId));
}
public unsafe static (Expansion expansion, string debugInfo) GetCurrentExpansionFromGameWithDebug()
{
StringBuilder debug = new StringBuilder();
debug.AppendLine("=== AGENT SCENARIO TREE DEBUG ===");
try
{
AgentScenarioTree* agentScenarioTree = AgentScenarioTree.Instance();
StringBuilder stringBuilder = debug;
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(30, 1, stringBuilder);
handler.AppendLiteral("AgentScenarioTree.Instance(): ");
handler.AppendFormatted((agentScenarioTree != null) ? "OK" : "NULL");
stringBuilder2.AppendLine(ref handler);
if (agentScenarioTree == null)
{
debug.AppendLine("ERROR: AgentScenarioTree is NULL!");
return (expansion: Expansion.ARealmReborn, debugInfo: debug.ToString());
}
stringBuilder = debug;
StringBuilder stringBuilder3 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder);
handler.AppendLiteral("AgentScenarioTree->Data: ");
handler.AppendFormatted((agentScenarioTree->Data != null) ? "OK" : "NULL");
stringBuilder3.AppendLine(ref handler);
if (agentScenarioTree->Data == null)
{
debug.AppendLine("ERROR: AgentScenarioTree->Data is NULL!");
return (expansion: Expansion.ARealmReborn, debugInfo: debug.ToString());
}
ushort currentQuest = agentScenarioTree->Data->CurrentScenarioQuest;
ushort completedQuest = agentScenarioTree->Data->CompleteScenarioQuest;
stringBuilder = debug;
StringBuilder stringBuilder4 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(33, 2, stringBuilder);
handler.AppendLiteral("CurrentScenarioQuest (raw): ");
handler.AppendFormatted(currentQuest);
handler.AppendLiteral(" (0x");
handler.AppendFormatted(currentQuest, "X4");
handler.AppendLiteral(")");
stringBuilder4.AppendLine(ref handler);
stringBuilder = debug;
StringBuilder stringBuilder5 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(34, 2, stringBuilder);
handler.AppendLiteral("CompleteScenarioQuest (raw): ");
handler.AppendFormatted(completedQuest);
handler.AppendLiteral(" (0x");
handler.AppendFormatted(completedQuest, "X4");
handler.AppendLiteral(")");
stringBuilder5.AppendLine(ref handler);
ushort questToCheck = ((currentQuest != 0) ? currentQuest : completedQuest);
stringBuilder = debug;
StringBuilder stringBuilder6 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 2, stringBuilder);
handler.AppendLiteral("Quest to check: ");
handler.AppendFormatted(questToCheck);
handler.AppendLiteral(" (using ");
handler.AppendFormatted((currentQuest != 0) ? "Current" : "Completed");
handler.AppendLiteral(")");
stringBuilder6.AppendLine(ref handler);
if (questToCheck == 0)
{
debug.AppendLine("WARNING: Both CurrentScenarioQuest and CompleteScenarioQuest are 0!");
return (expansion: Expansion.ARealmReborn, debugInfo: debug.ToString());
}
uint questId = (uint)(questToCheck | 0x10000);
stringBuilder = debug;
StringBuilder stringBuilder7 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 2, stringBuilder);
handler.AppendLiteral("Converted Quest ID: ");
handler.AppendFormatted(questId);
handler.AppendLiteral(" (0x");
handler.AppendFormatted(questId, "X8");
handler.AppendLiteral(")");
stringBuilder7.AppendLine(ref handler);
Expansion expansion = GetExpansionForQuest(questId);
stringBuilder = debug;
StringBuilder stringBuilder8 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 2, stringBuilder);
handler.AppendLiteral("Expansion for Quest ");
handler.AppendFormatted(questId);
handler.AppendLiteral(": ");
handler.AppendFormatted(GetExpansionName(expansion));
stringBuilder8.AppendLine(ref handler);
IReadOnlySet<uint> expansionQuests = GetQuestsForExpansion(expansion);
bool isRegistered = expansionQuests.Contains(questId);
stringBuilder = debug;
StringBuilder stringBuilder9 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(23, 3, stringBuilder);
handler.AppendLiteral("Quest ");
handler.AppendFormatted(questId);
handler.AppendLiteral(" registered in ");
handler.AppendFormatted(expansion);
handler.AppendLiteral(": ");
handler.AppendFormatted(isRegistered);
stringBuilder9.AppendLine(ref handler);
if (!isRegistered)
{
stringBuilder = debug;
StringBuilder stringBuilder10 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(48, 1, stringBuilder);
handler.AppendLiteral("WARNING: Quest ");
handler.AppendFormatted(questId);
handler.AppendLiteral(" is NOT in our registered quests!");
stringBuilder10.AppendLine(ref handler);
stringBuilder = debug;
StringBuilder stringBuilder11 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(30, 2, stringBuilder);
handler.AppendLiteral("Total registered quests for ");
handler.AppendFormatted(expansion);
handler.AppendLiteral(": ");
handler.AppendFormatted(expansionQuests.Count);
stringBuilder11.AppendLine(ref handler);
foreach (Expansion exp in GetAllExpansions())
{
if (GetQuestsForExpansion(exp).Contains(questId))
{
stringBuilder = debug;
StringBuilder stringBuilder12 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder);
handler.AppendLiteral("FOUND in ");
handler.AppendFormatted(exp);
handler.AppendLiteral("!");
stringBuilder12.AppendLine(ref handler);
expansion = exp;
break;
}
}
}
stringBuilder = debug;
StringBuilder stringBuilder13 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(25, 1, stringBuilder);
handler.AppendLiteral(">>> FINAL EXPANSION: ");
handler.AppendFormatted(GetExpansionName(expansion));
handler.AppendLiteral(" <<<");
stringBuilder13.AppendLine(ref handler);
return (expansion: expansion, debugInfo: debug.ToString());
}
catch (Exception ex)
{
StringBuilder stringBuilder = debug;
StringBuilder stringBuilder14 = stringBuilder;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(11, 1, stringBuilder);
handler.AppendLiteral("EXCEPTION: ");
handler.AppendFormatted(ex.Message);
stringBuilder14.AppendLine(ref handler);
stringBuilder = debug;
StringBuilder stringBuilder15 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder);
handler.AppendLiteral("Stack: ");
handler.AppendFormatted(ex.StackTrace);
stringBuilder15.AppendLine(ref handler);
return (expansion: Expansion.ARealmReborn, debugInfo: debug.ToString());
}
}
public static Expansion GetCurrentExpansionFromGame()
{
return GetCurrentExpansionFromGameWithDebug().expansion;
}
public static Expansion GetCurrentExpansion(IEnumerable<uint> completedQuestIds)
{
List<uint> questList = completedQuestIds.ToList();
if (questList.Count == 0)
{
return Expansion.ARealmReborn;
}
foreach (Expansion expansion in GetAllExpansions().Reverse().ToList())
{
IReadOnlySet<uint> expansionQuests = GetQuestsForExpansion(expansion);
if (questList.Where((uint qId) => expansionQuests.Contains(qId)).ToList().Count > 0)
{
return expansion;
}
}
return Expansion.ARealmReborn;
}
public static string GetExpansionDetectionDebugInfo(IEnumerable<uint> completedQuestIds)
{
List<uint> questList = completedQuestIds.ToList();
StringBuilder result = new StringBuilder();
result.AppendLine("=== EXPANSION DETECTION DEBUG ===");
StringBuilder stringBuilder = result;
StringBuilder stringBuilder2 = stringBuilder;
StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(24, 1, stringBuilder);
handler.AppendLiteral("Total completed quests: ");
handler.AppendFormatted(questList.Count);
stringBuilder2.AppendLine(ref handler);
result.AppendLine("");
result.AppendLine("Checking expansions from highest to lowest:");
result.AppendLine("");
foreach (Expansion expansion in GetAllExpansions().Reverse())
{
IReadOnlySet<uint> expansionQuests = GetQuestsForExpansion(expansion);
List<uint> completedInExpansion = questList.Where((uint qId) => expansionQuests.Contains(qId)).ToList();
float percentage = ((expansionQuests.Count > 0) ? ((float)completedInExpansion.Count / (float)expansionQuests.Count * 100f) : 0f);
stringBuilder = result;
StringBuilder stringBuilder3 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(4, 2, stringBuilder);
handler.AppendFormatted(GetExpansionName(expansion));
handler.AppendLiteral(" (");
handler.AppendFormatted(GetExpansionShortName(expansion));
handler.AppendLiteral("):");
stringBuilder3.AppendLine(ref handler);
stringBuilder = result;
StringBuilder stringBuilder4 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(28, 1, stringBuilder);
handler.AppendLiteral(" - Total MSQ in expansion: ");
handler.AppendFormatted(expansionQuests.Count);
stringBuilder4.AppendLine(ref handler);
stringBuilder = result;
StringBuilder stringBuilder5 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(32, 2, stringBuilder);
handler.AppendLiteral(" - Completed by character: ");
handler.AppendFormatted(completedInExpansion.Count);
handler.AppendLiteral(" (");
handler.AppendFormatted(percentage, "F1");
handler.AppendLiteral("%)");
stringBuilder5.AppendLine(ref handler);
if (completedInExpansion.Count > 0)
{
string samples = string.Join(", ", completedInExpansion.OrderByDescending((uint x) => x).Take(5));
stringBuilder = result;
StringBuilder stringBuilder6 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(22, 1, stringBuilder);
handler.AppendLiteral(" - Sample Quest IDs: ");
handler.AppendFormatted(samples);
stringBuilder6.AppendLine(ref handler);
result.AppendLine(" >>> HAS COMPLETED QUESTS - WOULD SELECT THIS EXPANSION <<<");
}
else
{
result.AppendLine(" - No quests completed in this expansion");
}
result.AppendLine("");
}
Expansion currentExpansion = GetCurrentExpansion(questList);
result.AppendLine("===========================================");
stringBuilder = result;
StringBuilder stringBuilder7 = stringBuilder;
handler = new StringBuilder.AppendInterpolatedStringHandler(34, 1, stringBuilder);
handler.AppendLiteral(">>> FINAL DETECTED EXPANSION: ");
handler.AppendFormatted(GetExpansionName(currentExpansion));
handler.AppendLiteral(" <<<");
stringBuilder7.AppendLine(ref handler);
result.AppendLine("===========================================");
return result.ToString();
}
public static ExpansionProgress GetExpansionProgress(IEnumerable<uint> completedQuestIds, Expansion expansion)
{
int completed = GetCompletedQuestCountForExpansion(completedQuestIds, expansion);
int expected = GetExpectedQuestCount(expansion);
return new ExpansionProgress
{
Expansion = expansion,
CompletedCount = completed,
ExpectedCount = expected,
Percentage = ((expected > 0) ? ((float)completed / (float)expected * 100f) : 0f),
IsComplete = (completed >= expected)
};
}
public static List<ExpansionProgress> GetAllExpansionProgress(IEnumerable<uint> completedQuestIds)
{
return (from exp in GetAllExpansions()
select GetExpansionProgress(completedQuestIds, exp)).ToList();
}
}