using System.Collections.Concurrent; using LootDumpProcessor.Logger; using LootDumpProcessor.Model; using LootDumpProcessor.Model.Input; using LootDumpProcessor.Model.Output.StaticContainer; using LootDumpProcessor.Model.Processing; using LootDumpProcessor.Serializers.Json; using LootDumpProcessor.Storage; using LootDumpProcessor.Storage.Collections; using LootDumpProcessor.Utils; namespace LootDumpProcessor.Process.Processor.DumpProcessor; public class MultithreadSteppedDumpProcessor : IDumpProcessor { private static IJsonSerializer _jsonSerializer = JsonSerializerFactory.GetInstance(); private static readonly List Runners = new(); private static readonly BlockingCollection _partialDataToProcess = new(); // if we need to, this variable can be moved to use the factory, but since the factory // needs a locking mechanism to prevent dictionary access exceptions, its better to keep // a reference to use here private static readonly IDataStorage _dataStorage = DataStorageFactory.GetInstance(); public Dictionary ProcessDumps(List dumps) { if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) LoggerFactory.GetInstance().Log("Starting final dump processing", LogLevel.Info); var output = new Dictionary(); var dumpProcessData = GetDumpProcessData(dumps); if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) LoggerFactory.GetInstance().Log("Heavy processing done!", LogLevel.Info); var staticContainers = new Dictionary(); var staticContainersLock = new object(); // We need to count how many dumps we have for each map var mapDumpCounter = new Dictionary(); var mapDumpCounterLock = new object(); // dictionary of maps, that has a dictionary of template and hit count var mapStaticContainersAggregated = new Dictionary>(); var mapStaticContainersAggregatedLock = new object(); Runners.Clear(); // BSG changed the map data so static containers are now dynamic, so we need to scan all dumps for the static containers. if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) LoggerFactory.GetInstance().Log("Queuing dumps for static data processing", LogLevel.Info); foreach (var dumped in dumps) { Runners.Add( Task.Factory.StartNew(() => { if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Debug)) LoggerFactory.GetInstance().Log($"Processing static data for file {dumped.BasicInfo.FileName}", LogLevel.Debug); var dataDump = _jsonSerializer.Deserialize(File.ReadAllText(dumped.BasicInfo.FileName)); if (dataDump == null) { if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Error)) LoggerFactory.GetInstance().Log($"Failed to deserialize data from file {dumped.BasicInfo.FileName}", LogLevel.Error); return; // Skip processing this dump } var mapId = dataDump.Data.LocationLoot.Id.ToLower(); // Because we may use multiple version dumps for map data, merge the static loot between dumps lock (staticContainersLock) { if (!staticContainers.TryGetValue(mapId, out var mapStaticLoot)) { if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) LoggerFactory.GetInstance().Log($"Doing first time process for map {mapId} of real static data", LogLevel.Info); staticContainers[mapId] = new MapStaticLoot { StaticWeapons = new List