2023-09-18 16:30:24 +01:00
using System.Collections.Concurrent ;
using Common.Models.Input ;
2021-08-13 16:22:10 +01:00
using Newtonsoft.Json.Linq ;
2021-08-12 16:52:06 +01:00
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
2021-11-26 14:50:07 +00:00
using System.Text.Json ;
2021-08-31 18:52:28 +01:00
using System.Threading.Tasks ;
2024-09-14 20:45:27 +01:00
using Common.Models.Output ;
2021-08-12 16:52:06 +01:00
2021-11-26 14:50:07 +00:00
namespace Common.Bots ;
public static class BotParser
2021-08-12 16:52:06 +01:00
{
2024-09-14 20:45:27 +01:00
private static readonly JsonSerializerOptions serialiserOptions = new ( ) { } ;
2021-11-26 14:50:07 +00:00
2024-09-14 20:45:27 +01:00
public static async Task < List < Datum > > ParseAsync ( string dumpPath , HashSet < string > botTypes )
2021-08-12 16:52:06 +01:00
{
2021-11-26 14:50:07 +00:00
var stopwatch = Stopwatch . StartNew ( ) ;
2021-08-12 16:52:06 +01:00
2021-11-26 14:50:07 +00:00
DiskHelpers . CreateDirIfDoesntExist ( dumpPath ) ;
2021-08-12 16:52:06 +01:00
2024-09-14 20:45:27 +01:00
var botFiles = Directory . GetFiles ( dumpPath , "*.json" , SearchOption . TopDirectoryOnly ) ;
LoggingHelpers . LogToConsole ( $"{botFiles.Length} bot dump files found" ) ;
2021-08-12 16:52:06 +01:00
2024-09-14 20:45:27 +01:00
// key = bot type
// Store bots keyed against their ID so we never get duplicates
var parsedBotsDict = new ConcurrentDictionary < string , Datum > ( ) ;
2023-09-18 17:15:30 +01:00
2021-11-26 14:50:07 +00:00
int totalDupeCount = 0 ;
2024-09-14 20:45:27 +01:00
var tasks = new List < Task > ( ) ;
foreach ( var filePath in botFiles )
2021-11-26 14:50:07 +00:00
{
2024-09-14 20:45:27 +01:00
tasks . Add ( ProcessBotFile ( botTypes , filePath , parsedBotsDict , totalDupeCount ) ) ;
2023-09-18 16:30:24 +01:00
}
2021-08-12 16:52:06 +01:00
2024-09-14 20:45:27 +01:00
await Task . WhenAll ( tasks . ToArray ( ) ) ;
2021-11-26 14:50:07 +00:00
stopwatch . Stop ( ) ;
2023-09-18 17:15:30 +01:00
2023-09-18 16:30:24 +01:00
LoggingHelpers . LogToConsole ( $"Cleaned and Parsed: {parsedBotsDict.Count} bots. {totalDupeCount} dupes were ignored. Took {LoggingHelpers.LogTimeTaken(stopwatch.Elapsed.TotalSeconds)} seconds" ) ;
2021-11-26 14:50:07 +00:00
2024-02-21 17:06:08 +00:00
return [ . . parsedBotsDict . Values ] ;
2021-11-26 14:50:07 +00:00
}
2024-09-14 20:45:27 +01:00
private static async Task < int > ProcessBotFile (
HashSet < string > botTypes ,
string filePath ,
ConcurrentDictionary < string , Datum > parsedBotsDict ,
int totalDupeCount )
{
var splitFilePath = filePath . Split ( "\\" ) ;
int dupeCount = 0 ;
List < Datum > bots = [ ] ;
try
{
// Parse the bots inside the json file
using ( var reader = new StreamReader ( filePath ) )
{
var deSerialisedObject = JsonSerializer . Deserialize < Root > ( reader . ReadToEnd ( ) , serialiserOptions ) ;
bots . AddRange ( deSerialisedObject . data . Where ( botData = > botTypes . Contains ( botData . Info . Settings . Role . ToLower ( ) ) ) ) ;
}
}
catch ( Exception ex )
{
Console . WriteLine ( $"File parse fucked up: {filePath}" ) ;
throw ;
}
if ( bots = = null | | bots . Count = = 0 )
{
Console . WriteLine ( $"Skipping file: {splitFilePath.Last()}. no bots found, " ) ;
return totalDupeCount ;
}
//Console.WriteLine($"parsing: {bots.Count} bots in file {splitFilePath.Last()}");
foreach ( var bot in bots )
{
// Bot fucks up something, never allow it in
if ( bot . _id = = "6483938c53cc9087c70eae86" )
{
Console . WriteLine ( "oh no" ) ;
continue ;
}
// null out unnecessary data to save ram
bot . Stats = null ;
bot . Encyclopedia = null ;
bot . Hideout = null ;
bot . TaskConditionCounters = null ;
bot . Bonuses = null ;
bot . InsuredItems = null ;
// Add bot if not already added
if ( parsedBotsDict . TryAdd ( bot . _id , bot ) )
{
// Success
// Null out more data to save ram
bot . Inventory . items . RemoveAll ( x = > x . parentId = = null ) ;
}
else
{
dupeCount + + ;
}
}
totalDupeCount + = dupeCount ;
Console . WriteLine ( $"Parsed file: {filePath}" ) ;
return totalDupeCount ;
}
private static IEnumerable < Datum > ParseJson ( string json )
{
var deSerialisedObject = JsonSerializer . Deserialize < Root > ( json , serialiserOptions ) ;
return deSerialisedObject . data ;
}
2021-11-26 14:50:07 +00:00
private static string PruneMalformedBsgJson ( string json , string fileName )
{
// Bsg send json where an item has a location of 1 but it should be an object with x/y/z coords
var o = JObject . Parse ( json ) ;
var jItemsToReplace = o . SelectTokens ( "$.data[*].Inventory.items[?(@.location == 1)].location" ) ;
//var jItemsToReplace = o.SelectTokens("$.data[*].Inventory.items[?(@.location == 1 && @.slotId == 'cartridges')].location");
2021-08-12 16:52:06 +01:00
2021-11-26 14:50:07 +00:00
if ( jItemsToReplace ! = null & & jItemsToReplace . Any ( ) )
{
LoggingHelpers . LogToConsole ( $"file {fileName} has {jItemsToReplace.Count()} json issues, cleaning up." , ConsoleColor . Yellow ) ;
foreach ( var item in jItemsToReplace )
2021-08-13 16:22:10 +01:00
{
2021-11-26 14:50:07 +00:00
var obj = new { x = 1 , y = 0 , r = 0 } ;
item . Replace ( JToken . FromObject ( obj ) ) ;
2021-08-13 16:22:10 +01:00
}
2021-08-12 16:52:06 +01:00
}
2021-11-26 14:50:07 +00:00
var returnString = o . ToString ( ) ;
2021-08-12 16:52:06 +01:00
2021-11-26 14:50:07 +00:00
o = null ;
jItemsToReplace = null ;
2021-08-31 18:52:28 +01:00
2021-11-26 14:50:07 +00:00
return returnString ;
}
2021-08-12 16:52:06 +01:00
}