391 lines
15 KiB
C#
391 lines
15 KiB
C#
|
using AssortValidator.Common;
|
|||
|
using AssortValidator.Common.Helpers;
|
|||
|
using AssortValidator.Common.Helpers.Models;
|
|||
|
using AssortValidator.Common.Models;
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
|
|||
|
namespace AssortValidator
|
|||
|
{
|
|||
|
public static class AssortItemChecker
|
|||
|
{
|
|||
|
public static void CheckAssortValues(Dictionary<Trader, Assort> assortData, Dictionary<Trader, Assort> liveAssortData)
|
|||
|
{
|
|||
|
List<QuestAssortUnlock> questAssortUnlocks = QuestHelper.GetQuestAssortUnlocks(QuestHelper.GetQuestDataFromDump().Values);
|
|||
|
foreach (var trader in assortData)
|
|||
|
{
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
LoggingHelpers.LogHeading($"Checking Trader: {trader.Key}");
|
|||
|
|
|||
|
var correspondingLiveTrader = liveAssortData[trader.Key];
|
|||
|
if (correspondingLiveTrader == null)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"Unable to find live trader: {trader.Key}");
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
foreach (var assort in trader.Value.items.Where(x => x.parentId == "hideout"))
|
|||
|
{
|
|||
|
var itemName = ItemTemplateHelper.GetTemplateById(assort._tpl)._name;
|
|||
|
int assortLoyaltyLevel = AssortHelper.GetAssortLoyaltyLevel(assort._id, trader.Value);
|
|||
|
|
|||
|
LoggingHelpers.LogInfo($"{trader.Key}: itemId: {assort._id} - tpId: {assort._tpl} ({itemName}) Level {assortLoyaltyLevel}");
|
|||
|
LogUnlockQuest(questAssortUnlocks, assort, assortLoyaltyLevel);
|
|||
|
|
|||
|
var liveAssort = GetLiveAssort(correspondingLiveTrader, assort._tpl, assortLoyaltyLevel);
|
|||
|
if (liveAssort == null)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Check if upd objects match ( both exist or both dont exist)
|
|||
|
if (!DoesLiveAssortUpdMatchOffline(assort, liveAssort, itemName))
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
var offlineBarterData = trader.Value.barter_scheme.FirstOrDefault(x => x.Key == assort._id).Value;
|
|||
|
var liveBarterData = correspondingLiveTrader.barter_scheme.FirstOrDefault(x => x.Key == liveAssort._id).Value;
|
|||
|
if (assort.upd != null)
|
|||
|
{
|
|||
|
CheckUpdValues(assort, liveAssort);
|
|||
|
|
|||
|
// Iterate over assort barter items
|
|||
|
// Assorts live barter data
|
|||
|
for (int i = 0; i < offlineBarterData.Count; i++)
|
|||
|
{
|
|||
|
var liveItem = liveBarterData[i];
|
|||
|
|
|||
|
// Create list of offline barter items for assort
|
|||
|
var offlineBarterItems = new List<Assort.BarterDetails>();
|
|||
|
foreach (var foundItem in offlineBarterData)
|
|||
|
{
|
|||
|
foreach (var item in foundItem)
|
|||
|
{
|
|||
|
offlineBarterItems.Add(item);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LogAssortType(offlineBarterItems, "Existing");
|
|||
|
|
|||
|
if (offlineBarterItems.Count != liveItem.Count)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"assort {assort._id} barter item count mismatch, found {offlineBarterItems.Count}, expected {liveItem.Count}");
|
|||
|
LoggingHelpers.LogError("Found:");
|
|||
|
foreach (var foundItem in offlineBarterItems)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"{foundItem._tpl} ({ItemTemplateHelper.GetTemplateById(foundItem._tpl)._name}) x{foundItem.count}");
|
|||
|
}
|
|||
|
LoggingHelpers.LogError("Expected:");
|
|||
|
foreach (var missingItem in liveItem)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"{missingItem._tpl} ({ItemTemplateHelper.GetTemplateById(missingItem._tpl)._name}) x{missingItem.count}");
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Iterate over the barter requirement items
|
|||
|
for (int j = 0; j < offlineBarterData[i].Count; j++)
|
|||
|
{
|
|||
|
// Check live barter item exists
|
|||
|
if (j > liveItem.Count - 1)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"assort {assort._id} live barter item requirement missing");
|
|||
|
continue;
|
|||
|
}
|
|||
|
var liveSubItem = liveItem[j];
|
|||
|
var subItem = liveItem[j];
|
|||
|
|
|||
|
ValueCheckerHelper.CheckValuesMatch(subItem._tpl, liveSubItem._tpl, "barter item template ids dont match");
|
|||
|
ValueCheckerHelper.CheckValuesMatch(subItem.count.ToString(), liveSubItem.count.ToString(), "barter item counts dont match");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
CheckAssortCost(offlineBarterData, liveBarterData);
|
|||
|
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static void CheckUpdValues(Assort.Item assort, Assort.Item correspondingLiveAssort)
|
|||
|
{
|
|||
|
if (assort.upd.StackObjectsCount.HasValue && !assort.upd.UnlimitedCount.HasValue)
|
|||
|
{
|
|||
|
var liveStackCount = GetRoundedStackCount(correspondingLiveAssort.upd.StackObjectsCount.Value);
|
|||
|
ValueCheckerHelper.CheckValuesMatch(assort.upd.StackObjectsCount.Value, liveStackCount, $"stackobjectCount does not match live. orig: ({correspondingLiveAssort.upd.StackObjectsCount})");
|
|||
|
}
|
|||
|
|
|||
|
// check count is 999999 if unlimited count is true
|
|||
|
if (assort.upd.UnlimitedCount.HasValue)
|
|||
|
{
|
|||
|
ValueCheckerHelper.CheckValuesMatch(assort.upd.StackObjectsCount.Value, 999999, "unlimited count does not match");
|
|||
|
}
|
|||
|
|
|||
|
// Check max buy restriction matches
|
|||
|
ValueCheckerHelper.CheckValuesMatch(assort.upd.BuyRestrictionMax.GetValueOrDefault(0), correspondingLiveAssort.upd.BuyRestrictionMax.GetValueOrDefault(0), "BuyRestrictionMax does not match");
|
|||
|
}
|
|||
|
|
|||
|
private static int GetRoundedStackCount(int stackObjectsCount)
|
|||
|
{
|
|||
|
//TODO: automate this with math.round
|
|||
|
if (stackObjectsCount < 6)
|
|||
|
{
|
|||
|
return 5;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 11)
|
|||
|
{
|
|||
|
return 10;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 21)
|
|||
|
{
|
|||
|
return 20;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 51)
|
|||
|
{
|
|||
|
return 50;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 101)
|
|||
|
{
|
|||
|
return 100;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 201)
|
|||
|
{
|
|||
|
return 200;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 501)
|
|||
|
{
|
|||
|
return 500;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 1001)
|
|||
|
{
|
|||
|
return 1000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 2001)
|
|||
|
{
|
|||
|
return 2000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 3001)
|
|||
|
{
|
|||
|
return 3000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 4001)
|
|||
|
{
|
|||
|
return 4000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 5001)
|
|||
|
{
|
|||
|
return 5000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 6001)
|
|||
|
{
|
|||
|
return 6000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 10001)
|
|||
|
{
|
|||
|
return 10000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 15001)
|
|||
|
{
|
|||
|
return 15000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 20001)
|
|||
|
{
|
|||
|
return 20000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 25001)
|
|||
|
{
|
|||
|
return 25000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 50001)
|
|||
|
{
|
|||
|
return 50000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 70001)
|
|||
|
{
|
|||
|
return 70000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 85001)
|
|||
|
{
|
|||
|
return 85000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 100001)
|
|||
|
{
|
|||
|
return 100000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 150001)
|
|||
|
{
|
|||
|
return 150000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 200001)
|
|||
|
{
|
|||
|
return 200000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 500001)
|
|||
|
{
|
|||
|
return 500000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 700001)
|
|||
|
{
|
|||
|
return 700000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 1000001)
|
|||
|
{
|
|||
|
return 1000000;
|
|||
|
}
|
|||
|
|
|||
|
if (stackObjectsCount < 5000001)
|
|||
|
{
|
|||
|
return 5000000;
|
|||
|
}
|
|||
|
|
|||
|
return 9999999;
|
|||
|
}
|
|||
|
|
|||
|
private static bool DoesLiveAssortUpdMatchOffline(Assort.Item assort, Assort.Item correspondingLiveAssort, string itemName)
|
|||
|
{
|
|||
|
if (assort.upd != null && correspondingLiveAssort.upd == null)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"assort {assort._id} ({itemName}) has a upd object, live does not. skipping assort");
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
// no parent id = not a gun item
|
|||
|
if (assort.parentId == null && assort.upd == null && correspondingLiveAssort.upd != null)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"assort {assort._id} ({itemName}) does not have a upd object, live does. skipping assort");
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
private static Assort.Item GetLiveAssort(Assort trader, string templateId, int expectedLoyaltyLevel)
|
|||
|
{
|
|||
|
var liveAssorts = trader.items;
|
|||
|
var liveLoyaltyLevels = trader.loyal_level_items;
|
|||
|
|
|||
|
var liveAssortsWithTemplateId = liveAssorts.Where(x => x._tpl == templateId).ToList();
|
|||
|
|
|||
|
if (liveAssortsWithTemplateId.Count == 0)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"Unable to find live assort tpId: {templateId} ({ItemTemplateHelper.GetTemplateById(templateId)._name})");
|
|||
|
LoggingHelpers.LogError($"Skipping assort");
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
// Only one item, break out early and return
|
|||
|
if (liveAssortsWithTemplateId.Count == 1)
|
|||
|
{
|
|||
|
return liveAssortsWithTemplateId.First();
|
|||
|
}
|
|||
|
|
|||
|
// More than one assort found
|
|||
|
// Gather assort ids and use them to get loyalty level records
|
|||
|
var liveAssortsIds = liveAssortsWithTemplateId.Select(x => x._id);
|
|||
|
var liveLoyaltyLevelsForTemplateId = liveLoyaltyLevels.Where(x => liveAssortsIds.Contains(x.Key)).ToList();
|
|||
|
|
|||
|
// Same loyalty level + multiple found
|
|||
|
if (liveLoyaltyLevelsForTemplateId.All(x => x.Value == expectedLoyaltyLevel) && liveLoyaltyLevelsForTemplateId.Count > 1)
|
|||
|
{
|
|||
|
// Both have same loyalty level, cant proceed;
|
|||
|
LoggingHelpers.LogError($"Multiple ({liveLoyaltyLevelsForTemplateId.Count}) live assorts for this tpId found at same Level ({expectedLoyaltyLevel}) - Unable to distinguish: {templateId} ({ItemTemplateHelper.GetTemplateById(templateId)._name}) ");
|
|||
|
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
var loyaltyLevelItemThatMatches = liveLoyaltyLevelsForTemplateId.Where(x => x.Value == expectedLoyaltyLevel);
|
|||
|
if (loyaltyLevelItemThatMatches != null && loyaltyLevelItemThatMatches.Count() > 1)
|
|||
|
{
|
|||
|
LoggingHelpers.LogWarning($"({loyaltyLevelItemThatMatches.Count()}) live items found, choosing first one in list");
|
|||
|
}
|
|||
|
|
|||
|
if (loyaltyLevelItemThatMatches == null)
|
|||
|
{
|
|||
|
// Both have same loyalty level, cant proceed;
|
|||
|
LoggingHelpers.LogError($"No live assort for this tpId found at same level - Unable proceed: {templateId} ({ItemTemplateHelper.GetTemplateById(templateId)._name})");
|
|||
|
LoggingHelpers.LogNewLine();
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
return liveAssorts.Find(x => x._id == loyaltyLevelItemThatMatches.FirstOrDefault().Key);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private static void CheckAssortCost(List<List<Assort.BarterDetails>> offlineBarterData, List<List<Assort.BarterDetails>> liveBarterData)
|
|||
|
{
|
|||
|
var firstBarterItem = offlineBarterData.First().First();
|
|||
|
var firstOfflineItemIsMoney = ItemTemplateHelper.IsMoney(firstBarterItem._tpl);
|
|||
|
|
|||
|
var firstLiveBarterItem = liveBarterData.First().First();
|
|||
|
var firstLiveItemIsMoney = ItemTemplateHelper.IsMoney(firstLiveBarterItem._tpl);
|
|||
|
|
|||
|
if (firstOfflineItemIsMoney != firstLiveItemIsMoney)
|
|||
|
{
|
|||
|
LoggingHelpers.LogError($"item cost mismatch. Offline item is money: {firstOfflineItemIsMoney}. Live item is money: {firstLiveItemIsMoney}");
|
|||
|
}
|
|||
|
|
|||
|
if (firstOfflineItemIsMoney && firstOfflineItemIsMoney)
|
|||
|
{
|
|||
|
var liveCount = int.Parse(Math.Round(firstLiveBarterItem.count).ToString());
|
|||
|
ValueCheckerHelper.CheckValuesMatch(firstBarterItem.count.ToString(), liveCount.ToString(), "costs do not match");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Log the quest type: money or barter trade
|
|||
|
/// </summary>
|
|||
|
private static void LogAssortType(List<Assort.BarterDetails> offlineBarterItems, string assortSource)
|
|||
|
{
|
|||
|
if (ItemTemplateHelper.IsMoney(offlineBarterItems.First()._tpl))
|
|||
|
{
|
|||
|
LoggingHelpers.LogInfo($"{assortSource} assort is money trade");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LoggingHelpers.LogInfo($"{assortSource} assort is barter trade");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static void LogUnlockQuest(List<QuestAssortUnlock> questAssortUnlocks, Assort.Item assort, int assortLoyaltyLevel)
|
|||
|
{
|
|||
|
var questAssortUnlockData = questAssortUnlocks.FirstOrDefault(x => x.AssortTemplateId == assort._tpl && x.LoyaltyLevel == assortLoyaltyLevel);
|
|||
|
if (questAssortUnlockData != null)
|
|||
|
{
|
|||
|
LoggingHelpers.LogInfo($"Assort likely unlocked by quest: {questAssortUnlockData.QuestName} ({questAssortUnlockData.QuestId})");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|