212 lines
5.6 KiB
C#
212 lines
5.6 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Questionable.Model;
|
|
using Questionable.Model.Questing;
|
|
|
|
namespace Questionable.Data;
|
|
|
|
internal sealed class QuestChainBuilder
|
|
{
|
|
private readonly QuestData _questData;
|
|
|
|
private readonly Dictionary<QuestId, List<QuestId>> _descendants = new Dictionary<QuestId, List<QuestId>>();
|
|
|
|
private readonly Dictionary<QuestId, QuestChain> _cache = new Dictionary<QuestId, QuestChain>();
|
|
|
|
private readonly Dictionary<QuestId, QuestChainGraph> _graphCache = new Dictionary<QuestId, QuestChainGraph>();
|
|
|
|
public QuestChainBuilder(QuestData questData)
|
|
{
|
|
_questData = questData;
|
|
foreach (var (elementId2, questInfo2) in _questData.AllQuests)
|
|
{
|
|
if (!(elementId2 is QuestId item))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (PreviousQuestInfo previousQuest in questInfo2.PreviousQuests)
|
|
{
|
|
if (!_descendants.TryGetValue(previousQuest.QuestId, out List<QuestId> value))
|
|
{
|
|
value = new List<QuestId>();
|
|
_descendants[previousQuest.QuestId] = value;
|
|
}
|
|
value.Add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
public QuestChain GetChain(QuestId questId)
|
|
{
|
|
if (_cache.TryGetValue(questId, out QuestChain value))
|
|
{
|
|
return value;
|
|
}
|
|
List<QuestId> list = new List<QuestId>();
|
|
CollectAncestors(questId, list, new HashSet<QuestId>());
|
|
list.Add(questId);
|
|
List<QuestId> list2 = new List<QuestId>();
|
|
CollectDescendants(questId, list2, new HashSet<QuestId>());
|
|
QuestChain questChain = new QuestChain(list, list2, questId);
|
|
_cache[questId] = questChain;
|
|
return questChain;
|
|
}
|
|
|
|
public QuestChainGraph GetChainGraph(QuestId questId)
|
|
{
|
|
if (_graphCache.TryGetValue(questId, out QuestChainGraph value))
|
|
{
|
|
return value;
|
|
}
|
|
HashSet<QuestId> hashSet = new HashSet<QuestId>();
|
|
CollectAllRelated(questId, hashSet);
|
|
Dictionary<QuestId, List<QuestId>> prerequisites = new Dictionary<QuestId, List<QuestId>>();
|
|
Dictionary<QuestId, List<QuestId>> dictionary = new Dictionary<QuestId, List<QuestId>>();
|
|
foreach (QuestId item in hashSet)
|
|
{
|
|
prerequisites[item] = new List<QuestId>();
|
|
dictionary[item] = new List<QuestId>();
|
|
}
|
|
foreach (QuestId item2 in hashSet)
|
|
{
|
|
if (!_questData.TryGetQuestInfo(item2, out IQuestInfo questInfo))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (PreviousQuestInfo previousQuest in questInfo.PreviousQuests)
|
|
{
|
|
if (hashSet.Contains(previousQuest.QuestId))
|
|
{
|
|
prerequisites[item2].Add(previousQuest.QuestId);
|
|
dictionary[previousQuest.QuestId].Add(item2);
|
|
}
|
|
}
|
|
}
|
|
Dictionary<QuestId, int> dictionary2 = new Dictionary<QuestId, int>();
|
|
List<QuestId> list = hashSet.Where((QuestId q) => prerequisites[q].Count == 0).ToList();
|
|
foreach (QuestId item3 in hashSet)
|
|
{
|
|
dictionary2[item3] = 0;
|
|
}
|
|
Dictionary<QuestId, int> dictionary3 = new Dictionary<QuestId, int>();
|
|
foreach (QuestId item4 in hashSet)
|
|
{
|
|
dictionary3[item4] = prerequisites[item4].Count;
|
|
}
|
|
Queue<QuestId> queue = new Queue<QuestId>(list);
|
|
foreach (QuestId item5 in list)
|
|
{
|
|
dictionary2[item5] = 0;
|
|
}
|
|
while (queue.Count > 0)
|
|
{
|
|
QuestId key = queue.Dequeue();
|
|
foreach (QuestId item6 in dictionary[key])
|
|
{
|
|
int num = dictionary2[key] + 1;
|
|
if (num > dictionary2[item6])
|
|
{
|
|
dictionary2[item6] = num;
|
|
}
|
|
dictionary3[item6]--;
|
|
if (dictionary3[item6] == 0)
|
|
{
|
|
queue.Enqueue(item6);
|
|
}
|
|
}
|
|
}
|
|
foreach (QuestId item7 in hashSet)
|
|
{
|
|
if (!dictionary2.ContainsKey(item7))
|
|
{
|
|
dictionary2[item7] = 0;
|
|
}
|
|
}
|
|
int num2 = ((hashSet.Count > 0) ? dictionary2.Values.Max() : 0);
|
|
List<List<QuestId>> list2 = new List<List<QuestId>>();
|
|
for (int num3 = 0; num3 <= num2; num3++)
|
|
{
|
|
list2.Add(new List<QuestId>());
|
|
}
|
|
foreach (QuestId item8 in hashSet)
|
|
{
|
|
list2[dictionary2[item8]].Add(item8);
|
|
}
|
|
foreach (List<QuestId> item9 in list2)
|
|
{
|
|
item9.Sort((QuestId a, QuestId b) => a.Value.CompareTo(b.Value));
|
|
}
|
|
QuestChainGraph questChainGraph = new QuestChainGraph(prerequisites, dictionary, dictionary2, list2, questId);
|
|
_graphCache[questId] = questChainGraph;
|
|
return questChainGraph;
|
|
}
|
|
|
|
public void Invalidate()
|
|
{
|
|
_cache.Clear();
|
|
_graphCache.Clear();
|
|
}
|
|
|
|
private void CollectAllRelated(QuestId questId, HashSet<QuestId> result)
|
|
{
|
|
CollectAncestorsSet(questId, result);
|
|
result.Add(questId);
|
|
CollectDescendantsSet(questId, result);
|
|
}
|
|
|
|
private void CollectAncestorsSet(QuestId questId, HashSet<QuestId> visited)
|
|
{
|
|
if (!visited.Add(questId) || !_questData.TryGetQuestInfo(questId, out IQuestInfo questInfo))
|
|
{
|
|
return;
|
|
}
|
|
foreach (PreviousQuestInfo previousQuest in questInfo.PreviousQuests)
|
|
{
|
|
CollectAncestorsSet(previousQuest.QuestId, visited);
|
|
}
|
|
}
|
|
|
|
private void CollectDescendantsSet(QuestId questId, HashSet<QuestId> visited)
|
|
{
|
|
if (!visited.Add(questId) || !_descendants.TryGetValue(questId, out List<QuestId> value))
|
|
{
|
|
return;
|
|
}
|
|
foreach (QuestId item in value)
|
|
{
|
|
CollectDescendantsSet(item, visited);
|
|
}
|
|
}
|
|
|
|
private void CollectAncestors(QuestId questId, List<QuestId> result, HashSet<QuestId> visited)
|
|
{
|
|
if (!visited.Add(questId) || !_questData.TryGetQuestInfo(questId, out IQuestInfo questInfo))
|
|
{
|
|
return;
|
|
}
|
|
foreach (PreviousQuestInfo previousQuest in questInfo.PreviousQuests)
|
|
{
|
|
CollectAncestors(previousQuest.QuestId, result, visited);
|
|
if (!result.Contains(previousQuest.QuestId))
|
|
{
|
|
result.Add(previousQuest.QuestId);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CollectDescendants(QuestId questId, List<QuestId> result, HashSet<QuestId> visited)
|
|
{
|
|
if (!visited.Add(questId) || !_descendants.TryGetValue(questId, out List<QuestId> value))
|
|
{
|
|
return;
|
|
}
|
|
foreach (QuestId item in value)
|
|
{
|
|
if (!result.Contains(item))
|
|
{
|
|
result.Add(item);
|
|
}
|
|
CollectDescendants(item, result, visited);
|
|
}
|
|
}
|
|
}
|