2021-09-05 20:54:44 +01:00
using AssortGenerator.Common ;
using AssortGenerator.Common.Helpers ;
using AssortGenerator.Models.Input ;
using AssortGenerator.Models.Other ;
using AssortGenerator.Models.Output ;
using Common ;
2023-01-08 15:06:37 +00:00
using System ;
2021-09-05 20:54:44 +01:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text.Json ;
namespace AssortGenerator
{
2021-09-18 22:32:56 +01:00
public class Program
2021-09-05 20:54:44 +01:00
{
static void Main ( string [ ] args )
{
var assortsPath = CreateWorkingFolders ( ) ;
InputFileHelper . SetInputFiles ( assortsPath ) ;
// Get trader assort files from assorts input folder
var traderAssortFilePaths = InputFileHelper . GetInputFilePaths ( ) . Where ( x = > TraderHelper . GetTraders ( ) . Values . Any ( x . Contains ) ) . ToList ( ) ;
foreach ( var trader in TraderHelper . GetTraders ( ) )
{
// Get relevant trader dump
2023-01-03 10:46:33 +00:00
var assortDumpPath = traderAssortFilePaths . Find ( x = > x . Contains ( $"getTraderAssort.{trader.Value}" ) ) ;
2021-09-05 20:54:44 +01:00
2023-01-03 10:46:33 +00:00
// Convert input dump json into object
2021-09-05 20:54:44 +01:00
var json = File . ReadAllText ( assortDumpPath ) ;
var jsonObject = JsonDocument . Parse ( json ) ;
2023-01-03 10:46:33 +00:00
// Find root data node
2021-09-05 20:54:44 +01:00
var data = jsonObject . RootElement . GetProperty ( "data" ) ;
2023-01-03 10:46:33 +00:00
// Find assort items node and parse into list
2021-09-05 20:54:44 +01:00
string itemsJson = data . GetProperty ( "items" ) . ToString ( ) ;
List < Item > items = JsonSerializer . Deserialize < List < Item > > ( itemsJson ) ;
2023-01-03 10:46:33 +00:00
// Fix items that have ran out of stock in the dump and give stack size
FixZeroSizedStackAssorts ( items , 100 ) ;
2022-07-24 22:22:53 +01:00
2023-01-08 15:06:37 +00:00
FixFullyPurchasedStackLimits ( items ) ;
2023-01-03 10:46:33 +00:00
// Find barter scheme node and parse into dictionary
2021-09-05 20:54:44 +01:00
var barterSchemeJson = data . GetProperty ( "barter_scheme" ) . ToString ( ) ;
var barterSchemeItems = JsonSerializer . Deserialize < Dictionary < string , object > > ( barterSchemeJson ) ;
2023-01-03 10:46:33 +00:00
// Find loyalty level node and parse into dictionary
2021-09-05 20:54:44 +01:00
var loyaltyLevelItemsJson = data . GetProperty ( "loyal_level_items" ) . ToString ( ) ;
var loyaltyLevelItems = JsonSerializer . Deserialize < Dictionary < string , int > > ( loyaltyLevelItemsJson ) ;
WriteOutputFilesForTrader ( trader , items , barterSchemeItems , loyaltyLevelItems ) ;
}
}
2023-01-03 10:46:33 +00:00
private static void FixZeroSizedStackAssorts ( List < Item > items , int defaultStackSize )
{
foreach ( var item in items
. Where ( item = > item . upd ? . StackObjectsCount = = 0 & & item . slotId = = "hideout" ) )
{
LoggingHelpers . LogError ( $"item {item._tpl} found with stack count of 0, changing to {defaultStackSize}" ) ;
item . upd . StackObjectsCount = defaultStackSize ;
}
}
2023-01-08 15:06:37 +00:00
private static void FixFullyPurchasedStackLimits ( List < Item > items )
{
foreach ( var item in items
. Where ( item = > item . upd ? . BuyRestrictionCurrent > 0 & & item . slotId = = "hideout" ) )
{
LoggingHelpers . LogError ( $"item {item._tpl} found with stack count > 0, changing to 0" ) ;
item . upd . BuyRestrictionCurrent = 0 ;
}
}
2023-01-03 10:46:33 +00:00
/// <summary>
/// Create input/assorts/output/traders folders
/// </summary>
2021-09-05 20:54:44 +01:00
private static string CreateWorkingFolders ( )
{
var workingPath = Directory . GetCurrentDirectory ( ) ;
// create input folder
var inputPath = $"{workingPath}//input" ;
DiskHelpers . CreateDirIfDoesntExist ( inputPath ) ;
// create sub folder in input called assorts
var assortsPath = $"{inputPath}//assorts" ;
DiskHelpers . CreateDirIfDoesntExist ( assortsPath ) ;
// create output folder
var outputPath = $"{workingPath}//output" ;
DiskHelpers . CreateDirIfDoesntExist ( outputPath ) ;
// create traders sub-folder
var tradersPath = $"{outputPath}//traders" ;
DiskHelpers . CreateDirIfDoesntExist ( tradersPath ) ;
return assortsPath ;
}
2023-01-03 10:46:33 +00:00
/// <summary>
/// Parse raw tradersettings dump file into BaseRoot object
/// </summary>
/// <param name="filesInAssortsFolder">list of file paths</param>
/// <returns>BaseRoot</returns>
2021-09-05 20:54:44 +01:00
private static BaseRoot GetTraderData ( IEnumerable < string > filesInAssortsFolder )
{
var traderDataPath = filesInAssortsFolder . FirstOrDefault ( x = > x . Contains ( "resp.client.trading.api.traderSettings" ) ) ;
var traderDataJson = File . ReadAllText ( traderDataPath ) ;
return JsonSerializer . Deserialize < BaseRoot > ( traderDataJson ) ;
}
2023-01-03 10:46:33 +00:00
private static void WriteOutputFilesForTrader (
KeyValuePair < Trader , string > trader ,
2021-09-05 20:54:44 +01:00
List < Item > items ,
Dictionary < string , object >
barterSchemeItems ,
Dictionary < string , int > loyaltyLevelItems )
{
var workingPath = Directory . GetCurrentDirectory ( ) ;
var traderData = GetTraderData ( InputFileHelper . GetInputFilePaths ( ) ) ;
var traderFolderPath = $"traders\\{trader.Value}" ;
2023-01-03 10:46:33 +00:00
// Create assort file, serialise into json and save into output folder
2021-09-05 20:54:44 +01:00
var outputAssortFile = new AssortRoot
{
items = items ,
barter_scheme = barterSchemeItems ,
loyal_level_items = loyaltyLevelItems
} ;
2022-07-21 22:08:33 +01:00
JsonWriter . WriteJson ( outputAssortFile , traderFolderPath , workingPath , "assort" ) ;
2021-09-05 20:54:44 +01:00
// create base file, serialise into json and save into output folder
var outputBaseFile = traderData . data . Find ( x = > x . _id = = trader . Value ) ;
JsonWriter . WriteJson ( outputBaseFile , traderFolderPath , workingPath , "base" ) ;
QuestAssort questAssort = GenerateQuestAssort ( trader . Key , outputAssortFile ) ;
JsonWriter . WriteJson ( questAssort , traderFolderPath , workingPath , "questassort" ) ;
// create suits file for ragman
if ( trader . Key = = Trader . Ragman )
{
2023-01-03 10:46:33 +00:00
CreateRagmanSuitsFile ( workingPath , traderFolderPath ) ;
}
}
2021-09-05 20:54:44 +01:00
2023-01-03 10:46:33 +00:00
/// <summary>
/// merges bear and usec ragman clothing dumps into one file
/// </summary>
/// <param name="trader"></param>
/// <param name="workingPath"></param>
/// <param name="traderFolderPath"></param>
private static void CreateRagmanSuitsFile ( string workingPath , string traderFolderPath )
{
var suitFileNames = new List < string > ( ) ;
suitFileNames . Add ( "usec.resp.client.trading.customization." ) ;
suitFileNames . Add ( "bear.resp.client.trading.customization." ) ;
var outputSuitData = new List < Suit > ( ) ;
foreach ( var suitSideFilename in suitFileNames )
{
var customisationFilePath = InputFileHelper . GetInputFilePaths ( ) . FirstOrDefault ( x = > x . Contains ( suitSideFilename ) ) ;
if ( string . IsNullOrEmpty ( customisationFilePath ) )
{
LoggingHelpers . LogWarning ( $"no suit file found: {suitSideFilename}, skipped" ) ;
continue ;
}
2021-09-05 20:54:44 +01:00
2023-01-03 10:46:33 +00:00
var traderDataJson = File . ReadAllText ( customisationFilePath ) ;
if ( traderDataJson ! = null )
{
var suitData = JsonSerializer . Deserialize < CustomisationRoot > ( traderDataJson ) ;
outputSuitData . AddRange ( suitData . data ) ;
}
2021-09-05 20:54:44 +01:00
}
2023-01-03 10:46:33 +00:00
JsonWriter . WriteJson ( outputSuitData , traderFolderPath , workingPath , "suits" ) ;
2021-09-05 20:54:44 +01:00
}
2023-01-03 10:46:33 +00:00
/// <summary>
/// Create quest assort file that links quest completions to trader assort unlocks
/// </summary>
/// <param name="trader"></param>
/// <param name="assortRoot"></param>
/// <returns></returns>
2021-09-05 20:54:44 +01:00
private static QuestAssort GenerateQuestAssort ( Trader trader , AssortRoot assortRoot )
{
var result = new QuestAssort ( ) ;
var questData = QuestHelper . GetQuestData ( ) ;
2023-01-03 10:46:33 +00:00
// Find assort unlocks
2021-09-05 20:54:44 +01:00
List < AssortUnlocks > assortUnlocks = QuestHelper . GetAssortUnlocks ( ) ;
2023-01-03 10:46:33 +00:00
var assortItemsThatMatchBlackList = new List < string > ( ) ; // store items already matched here
2021-09-05 20:54:44 +01:00
// TODO: find out how the fuck the assort unlock is associated to the quest
foreach ( var assortUnlock in assortUnlocks . Where ( x = > x . TraderType = = trader ) )
{
2023-01-03 10:46:33 +00:00
if ( assortUnlock . AssortUnlockId = = "5ac653ed86f77405d4729344" )
{
var x = 2 ;
}
2021-09-05 20:54:44 +01:00
2023-01-03 10:46:33 +00:00
// Get unlock items name
var assortItemName = ItemTemplateHelper . Items
. FirstOrDefault ( x = > x . Key = = assortUnlock . ItemUnlockedTemplateId ) . Value . _name ;
2021-09-05 20:54:44 +01:00
// TODO: handle started
// TODO: handle fail
2023-01-03 10:46:33 +00:00
// Handle quest success for now
if ( assortUnlock . Criteria . ToLower ( ) = = "success" )
2021-09-05 20:54:44 +01:00
{
//Find assorts that match the quest unlocks item template
2023-01-03 10:46:33 +00:00
List < Item > assortItemsThatMatch = assortRoot . items
. Where ( x = > x . _tpl = = assortUnlock . ItemUnlockedTemplateId & & x . slotId = = "hideout" )
. ToList ( ) ;
2021-09-05 20:54:44 +01:00
2023-01-03 10:46:33 +00:00
// No assort found for this unlock, log and skip it
2021-09-05 20:54:44 +01:00
if ( assortItemsThatMatch = = null | | assortItemsThatMatch . Count = = 0 )
{
LoggingHelpers . LogError ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {assortUnlock.QuestId}. no assort item found. ({assortItemName})" ) ;
continue ;
}
2023-01-03 10:46:33 +00:00
// Iterate over assorts that match. goal is to find assort that fits the best
// (assort has same loyalty level unlock as quest expects)
2021-09-05 20:54:44 +01:00
string assortIdUnlockedByQuest = string . Empty ;
foreach ( var match in assortItemsThatMatch )
{
// Look up item in Loyalty Level array
2023-01-03 10:46:33 +00:00
var associatedLoyaltyLevelItem = assortRoot . loyal_level_items
. FirstOrDefault ( x = > x . Key = = match . _id ) ;
2021-09-05 20:54:44 +01:00
if ( associatedLoyaltyLevelItem . Key = = null )
{
2023-01-03 10:46:33 +00:00
// Skip item if no record found in loyalty level array
LoggingHelpers . LogError ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. no loyalty record found. " ) ;
continue ;
2021-09-05 20:54:44 +01:00
}
if ( associatedLoyaltyLevelItem . Value ! = assortUnlock . LoyaltyLevel )
{
2023-01-03 10:46:33 +00:00
// Loyalty level is different to what was expected, skip and try next
LoggingHelpers . LogWarning ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. no match found in LL array. expected LL{associatedLoyaltyLevelItem.Value}. found: LL{assortUnlock.LoyaltyLevel}" ) ;
2021-09-05 21:35:28 +01:00
continue ;
}
// LoggingHelpers.LogInfo($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} {assortItemName}. MATCH FOUND. LL{assortUnlock.LoyaltyLevel}");
if ( assortItemsThatMatchBlackList . Contains ( associatedLoyaltyLevelItem . Key ) )
{
// Not the item we want, its already been matched
2021-09-05 20:54:44 +01:00
continue ;
}
2021-09-05 21:35:28 +01:00
// Add assort item id to blacklist so it wont be matched again
assortItemsThatMatchBlackList . Add ( associatedLoyaltyLevelItem . Key ) ;
// assign id and break out of loop, We found the one we want
2021-09-05 20:54:44 +01:00
assortIdUnlockedByQuest = associatedLoyaltyLevelItem . Key ;
2021-09-05 21:35:28 +01:00
break ;
2021-09-05 20:54:44 +01:00
}
2023-01-03 10:46:33 +00:00
2021-09-05 21:35:28 +01:00
if ( result . success . ContainsKey ( assortIdUnlockedByQuest ) )
2021-09-05 20:54:44 +01:00
{
2023-01-03 10:46:33 +00:00
LoggingHelpers . LogWarning ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. ALREADY EXISTS. SKIPPING" ) ;
2021-09-05 20:54:44 +01:00
continue ;
}
2023-01-03 10:46:33 +00:00
if ( assortIdUnlockedByQuest . Length = = 0 )
2021-09-05 21:35:28 +01:00
{
2023-01-03 10:46:33 +00:00
LoggingHelpers . LogError ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. no assortId found" ) ;
2021-09-05 21:35:28 +01:00
continue ;
}
2023-01-03 10:46:33 +00:00
LoggingHelpers . LogSuccess ( $"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. ADDING TO QUEST-ASSORT" ) ;
2021-09-05 21:35:28 +01:00
result . success . Add ( assortIdUnlockedByQuest , assortUnlock . QuestId ) ;
2021-09-05 20:54:44 +01:00
}
2023-01-03 10:46:33 +00:00
if ( assortUnlock . Criteria . ToLower ( ) = = "fail" )
{
LoggingHelpers . LogError ( "Fail quest criteria not handled" ) ;
}
if ( assortUnlock . Criteria . ToLower ( ) = = "started" )
{
LoggingHelpers . LogError ( "started quest criteria not handled" ) ;
}
2021-09-05 20:54:44 +01:00
}
return result ;
}
}
}