2021-09-14 19:52:11 +01:00
using AssortGenerator.Common.Helpers ;
using QuestValidator.Common ;
using QuestValidator.Common.Helpers ;
2022-09-07 11:15:52 +01:00
using QuestValidator.Common.Models ;
2021-09-14 19:52:11 +01:00
using QuestValidator.Helpers ;
using QuestValidator.Models ;
2022-06-08 16:41:30 +01:00
using System ;
2021-09-14 19:52:11 +01:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
2022-09-07 08:51:30 +01:00
using System.Text ;
2021-09-14 19:52:11 +01:00
using System.Text.RegularExpressions ;
2022-09-07 11:15:52 +01:00
using Quest = QuestValidator . Models . Quest ;
2021-09-14 19:52:11 +01:00
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 ) ;
2022-01-09 20:35:43 +00:00
// Read in quest files
var existingQuestData = QuestHelper . GetQuestData ( ) ;
2021-09-14 19:52:11 +01:00
var liveQuestData = QuestHelper . GetLiveQuestData ( ) ;
2022-09-07 08:51:30 +01:00
var mergedLiveData = QuestHelper . MergeLiveQuestFiles ( liveQuestData ) ;
2023-01-09 11:11:46 +00:00
OutputQuestRequirementsToConsole ( mergedLiveData . data ) ;
2023-01-05 23:04:11 +00:00
2023-01-02 12:22:48 +00:00
JsonWriter . WriteJson < QuestRoot > ( mergedLiveData , "output" , Directory . GetCurrentDirectory ( ) , "mergedlivejson" ) ;
2022-09-07 08:51:30 +01:00
2022-01-09 20:35:43 +00:00
// Find the quests that are missing from the live file from existing quest data
2022-09-07 08:51:30 +01:00
var missingQuests = GetMissingQuestsNotInLiveFile ( existingQuestData , mergedLiveData ) ;
2021-09-14 19:52:11 +01:00
// Create a list of quests to output
2022-01-09 20:35:43 +00:00
// Use all quests in live file
2021-09-14 19:52:11 +01:00
// Use quests from quests.json to fill in missing quests
var questsToOutputToFile = new Dictionary < string , Quest > ( ) ;
2022-01-09 20:35:43 +00:00
// Add live quests to collection to return later
2022-09-07 08:51:30 +01:00
foreach ( var liveQuest in mergedLiveData . data )
2021-09-14 19:52:11 +01:00
{
2022-01-09 20:35:43 +00:00
questsToOutputToFile . Add ( liveQuest . _id , liveQuest ) ;
2021-09-14 19:52:11 +01:00
}
2022-01-09 20:35:43 +00:00
// Add missing quests from existing quest data to fill in blanks from live data
2021-09-14 19:52:11 +01:00
foreach ( var missingQuest in missingQuests )
{
2022-01-09 20:35:43 +00:00
// Going from a pre-12.7.x version has problems, it doesnt have the new quest data format
2022-06-08 16:41:30 +01:00
//CheckAndFixMissingProperties(missingQuest);
2022-01-09 20:35:43 +00:00
2021-09-14 19:52:11 +01:00
questsToOutputToFile . Add ( missingQuest . _id , missingQuest ) ;
}
2023-01-02 12:22:48 +00:00
// Now old + new quests have been merged, check quest list to see if any quests are missing
2022-09-07 08:51:30 +01:00
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}" ) ;
}
}
2022-01-09 20:35:43 +00:00
if ( ! questsToOutputToFile . ContainsKey ( "5e383a6386f77465910ce1f3" ) ) // TextileP1Bear
{
// add textileP1Bear
}
if ( ! questsToOutputToFile . ContainsKey ( "5e4d515e86f77438b2195244" ) ) // TextileP2Bear
{
// add TextileP2Bear
}
2021-09-14 19:52:11 +01:00
foreach ( var quest in questsToOutputToFile )
{
2022-01-09 20:35:43 +00:00
AddQuestName ( quest ) ;
2021-09-14 19:52:11 +01:00
2022-01-09 20:35:43 +00:00
var originalQuest = existingQuestData . FirstOrDefault ( x = > x . Key = = quest . Key ) . Value ;
2023-01-24 09:59:24 +00:00
2022-01-12 11:48:23 +00:00
if ( originalQuest is null )
{
2022-01-14 10:16:37 +00:00
LoggingHelpers . LogWarning ( $"Cant check for original start conditions. Unable to find original quest {quest.Key} {QuestHelper.GetQuestNameById(quest.Key)}, skipping." ) ;
2022-01-12 11:48:23 +00:00
continue ;
}
2022-06-30 12:16:08 +01:00
AddMissingFields ( quest ) ;
2023-01-05 16:57:45 +00:00
// Quest has start conditions, check to ensure they're carried over
2021-09-14 19:52:11 +01:00
if ( originalQuest . conditions . AvailableForStart . Count > 0 )
{
2022-01-09 20:35:43 +00:00
AddMissingAvailableForStartConditions ( originalQuest , quest ) ;
2021-09-14 19:52:11 +01:00
}
2022-06-08 16:41:30 +01:00
if ( originalQuest . rewards . Fail . Count > 0 )
{
AddMissingFailRewards ( originalQuest , quest ) ;
}
2021-09-14 19:52:11 +01:00
}
2022-01-09 20:35:43 +00:00
// Iterate over quest objects a final time and add hard coded quest requirements if they dont already exist
2021-09-14 19:52:11 +01:00
foreach ( var quest in questsToOutputToFile )
{
2022-01-14 10:16:37 +00:00
var questRequirements = QuestRequirements . GetQuestRequirements ( quest . Key ) ;
2022-01-09 20:35:43 +00:00
if ( questRequirements is null | | questRequirements . Count = = 0 )
2021-09-14 19:52:11 +01:00
{
2022-01-14 10:16:37 +00:00
LoggingHelpers . LogWarning ( $"Quest requirement not found for : {quest.Value.QuestName}, skipping." ) ;
2023-01-24 09:59:24 +00:00
2021-09-14 20:11:41 +01:00
continue ;
}
2021-09-28 20:17:42 +01:00
foreach ( var requirement in questRequirements )
2021-09-14 20:11:41 +01:00
{
2023-01-24 09:59:24 +00:00
if ( requirement . PreReqType = = PreRequisiteType . Quest )
2021-09-14 19:52:11 +01:00
{
2023-01-24 09:59:24 +00:00
// Does quest have requirement
if ( ! quest . Value . conditions . AvailableForStart . Any ( x = > x . _parent = = "Quest"
& & x . _props . target . ToString ( ) = = requirement . Quest . Id ) )
2021-09-14 19:52:11 +01:00
{
2023-01-24 09:59:24 +00:00
LoggingHelpers . LogSuccess ( $"{quest.Value.QuestName} needs a prereq of quest {requirement.Quest.Name}, adding." ) ;
quest . Value . conditions . AvailableForStart . Add ( new AvailableFor
2021-09-28 20:17:42 +01:00
{
2023-01-24 09:59:24 +00:00
_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." ) ;
2021-09-28 20:17:42 +01:00
}
2021-09-14 19:52:11 +01:00
}
}
2023-01-24 09:59:24 +00:00
if ( requirement . PreReqType = = PreRequisiteType . Level )
2021-09-14 20:11:41 +01:00
{
2023-01-24 09:59:24 +00:00
if ( ! quest . Value . conditions . AvailableForStart . Any ( x = > x . _parent = = "Level"
& & int . Parse ( ( string ) x . _props . value ) = = requirement . Level ) )
2021-09-28 20:17:42 +01:00
{
2023-01-24 09:59:24 +00:00
LoggingHelpers . LogSuccess ( $"{quest.Value.QuestName} needs a prereq of level {requirement.Level}, adding." ) ;
quest . Value . conditions . AvailableForStart . Add ( new AvailableFor
{
_parent = "Level" ,
_props = new AvailableForProps
{
id = Sha256 ( new DateTime ( ) . ToString ( ) ) ,
index = quest . Value . conditions . AvailableForStart . Count ,
parentId = "" ,
dynamicLocale = false ,
value = requirement . Level ,
compareMethod = ">=" ,
visibilityConditions = new List < object > ( )
}
}
) ;
2021-09-28 20:17:42 +01:00
}
2021-09-14 20:11:41 +01:00
}
}
2021-09-14 19:52:11 +01:00
}
2023-01-09 11:11:46 +00:00
OutputQuestRequirementsToConsole2 ( questsToOutputToFile ) ;
2021-09-14 19:52:11 +01:00
JsonWriter . WriteJson ( questsToOutputToFile , "output" , Directory . GetCurrentDirectory ( ) , "quests" ) ;
}
2022-01-09 20:36:05 +00:00
2023-01-09 11:11:46 +00:00
private static void OutputQuestRequirementsToConsole ( List < Quest > quests )
2023-01-05 23:04:11 +00:00
{
var output = new List < string > ( ) ;
2023-01-09 11:11:46 +00:00
foreach ( var quest in quests )
2023-01-05 23:04:11 +00:00
{
var questConditions = quest . conditions . AvailableForStart . Where ( x = > x . _parent = = "Quest" ) ;
if ( questConditions ! = null )
{
foreach ( var questCondition in questConditions )
{
var x = questCondition . _props . target . ToString ( ) ;
Console . WriteLine ( $"{QuestHelper.GetQuestNameById(quest._id)} needs {QuestHelper.GetQuestNameById(x)}" ) ;
}
}
}
2023-01-24 09:59:24 +00:00
// JsonWriter.WriteJson<QuestRoot>(output, "output", Directory.GetCurrentDirectory(), "questRequirements");
2023-01-09 11:11:46 +00:00
}
private static void OutputQuestRequirementsToConsole2 ( Dictionary < string , Quest > quests )
{
var output = new List < string > ( ) ;
foreach ( var quest in quests )
{
var questConditions = quest . Value . conditions . AvailableForStart . Where ( x = > x . _parent = = "Quest" ) ;
if ( questConditions ! = null )
{
foreach ( var questCondition in questConditions )
{
var x = questCondition . _props . target . ToString ( ) ;
Console . WriteLine ( $"{QuestHelper.GetQuestNameById(quest.Value._id)} needs {QuestHelper.GetQuestNameById(x)}" ) ;
}
}
}
// JsonWriter.WriteJson<QuestRoot>(output, "output", Directory.GetCurrentDirectory(), "questRequirements");
2023-01-05 23:04:11 +00:00
}
2022-09-07 11:15:52 +01:00
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 } ;
2023-01-05 16:57:45 +00:00
case QuestStatus . SuccessFail :
return new int [ ] { ( int ) QuestStatus . Success , ( int ) QuestStatus . Fail } ;
2022-09-07 11:15:52 +01:00
}
throw new Exception ( $"Unable to process quest status {status}" ) ;
}
2022-06-30 12:16:08 +01:00
/// <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 )
2022-01-09 20:36:05 +00:00
{
2022-06-30 12:16:08 +01:00
//side
if ( String . IsNullOrEmpty ( quest . Value . side ) )
2022-01-09 20:36:05 +00:00
{
2022-06-30 12:16:08 +01:00
quest . Value . side = "Pmc" ;
LoggingHelpers . LogInfo ( $"Updated quest {quest.Value.QuestName} to have a side of 'pmc'" ) ;
2022-01-09 20:36:05 +00:00
}
2022-06-30 12:16:08 +01:00
//changeQuestMessageText
if ( String . IsNullOrEmpty ( quest . Value . changeQuestMessageText ) )
2022-01-09 20:36:05 +00:00
{
2022-06-30 12:16:08 +01:00
quest . Value . changeQuestMessageText = $"{quest.Value._id} changeQuestMessageText" ;
LoggingHelpers . LogInfo ( $"Updated quest {quest.Value.QuestName} to have a changeQuestMessageText value" ) ;
2022-01-09 20:36:05 +00:00
}
2022-06-30 12:16:08 +01:00
// findInRaid
foreach ( var success in quest . Value . rewards . Success )
2022-01-09 20:36:05 +00:00
{
2023-01-24 09:59:24 +00:00
if ( string . Equals ( success . type , "item" , StringComparison . OrdinalIgnoreCase )
2022-06-30 12:16:08 +01:00
& & success . findInRaid = = null )
{
success . findInRaid = true ;
LoggingHelpers . LogInfo ( $"Updated quest {quest.Value.QuestName} to have a success item reward findInRaid value of 'true'" ) ;
}
2022-01-09 20:36:05 +00:00
}
2022-06-30 12:16:08 +01:00
}
2022-01-09 20:36:05 +00:00
2022-06-30 12:16:08 +01:00
private static void AddMissingFailRewards ( Quest originalQuest , KeyValuePair < string , Quest > quest )
{
2022-07-09 18:18:32 +01:00
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 ) ;
}
2022-01-09 20:36:05 +00:00
}
2022-06-30 12:16:08 +01:00
/// <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>
2022-01-09 20:36:05 +00:00
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
2023-01-05 16:57:45 +00:00
//if (questToUpdate.Value.conditions.AvailableForStart.Any(
// x => x._parent == questRequirementToAdd._parent
// && x._props.target?.ToString() == questRequirementToAdd._props.target?.ToString())
// )
//{
// continue;
//}
if ( questToUpdate . Value . conditions . AvailableForStart . Any ( x = > string . Equals ( x . _parent , "quest" , StringComparison . CurrentCultureIgnoreCase ) ) )
2022-01-09 20:36:05 +00:00
{
continue ;
}
2022-09-07 08:51:30 +01:00
if ( questRequirementToAdd . _parent = = "Quest" )
{
2023-01-05 16:57:45 +00:00
LoggingHelpers . LogInfo ( $"Quest {questToUpdate.Value.QuestName} missing AvailableForStart quest requirement, adding prereq of {questRequirementToAdd._props.target} {QuestHelper.GetQuestNameById(questRequirementToAdd._props.target?.ToString())}" ) ;
2022-09-07 08:51:30 +01:00
questRequirementToAdd . _props . id = Sha256 ( new DateTime ( ) . ToString ( ) ) ;
2022-09-07 11:15:52 +01:00
if ( ! questRequirementToAdd . _props . availableAfter . HasValue )
{
questRequirementToAdd . _props . availableAfter = 0 ;
}
2023-01-24 09:59:24 +00:00
2022-09-07 11:15:52 +01:00
if ( questRequirementToAdd . _props . visibilityConditions = = null | | ! questRequirementToAdd . _props . visibilityConditions . Any ( ) )
{
questRequirementToAdd . _props . visibilityConditions = new List < object > ( ) ;
}
questRequirementToAdd . _props . index = questToUpdate . Value . conditions . AvailableForStart . Count ;
2023-01-24 09:59:24 +00:00
2022-09-07 08:51:30 +01:00
}
2023-01-05 16:57:45 +00:00
// Already exists, skip
2023-01-24 09:59:24 +00:00
if ( questToUpdate . Value . conditions . AvailableForStart
2023-01-05 16:57:45 +00:00
. Any ( x = > x . _props . target ? . ToString ( ) = = questRequirementToAdd . _props . target ? . ToString ( )
& & x . _parent = = questRequirementToAdd . _parent ) )
{
continue ;
}
2022-01-09 20:36:05 +00:00
questToUpdate . Value . conditions . AvailableForStart . Add ( questRequirementToAdd ) ;
}
2023-01-05 16:57:45 +00:00
if ( questToUpdate . Value . conditions . AvailableForStart . Count ( x = > x . _parent = = "Quest" ) > 1 )
{
LoggingHelpers . LogWarning ( $"Quest {questToUpdate.Value.QuestName} has {questToUpdate.Value.conditions.AvailableForStart.Count(x => x._parent == " Quest ")} quest prereqs, is this correct?" ) ;
}
2022-01-09 20:36:05 +00:00
}
2022-09-07 11:15:52 +01:00
/// <summary>
/// Get a bsg happy guid, must be 24 chars long
/// </summary>
/// <param name="randomSalt"></param>
/// <returns></returns>
static string Sha256 ( string randomSalt )
2022-09-07 08:51:30 +01:00
{
var crypt = new System . Security . Cryptography . SHA256Managed ( ) ;
var hash = new System . Text . StringBuilder ( ) ;
2022-09-07 11:15:52 +01:00
byte [ ] crypto = crypt . ComputeHash ( Encoding . UTF8 . GetBytes ( randomSalt ) ) ;
2022-09-07 08:51:30 +01:00
foreach ( byte theByte in crypto )
{
hash . Append ( theByte . ToString ( "x2" ) ) ;
}
return hash . ToString ( ) . Substring ( 0 , 24 ) ;
}
2022-01-09 20:36:05 +00:00
/// <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 ;
}
2021-09-14 19:52:11 +01:00
}
}