Rework assorting finding code with score-based system
This commit is contained in:
parent
4e20e6a03b
commit
309b882796
@ -23,6 +23,30 @@ namespace AssortGenerator.Common.Helpers
|
||||
return _questData;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Quest> GetFinalisedQuestData()
|
||||
{
|
||||
var questFilePath = InputFileHelper.GetInputFilePaths().FirstOrDefault(x => x.Contains("quests.json"));
|
||||
var questDataJson = File.ReadAllText(questFilePath);
|
||||
var finalisedQuestData = JsonSerializer.Deserialize<Dictionary<string, Quest>> (questDataJson);
|
||||
|
||||
var jsondoc = JsonDocument.Parse(questDataJson);
|
||||
var root = jsondoc.RootElement;
|
||||
|
||||
|
||||
|
||||
return finalisedQuestData;
|
||||
}
|
||||
|
||||
public static JsonDocument GetFinalisedQuestDataJsonDoc()
|
||||
{
|
||||
var questFilePath = InputFileHelper.GetInputFilePaths().FirstOrDefault(x => x.Contains("quests.json"));
|
||||
var questDataJson = File.ReadAllText(questFilePath);
|
||||
|
||||
var jsondoc = JsonDocument.Parse(questDataJson);
|
||||
|
||||
return jsondoc;
|
||||
}
|
||||
|
||||
public static List<AssortUnlocks> GetAssortUnlocks()
|
||||
{
|
||||
if (_assortUnlocks == null)
|
||||
@ -30,6 +54,12 @@ namespace AssortGenerator.Common.Helpers
|
||||
_assortUnlocks = new List<AssortUnlocks>();
|
||||
foreach (var quest in GetQuestData().data)
|
||||
{
|
||||
// debut
|
||||
if (quest._id == "5936d90786f7742b1420ba5b")
|
||||
{
|
||||
var x = 2;
|
||||
}
|
||||
|
||||
foreach (var reward in quest.rewards.Success)
|
||||
{
|
||||
if (string.Equals(reward.type, "assortmentunlock", System.StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using AssortGenerator.Models.Output;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AssortGenerator.Models.Input
|
||||
{
|
||||
@ -11,7 +12,18 @@ namespace AssortGenerator.Models.Input
|
||||
|
||||
public class Quest
|
||||
{
|
||||
public string QuestName { get; set; }
|
||||
public string _id { get; set; }
|
||||
public bool canShowNotificationsInGame { get; set; }
|
||||
public string acceptPlayerMessage { get; set; }
|
||||
public string changeQuestMessageText { get; set; }
|
||||
public string completePlayerMessage { get; set; }
|
||||
public object conditions { get; set; }
|
||||
public string description { get; set; }
|
||||
public string failMessageText { get; set; }
|
||||
public string name { get; set; }
|
||||
public string note { get; set; }
|
||||
public object questStatus { get; set; }
|
||||
public string traderId { get; set; }
|
||||
public string location { get; set; }
|
||||
public string image { get; set; }
|
||||
@ -20,9 +32,11 @@ namespace AssortGenerator.Models.Input
|
||||
public bool restartable { get; set; }
|
||||
public bool instantComplete { get; set; }
|
||||
public bool secretQuest { get; set; }
|
||||
public int min_level { get; set; }
|
||||
public bool canShowNotificationsInGame { get; set; }
|
||||
public string startedMessageText { get; set; }
|
||||
public string successMessageText { get; set; }
|
||||
public string templateId { get; set; }
|
||||
public Rewards rewards { get; set; }
|
||||
public string side { get; set; }
|
||||
}
|
||||
|
||||
public class Rewards
|
||||
@ -42,13 +56,15 @@ namespace AssortGenerator.Models.Input
|
||||
public List<QuestRewardItem> items { get; set; }
|
||||
public int? loyaltyLevel { get; set; }
|
||||
public string traderId { get; set; }
|
||||
public bool? findInRaid { get; set; }
|
||||
public bool? unknown { get; set; }
|
||||
}
|
||||
|
||||
public class QuestRewardItem
|
||||
{
|
||||
public string _id { get; set; }
|
||||
public string _tpl { get; set; }
|
||||
public QuestRewardUpd upd { get; set; }
|
||||
public object upd { get; set; }
|
||||
public string parentId { get; set; }
|
||||
public string slotId { get; set; }
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace AssortGenerator.Models.Output
|
||||
public class AssortRoot
|
||||
{
|
||||
public List<Item> items { get; set; }
|
||||
public Dictionary<string, object> barter_scheme { get; set; }
|
||||
public Dictionary<string, List<List<BarterObject>>> barter_scheme { get; set; }
|
||||
public Dictionary<string, int> loyal_level_items { get; set; }
|
||||
}
|
||||
|
||||
@ -31,7 +31,11 @@ namespace AssortGenerator.Models.Output
|
||||
|
||||
public class BarterObject
|
||||
{
|
||||
public int count { get; set; }
|
||||
// Can be int or decimal, thanks bsg
|
||||
public object count { get; set; }
|
||||
public string _tpl { get; set; }
|
||||
public int? level { get; set; }
|
||||
public string side { get; set; }
|
||||
public bool? onlyFunctional { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using AssortGenerator.Models.Output;
|
||||
using Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
@ -21,15 +22,12 @@ namespace AssortGenerator
|
||||
|
||||
// Get trader assort files from assorts input folder
|
||||
var traderAssortFilePaths = InputFileHelper.GetInputFilePaths().Where(x => TraderHelper.GetTraders().Values.Any(x.Contains)).ToList();
|
||||
|
||||
var finalisedQuestData = QuestHelper.GetFinalisedQuestData();
|
||||
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"));
|
||||
}
|
||||
assortDumpPath ??= traderAssortFilePaths.Find(x => x.Contains($"{trader.Value}") && x.Contains("getTraderAssort"));
|
||||
|
||||
// Convert input dump json into object
|
||||
var json = File.ReadAllText(assortDumpPath);
|
||||
@ -49,14 +47,16 @@ namespace AssortGenerator
|
||||
|
||||
// Find barter scheme node and parse into dictionary
|
||||
var barterSchemeJson = data.GetProperty("barter_scheme").ToString();
|
||||
var barterSchemeItems = JsonSerializer.Deserialize<Dictionary<string, object>>(barterSchemeJson);
|
||||
var barterSchemeItems = JsonSerializer.Deserialize<Dictionary<string, List<List<BarterObject>>>>(barterSchemeJson);
|
||||
|
||||
// Find loyalty level node and parse into dictionary
|
||||
var loyaltyLevelItemsJson = data.GetProperty("loyal_level_items").ToString();
|
||||
var loyaltyLevelItems = JsonSerializer.Deserialize<Dictionary<string, int>>(loyaltyLevelItemsJson);
|
||||
|
||||
WriteOutputFilesForTrader(trader, items, barterSchemeItems, loyaltyLevelItems);
|
||||
WriteOutputFilesForTrader(trader, items, barterSchemeItems, loyaltyLevelItems, finalisedQuestData);
|
||||
}
|
||||
|
||||
JsonWriter.WriteJson(finalisedQuestData, "", Directory.GetCurrentDirectory(), "quests");
|
||||
}
|
||||
|
||||
private static void FixZeroSizedStackAssorts(List<Item> items, int defaultStackSize)
|
||||
@ -129,9 +129,9 @@ namespace AssortGenerator
|
||||
private static void WriteOutputFilesForTrader(
|
||||
KeyValuePair<Trader, string> trader,
|
||||
List<Item> items,
|
||||
Dictionary<string, object>
|
||||
barterSchemeItems,
|
||||
Dictionary<string, int> loyaltyLevelItems)
|
||||
Dictionary<string, List<List<BarterObject>>> barterSchemeItems,
|
||||
Dictionary<string, int> loyaltyLevelItems,
|
||||
Dictionary<string, Quest> finalisedQuestData)
|
||||
{
|
||||
var workingPath = Directory.GetCurrentDirectory();
|
||||
|
||||
@ -151,7 +151,7 @@ namespace AssortGenerator
|
||||
var outputBaseFile = traderData.data.Find(x => x._id == trader.Value);
|
||||
JsonWriter.WriteJson(outputBaseFile, traderFolderPath, workingPath, "base");
|
||||
|
||||
QuestAssort questAssort = GenerateQuestAssort(trader.Key, outputAssortFile);
|
||||
QuestAssort questAssort = GenerateQuestAssortForTrader(trader.Key, outputAssortFile);
|
||||
JsonWriter.WriteJson(questAssort, traderFolderPath, workingPath, "questassort");
|
||||
|
||||
// create suits file for ragman
|
||||
@ -199,7 +199,7 @@ namespace AssortGenerator
|
||||
/// <param name="trader"></param>
|
||||
/// <param name="assortRoot"></param>
|
||||
/// <returns></returns>
|
||||
private static QuestAssort GenerateQuestAssort(Trader trader, AssortRoot assortRoot)
|
||||
private static QuestAssort GenerateQuestAssortForTrader(Trader trader, AssortRoot assortRoot)
|
||||
{
|
||||
var result = new QuestAssort();
|
||||
var questData = QuestHelper.GetQuestData();
|
||||
@ -209,9 +209,10 @@ namespace AssortGenerator
|
||||
|
||||
// Store already matched items
|
||||
var assortItemsThatMatchBlackList = new List<string>();
|
||||
int unknownCount = 1;
|
||||
foreach (var assortUnlock in assortUnlocks.Where(x => x.TraderType == trader))
|
||||
{
|
||||
if (assortUnlock.ItemUnlockedTemplateId == "58948c8e86f77409493f7266")
|
||||
if (assortUnlock.QuestId == "64764abcd125ab430a14ccb5")
|
||||
{
|
||||
var x = 2;
|
||||
}
|
||||
@ -219,106 +220,41 @@ namespace AssortGenerator
|
||||
// Get unlock item details
|
||||
var assortItemDetailsDB = ItemTemplateHelper.Items.FirstOrDefault(x => x.Key == assortUnlock.ItemUnlockedTemplateId);
|
||||
var ItemName = assortItemDetailsDB.Value._name;
|
||||
var assortItemMods = assortUnlock.Items.Where(x => x.parentId == assortUnlock.ItemUnlockedId);
|
||||
var assortItemModsFromQuest = assortUnlock.Items.Where(x => x.parentId == assortUnlock.ItemUnlockedId);
|
||||
|
||||
//Find assorts that match the quest unlocks item template
|
||||
List<Item> 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)
|
||||
// Get matching assorts from trader
|
||||
var results = GetMatchingTraderAssortsWithScore(assortRoot, assortUnlock, trader, assortItemsThatMatchBlackList);
|
||||
if (results.Keys.Count == 0)
|
||||
{
|
||||
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {assortUnlock.QuestId}. no assort item found. ({ItemName})");
|
||||
// no assort found for this unlock, add to questassort with a placeholder value instead of assort id
|
||||
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. no assortId found");
|
||||
|
||||
result.success.Add($"UnknownAssortId{unknownCount}", assortUnlock.QuestId);
|
||||
unknownCount++;
|
||||
|
||||
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);
|
||||
var highestScoringAssortIdMatch = results.OrderByDescending(x => x.Value).First().Key;
|
||||
|
||||
if (associatedLoyaltyLevelItem.Key == null)
|
||||
{
|
||||
// Skip item if no record found in loyalty level array
|
||||
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. no loyalty record found. ");
|
||||
continue;
|
||||
}
|
||||
// Add assort item id to blacklist so it wont be matched again
|
||||
assortItemsThatMatchBlackList.Add(highestScoringAssortIdMatch);
|
||||
|
||||
if (associatedLoyaltyLevelItem.Value != assortUnlock.LoyaltyLevel)
|
||||
{
|
||||
// Loyalty level is different to what was expected, skip and try next
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). 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;
|
||||
}
|
||||
|
||||
// Try matching by mods on item if they exist
|
||||
if (assortItemMods.Any())
|
||||
{
|
||||
var matchedItemMods = assortRoot.items.Where(x => x.parentId == match._id).ToList();
|
||||
if (assortItemMods.Count() != matchedItemMods.Count)
|
||||
{
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. mismatch of mod count, skipping");
|
||||
continue;
|
||||
}
|
||||
var badMatch = false;
|
||||
foreach (var desiredMod in assortItemMods)
|
||||
{
|
||||
var matchingModInCurrentMatch = matchedItemMods.FirstOrDefault(x => x._tpl == desiredMod._tpl);
|
||||
if (matchingModInCurrentMatch == null)
|
||||
{
|
||||
badMatch = true;
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. mismatch of mods, skipping");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (badMatch)
|
||||
{
|
||||
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))
|
||||
if (result.success.ContainsKey(highestScoringAssortIdMatch))
|
||||
{
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. ALREADY EXISTS. SKIPPING");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assortIdUnlockedByQuest.Length == 0)
|
||||
{
|
||||
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. no assortId found");
|
||||
continue;
|
||||
}
|
||||
|
||||
LoggingHelpers.LogSuccess($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({ItemName}). questId: {assortUnlock.QuestId}. ADDING TO QUEST-ASSORT");
|
||||
|
||||
if (assortUnlock.Criteria == "Success")
|
||||
{
|
||||
result.success.Add(assortIdUnlockedByQuest, assortUnlock.QuestId);
|
||||
result.success.Add(highestScoringAssortIdMatch, assortUnlock.QuestId);
|
||||
}
|
||||
else if (assortUnlock.Criteria == "Started")
|
||||
{
|
||||
result.started.Add(assortIdUnlockedByQuest, assortUnlock.QuestId);
|
||||
result.started.Add(highestScoringAssortIdMatch, assortUnlock.QuestId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -341,5 +277,125 @@ namespace AssortGenerator
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of matching assorts with a score of how well they match the quest assort requirements
|
||||
/// </summary>
|
||||
/// <param name="traderAssortRoot">Traders assort items/barter/loyalty</param>
|
||||
/// <param name="assortUnlock"></param>
|
||||
/// <param name="trader"></param>
|
||||
/// <param name="assortItemsThatMatchBlackList"></param>
|
||||
/// <returns></returns>
|
||||
private static Dictionary<string, int> GetMatchingTraderAssortsWithScore(
|
||||
AssortRoot traderAssortRoot,
|
||||
AssortUnlocks assortUnlock,
|
||||
Trader trader,
|
||||
IEnumerable<string> assortItemsThatMatchBlackList)
|
||||
{
|
||||
var quests = QuestHelper.GetFinalisedQuestData();
|
||||
var assortItemDetailsDB = ItemTemplateHelper.Items.FirstOrDefault(x => x.Key == assortUnlock.ItemUnlockedTemplateId);
|
||||
var assortItemName = assortItemDetailsDB.Value._name;
|
||||
var assortItemModsFromQuest = assortUnlock.Items.Where(x => x.parentId == assortUnlock.ItemUnlockedId);
|
||||
|
||||
// assort id + score
|
||||
var matchScores = new Dictionary<string, int>();
|
||||
List<Item> assortItemsThatMatch = traderAssortRoot.items
|
||||
.Where(x => x._tpl == assortUnlock.ItemUnlockedTemplateId && x.slotId == "hideout")
|
||||
.ToList();
|
||||
|
||||
if (assortItemsThatMatch?.Count == 0)
|
||||
{
|
||||
LoggingHelpers.LogError($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {assortUnlock.QuestId}. No matches found. ");
|
||||
return matchScores;
|
||||
}
|
||||
|
||||
if (assortItemsThatMatch?.Count > 2)
|
||||
{
|
||||
var questData = quests.FirstOrDefault(x => x.Key == assortUnlock.QuestId);
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId}. questId: {questData.Value.QuestName}. multiple matches found. ");
|
||||
}
|
||||
|
||||
// Only one result, no need to work out score
|
||||
if (assortItemsThatMatch.Count == 1)
|
||||
{
|
||||
matchScores[assortItemsThatMatch[0]._id] = 1;
|
||||
return matchScores;
|
||||
}
|
||||
|
||||
foreach (var assortItemMatch in assortItemsThatMatch)
|
||||
{
|
||||
matchScores[assortItemMatch._id] = 0;
|
||||
var itemBarter = traderAssortRoot.barter_scheme[assortItemMatch._id];
|
||||
var barterItems = itemBarter.First();
|
||||
if (barterItems.Count == 1 && TplIsMoney(barterItems[0]._tpl))
|
||||
{
|
||||
matchScores[assortItemMatch._id] += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchScores[assortItemMatch._id] += 1;
|
||||
}
|
||||
|
||||
// Look up item in Loyalty Level array
|
||||
var associatedLoyaltyLevelItem = traderAssortRoot.loyal_level_items
|
||||
.FirstOrDefault(x => x.Key == assortItemMatch._id);
|
||||
|
||||
if (associatedLoyaltyLevelItem.Value == assortUnlock.LoyaltyLevel)
|
||||
{
|
||||
// Loyalty level matches
|
||||
matchScores[assortItemMatch._id] += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchScores[assortItemMatch._id] -= 25;
|
||||
}
|
||||
|
||||
if (assortItemsThatMatchBlackList.Contains(associatedLoyaltyLevelItem.Key))
|
||||
{
|
||||
// Not the item we want, its already been matched
|
||||
matchScores[assortItemMatch._id] -= 25;
|
||||
}
|
||||
|
||||
// Try matching by mods on item if they exist
|
||||
if (assortItemModsFromQuest.Any())
|
||||
{
|
||||
var matchedItemMods = traderAssortRoot.items.Where(x => x.parentId == assortItemMatch._id).ToList();
|
||||
if (assortItemModsFromQuest.Count() == matchedItemMods.Count)
|
||||
{
|
||||
// mod count from quest matches trader assort
|
||||
matchScores[assortItemMatch._id] += 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. mismatch of mod count, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var desiredMod in assortItemModsFromQuest)
|
||||
{
|
||||
// Compare each mod item in turn
|
||||
var matchingModInCurrentMatch = matchedItemMods.FirstOrDefault(x => x._tpl == desiredMod._tpl);
|
||||
if (matchingModInCurrentMatch != null)
|
||||
{
|
||||
matchScores[assortItemMatch._id] += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoggingHelpers.LogWarning($"{trader} item templateId: {assortUnlock.ItemUnlockedTemplateId} ({assortItemName}). questId: {assortUnlock.QuestId}. mismatch of mods, skipping");
|
||||
matchScores[assortItemMatch._id] -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return matchScores;
|
||||
}
|
||||
|
||||
private static bool TplIsMoney(string tpl)
|
||||
{
|
||||
var moneyTpls = new string[] { "5449016a4bdc2d6f028b456f", "569668774bdc2da2298b4568", "5696686a4bdc2da3298b456a" };
|
||||
return moneyTpls.Contains(tpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user