using AssortGenerator.Common; using AssortGenerator.Common.Helpers; using AssortGenerator.Models.Input; using AssortGenerator.Models.Other; using AssortGenerator.Models.Output; using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; namespace AssortGenerator { public class Program { 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 var assortDumpPath = traderAssortFilePaths.Find(x => x.Contains($"getTraderAssort.{trader.Value}")); if (assortDumpPath == null) { assortDumpPath = traderAssortFilePaths.Find(x => x.Contains($"{trader.Value}") && x.Contains("getTraderAssort")); } // Convert input dump json into object var json = File.ReadAllText(assortDumpPath); var jsonObject = JsonDocument.Parse(json); // Find root data node var data = jsonObject.RootElement; // Find assort items node and parse into list string itemsJson = data.GetProperty("items").ToString(); List items = JsonSerializer.Deserialize>(itemsJson); // Fix items that have ran out of stock in the dump and give stack size FixZeroSizedStackAssorts(items, 100); FixFullyPurchasedStackLimits(items); // Find barter scheme node and parse into dictionary var barterSchemeJson = data.GetProperty("barter_scheme").ToString(); var barterSchemeItems = JsonSerializer.Deserialize>(barterSchemeJson); // Find loyalty level node and parse into dictionary var loyaltyLevelItemsJson = data.GetProperty("loyal_level_items").ToString(); var loyaltyLevelItems = JsonSerializer.Deserialize>(loyaltyLevelItemsJson); WriteOutputFilesForTrader(trader, items, barterSchemeItems, loyaltyLevelItems); } } private static void FixZeroSizedStackAssorts(List 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}"); if (item.upd?.BuyRestrictionMax != null) { var parsedRestrictionMax = int.Parse(item.upd?.BuyRestrictionMax.ToString()); if (parsedRestrictionMax > defaultStackSize) { item.upd.StackObjectsCount = parsedRestrictionMax; continue; } } item.upd.StackObjectsCount = defaultStackSize; } } private static void FixFullyPurchasedStackLimits(List 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; } } /// /// Create input/assorts/output/traders folders /// 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; } /// /// Parse raw tradersettings dump file into BaseRoot object /// /// list of file paths /// BaseRoot private static BaseRoot GetTraderData(IEnumerable filesInAssortsFolder) { var traderDataPath = filesInAssortsFolder.FirstOrDefault(x => x.Contains("resp.client.trading.api.traderSettings")); var traderDataJson = File.ReadAllText(traderDataPath); return JsonSerializer.Deserialize(traderDataJson); } private static void WriteOutputFilesForTrader( KeyValuePair trader, List items, Dictionary barterSchemeItems, Dictionary loyaltyLevelItems) { var workingPath = Directory.GetCurrentDirectory(); var traderData = GetTraderData(InputFileHelper.GetInputFilePaths()); var traderFolderPath = $"traders\\{trader.Value}"; // Create assort file, serialise into json and save into output folder var outputAssortFile = new AssortRoot { items = items, barter_scheme = barterSchemeItems, loyal_level_items = loyaltyLevelItems }; JsonWriter.WriteJson(outputAssortFile, traderFolderPath, workingPath, "assort"); // 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) { CreateRagmanSuitsFile(workingPath, traderFolderPath); } } /// /// merges bear and usec ragman clothing dumps into one file /// /// /// /// private static void CreateRagmanSuitsFile(string workingPath, string traderFolderPath) { var suitFileNames = new List(); suitFileNames.Add("usec.resp.client.trading.customization."); suitFileNames.Add("bear.resp.client.trading.customization."); var outputSuitData = new List(); 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; } var traderDataJson = File.ReadAllText(customisationFilePath); if (traderDataJson != null) { var suitData = JsonSerializer.Deserialize(traderDataJson); outputSuitData.AddRange(suitData.data); } } JsonWriter.WriteJson(outputSuitData, traderFolderPath, workingPath, "suits"); } /// /// Create quest assort file that links quest completions to trader assort unlocks /// /// /// /// private static QuestAssort GenerateQuestAssort(Trader trader, AssortRoot assortRoot) { var result = new QuestAssort(); var questData = QuestHelper.GetQuestData(); // Find assort unlocks List assortUnlocks = QuestHelper.GetAssortUnlocks(); var assortItemsThatMatchBlackList = new List(); // store items already matched here // TODO: find out how the fuck the assort unlock is associated to the quest foreach (var assortUnlock in assortUnlocks.Where(x => x.TraderType == trader)) { if (assortUnlock.AssortUnlockId == "5ac653ed86f77405d4729344") { var x = 2; } // Get unlock items name var assortItemName = ItemTemplateHelper.Items .FirstOrDefault(x=> x.Key == assortUnlock.ItemUnlockedTemplateId).Value._name; // TODO: handle started // TODO: handle fail // Handle quest success for now if (assortUnlock.Criteria.ToLower() == "success") { //Find assorts that match the quest unlocks item template List assortItemsThatMatch = assortRoot.items .Where(x => x._tpl == assortUnlock.ItemUnlockedTemplateId && x.slotId == "hideout") .ToList(); // No assort found for this unlock, log and skip it if (assortItemsThatMatch == null || assortItemsThatMatch.Count == 0) { LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {assortUnlock.QuestId}. no assort item found. ({assortItemName})"); continue; } // Iterate over assorts that match. goal is to find assort that fits the best // (assort has same loyalty level unlock as quest expects) string assortIdUnlockedByQuest = string.Empty; foreach (var match in assortItemsThatMatch) { // Look up item in Loyalty Level array var associatedLoyaltyLevelItem = assortRoot.loyal_level_items .FirstOrDefault(x => x.Key == match._id); if (associatedLoyaltyLevelItem.Key == null) { // 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; } if (associatedLoyaltyLevelItem.Value != assortUnlock.LoyaltyLevel) { // 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}"); 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 continue; } // 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 assortIdUnlockedByQuest = associatedLoyaltyLevelItem.Key; break; } if (result.success.ContainsKey(assortIdUnlockedByQuest)) { LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. ALREADY EXISTS. SKIPPING"); continue; } if (assortIdUnlockedByQuest.Length == 0) { LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. no assortId found"); continue; } LoggingHelpers.LogSuccess($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. ADDING TO QUEST-ASSORT"); result.success.Add(assortIdUnlockedByQuest, assortUnlock.QuestId); } if (assortUnlock.Criteria.ToLower() == "fail") { LoggingHelpers.LogError("Fail quest criteria not handled"); } if (assortUnlock.Criteria.ToLower() == "started") { LoggingHelpers.LogError("started quest criteria not handled"); } } return result; } } }