forked from chomp/ChompQuestVerifier
2dfc8aefde
Add additional properties to quest prereqs Handle quests that need multiple start statuses nullguard some properties when adding missing start conditions renamed hippo vow to oath Add 'the courier' quest
309 lines
13 KiB
C#
309 lines
13 KiB
C#
using AssortGenerator.Common.Helpers;
|
|
using QuestValidator.Common;
|
|
using QuestValidator.Common.Helpers;
|
|
using QuestValidator.Common.Models;
|
|
using QuestValidator.Helpers;
|
|
using QuestValidator.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using Quest = QuestValidator.Models.Quest;
|
|
|
|
namespace GenerateQuestFile
|
|
{
|
|
class Program
|
|
{
|
|
/// <summary>
|
|
/// Generate a quests.json file in /output/
|
|
/// Uses every quest from the live quest dump file
|
|
/// If any quests are missing, it will use the quests.json file to fill in the blanks
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
static void Main(string[] args)
|
|
{
|
|
var inputPath = DiskHelpers.CreateWorkingFolders();
|
|
InputFileHelper.SetInputFiles(inputPath);
|
|
|
|
// Read in quest files
|
|
var existingQuestData = QuestHelper.GetQuestData();
|
|
var liveQuestData = QuestHelper.GetLiveQuestData();
|
|
|
|
var mergedLiveData = QuestHelper.MergeLiveQuestFiles(liveQuestData);
|
|
|
|
//JsonWriter.WriteJson<QuestRoot>(mergedLiveData, "merged", Directory.GetCurrentDirectory(), "mergedlivejson");
|
|
|
|
// Find the quests that are missing from the live file from existing quest data
|
|
var missingQuests = GetMissingQuestsNotInLiveFile(existingQuestData, mergedLiveData);
|
|
|
|
|
|
|
|
// Create a list of quests to output
|
|
// Use all quests in live file
|
|
// Use quests from quests.json to fill in missing quests
|
|
var questsToOutputToFile = new Dictionary<string, Quest>();
|
|
|
|
// Add live quests to collection to return later
|
|
foreach (var liveQuest in mergedLiveData.data)
|
|
{
|
|
questsToOutputToFile.Add(liveQuest._id, liveQuest);
|
|
}
|
|
|
|
// Add missing quests from existing quest data to fill in blanks from live data
|
|
foreach (var missingQuest in missingQuests)
|
|
{
|
|
// Going from a pre-12.7.x version has problems, it doesnt have the new quest data format
|
|
//CheckAndFixMissingProperties(missingQuest);
|
|
|
|
questsToOutputToFile.Add(missingQuest._id, missingQuest);
|
|
}
|
|
|
|
// Now old + new qeusts have been merged, check qeust list to see if any quests are missing
|
|
foreach (var missingQuest in QuestNames.GetQuests())
|
|
{
|
|
if (!questsToOutputToFile.Any(x => x.Key == missingQuest.Value))
|
|
{
|
|
LoggingHelpers.LogWarning($" quest not found in new or old data: {missingQuest.Key}");
|
|
}
|
|
}
|
|
|
|
if (!questsToOutputToFile.ContainsKey("5e383a6386f77465910ce1f3")) // TextileP1Bear
|
|
{
|
|
// add textileP1Bear
|
|
}
|
|
|
|
if (!questsToOutputToFile.ContainsKey("5e4d515e86f77438b2195244")) // TextileP2Bear
|
|
{
|
|
// add TextileP2Bear
|
|
}
|
|
|
|
foreach (var quest in questsToOutputToFile)
|
|
{
|
|
AddQuestName(quest);
|
|
|
|
var originalQuest = existingQuestData.FirstOrDefault(x => x.Key == quest.Key).Value;
|
|
|
|
if (originalQuest is null)
|
|
{
|
|
LoggingHelpers.LogWarning($"Cant check for original start conditions. Unable to find original quest {quest.Key} {QuestHelper.GetQuestNameById(quest.Key)}, skipping.");
|
|
continue;
|
|
}
|
|
|
|
AddMissingFields(quest);
|
|
|
|
// quest has start conditions, check to ensure they're carried over
|
|
if (originalQuest.conditions.AvailableForStart.Count > 0)
|
|
{
|
|
AddMissingAvailableForStartConditions(originalQuest, quest);
|
|
}
|
|
|
|
if (originalQuest.rewards.Fail.Count > 0)
|
|
{
|
|
AddMissingFailRewards(originalQuest, quest);
|
|
}
|
|
}
|
|
|
|
// Iterate over quest objects a final time and add hard coded quest requirements if they dont already exist
|
|
foreach (var quest in questsToOutputToFile)
|
|
{
|
|
var questRequirements = QuestRequirements.GetQuestRequirements(quest.Key);
|
|
if (questRequirements is null || questRequirements.Count == 0)
|
|
{
|
|
LoggingHelpers.LogWarning($"Quest requirement not found for : {quest.Value.QuestName}, skipping.");
|
|
continue;
|
|
}
|
|
|
|
foreach (var requirement in questRequirements)
|
|
{
|
|
// Does quest have requirement
|
|
if (!quest.Value.conditions.AvailableForStart.Any(x => x._parent == "Quest"
|
|
&& x._props.target.ToString() == requirement.Quest.Id))
|
|
{
|
|
LoggingHelpers.LogSuccess($"{quest.Value.QuestName} needs a prereq of quest {requirement.Quest.Name}, adding.");
|
|
quest.Value.conditions.AvailableForStart.Add(new AvailableFor
|
|
{
|
|
_parent = "Quest",
|
|
_props = new AvailableForProps
|
|
{
|
|
id = Sha256(new DateTime().ToString()),
|
|
index = quest.Value.conditions.AvailableForStart.Count,
|
|
parentId = "",
|
|
status = GetQuestStatus(requirement.QuestStatus),
|
|
target = requirement.Quest.Id,
|
|
visibilityConditions = new List<object>(),
|
|
availableAfter = 0
|
|
}
|
|
}
|
|
);
|
|
}
|
|
else
|
|
{
|
|
if (questRequirements != null)
|
|
{
|
|
LoggingHelpers.LogInfo($"{quest.Value.QuestName} already has prereq of quest {requirement.Quest.Name}, skipping.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
JsonWriter.WriteJson(questsToOutputToFile, "output", Directory.GetCurrentDirectory(), "quests");
|
|
}
|
|
|
|
private static int[] GetQuestStatus(QuestStatus status)
|
|
{
|
|
switch (status)
|
|
{
|
|
case QuestStatus.Started:
|
|
case QuestStatus.Success:
|
|
case QuestStatus.Fail:
|
|
return new int[] { (int)status };
|
|
case QuestStatus.StartedSuccess:
|
|
return new int[] { (int)QuestStatus.Started, (int)QuestStatus.Success };
|
|
}
|
|
|
|
throw new Exception($"Unable to process quest status {status}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Latest version of eft has changed the quest json structure, this method adds missing fields
|
|
/// Mega hack as we dont have a full dump as of 30/06/2022
|
|
/// </summary>
|
|
/// <param name="quest">quest to add missing fields to</param>
|
|
private static void AddMissingFields(KeyValuePair<string, Quest> quest)
|
|
{
|
|
//side
|
|
if (String.IsNullOrEmpty(quest.Value.side))
|
|
{
|
|
quest.Value.side = "Pmc";
|
|
LoggingHelpers.LogInfo($"Updated quest {quest.Value.QuestName} to have a side of 'pmc'");
|
|
}
|
|
|
|
//changeQuestMessageText
|
|
if (String.IsNullOrEmpty(quest.Value.changeQuestMessageText))
|
|
{
|
|
quest.Value.changeQuestMessageText = $"{quest.Value._id} changeQuestMessageText";
|
|
LoggingHelpers.LogInfo($"Updated quest {quest.Value.QuestName} to have a changeQuestMessageText value");
|
|
}
|
|
|
|
// findInRaid
|
|
foreach (var success in quest.Value.rewards.Success)
|
|
{
|
|
if (string.Equals(success.type, "item", StringComparison.OrdinalIgnoreCase)
|
|
&& success.findInRaid == null)
|
|
{
|
|
success.findInRaid = true;
|
|
LoggingHelpers.LogInfo($"Updated quest {quest.Value.QuestName} to have a success item reward findInRaid value of 'true'");
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void AddMissingFailRewards(Quest originalQuest, KeyValuePair<string, Quest> quest)
|
|
{
|
|
foreach (var originalFailReward in originalQuest.rewards.Fail)
|
|
{
|
|
// already has a fail reward of same type and target, skip
|
|
if (quest.Value.rewards.Fail.Any(x => x.type == originalFailReward.type && x.target == originalFailReward.target))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
quest.Value.rewards.Fail.Add(originalFailReward);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check original quest for start conditions and if missing from new quest, add them
|
|
/// </summary>
|
|
/// <param name="originalQuest"></param>
|
|
/// <param name="questToUpdate">quest to add to output json</param>
|
|
private static void AddMissingAvailableForStartConditions(Quest originalQuest, KeyValuePair<string, Quest> questToUpdate)
|
|
{
|
|
// Iterate over quest requirements in existing quest file
|
|
foreach (var questRequirementToAdd in originalQuest.conditions.AvailableForStart.ToList())
|
|
{
|
|
//Exists already, skip
|
|
if (questToUpdate.Value.conditions.AvailableForStart.Any(
|
|
x => x._parent == questRequirementToAdd._parent
|
|
&& x._props.target?.ToString() == questRequirementToAdd._props.target?.ToString())
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (questRequirementToAdd._parent == "Quest")
|
|
{
|
|
questRequirementToAdd._props.id = Sha256(new DateTime().ToString());
|
|
|
|
if (!questRequirementToAdd._props.availableAfter.HasValue)
|
|
{
|
|
questRequirementToAdd._props.availableAfter = 0;
|
|
}
|
|
|
|
if (questRequirementToAdd._props.visibilityConditions == null || !questRequirementToAdd._props.visibilityConditions.Any())
|
|
{
|
|
questRequirementToAdd._props.visibilityConditions = new List<object>();
|
|
}
|
|
|
|
questRequirementToAdd._props.index = questToUpdate.Value.conditions.AvailableForStart.Count;
|
|
|
|
}
|
|
|
|
questToUpdate.Value.conditions.AvailableForStart.Add(questRequirementToAdd);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a bsg happy guid, must be 24 chars long
|
|
/// </summary>
|
|
/// <param name="randomSalt"></param>
|
|
/// <returns></returns>
|
|
static string Sha256(string randomSalt)
|
|
{
|
|
var crypt = new System.Security.Cryptography.SHA256Managed();
|
|
var hash = new System.Text.StringBuilder();
|
|
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomSalt));
|
|
foreach (byte theByte in crypto)
|
|
{
|
|
hash.Append(theByte.ToString("x2"));
|
|
}
|
|
return hash.ToString().Substring(0, 24);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Look up the quests name by guid and add human readable string to quest object
|
|
/// </summary>
|
|
/// <param name="quest"></param>
|
|
private static void AddQuestName(KeyValuePair<string, Quest> quest)
|
|
{
|
|
var questName = QuestHelper.GetQuestNameById(quest.Value._id); // special characters like ", brake the client when it parses it, gotta remove
|
|
var rgx = new Regex("[^a-zA-Z0-9 -]");
|
|
quest.Value.QuestName = rgx.Replace(questName, "");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loop over live quests and use if it exists, otherwise use existing data
|
|
/// </summary>
|
|
private static List<Quest> GetMissingQuestsNotInLiveFile(Dictionary<string, Quest> existingQuests, QuestRoot liveQuestData)
|
|
{
|
|
var missingQuestsToReturn = new List<Quest>();
|
|
foreach (var quest in existingQuests.Values)
|
|
{
|
|
var liveQuest = liveQuestData.data.Find(x => x._id == quest._id);
|
|
if (liveQuest is null)
|
|
{
|
|
missingQuestsToReturn.Add(quest);
|
|
LoggingHelpers.LogError($"ERROR Quest {quest._id} {QuestHelper.GetQuestNameById(quest._id)} missing in live file. Will use fallback quests.json");
|
|
}
|
|
else
|
|
{
|
|
LoggingHelpers.LogSuccess($"SUCCESS Quest {quest._id} {QuestHelper.GetQuestNameById(quest._id)} found in live file.");
|
|
}
|
|
}
|
|
|
|
return missingQuestsToReturn;
|
|
}
|
|
}
|
|
}
|