First attempt at splitting static loot per map, static ammo is disabled for now

This commit is contained in:
Dev 2024-04-22 21:01:02 +01:00
parent 892c7c548e
commit 8834775186
4 changed files with 180 additions and 97 deletions

View File

@ -5,6 +5,6 @@ namespace LootDumpProcessor.Model.Processing;
public class DumpProcessData public class DumpProcessData
{ {
public Dictionary<string, IKey> LooseLootCounts { get; set; } = new(); public Dictionary<string, IKey> LooseLootCounts { get; set; } = new();
public List<PreProcessedStaticLoot> ContainerCounts { get; set; } = new(); public Dictionary<string, List<PreProcessedStaticLoot>> ContainerCounts { get; set; } = new();
public Dictionary<string, int> MapCounts { get; set; } = new(); public Dictionary<string, int> MapCounts { get; set; } = new();
} }

View File

@ -67,6 +67,7 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
LoggerFactory.GetInstance().Log($"Doing first time process for map {mapName} of real static data", LogLevel.Info); LoggerFactory.GetInstance().Log($"Doing first time process for map {mapName} of real static data", LogLevel.Info);
var mapStaticContainers = StaticLootProcessor.CreateStaticWeaponsAndStaticForcedContainers(dataDump); var mapStaticContainers = StaticLootProcessor.CreateStaticWeaponsAndStaticForcedContainers(dataDump);
// .Item1 = map name // .Item1 = map name
// .Item2 = force/weapon static arrays
staticContainers[mapStaticContainers.Item1] = mapStaticContainers.Item2; staticContainers[mapStaticContainers.Item1] = mapStaticContainers.Item2;
} }
} }
@ -84,8 +85,11 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
} }
// Only process the dump file if the date is higher (after) the configuration date // Only process the dump file if the date is higher (after) the configuration date
if (DumpWasMadeAfterConfigThresholdDate(dumped)) if (!DumpWasMadeAfterConfigThresholdDate(dumped))
{ {
return;
}
// Keep track of how many dumps we have for each map // Keep track of how many dumps we have for each map
lock (mapDumpCounterLock) lock (mapDumpCounterLock)
{ {
@ -105,6 +109,7 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
// Increment times container seen in dump by 1 // Increment times container seen in dump by 1
if (!mapAggregatedDataDict.TryAdd(dynamicStaticContainer, 1)) if (!mapAggregatedDataDict.TryAdd(dynamicStaticContainer, 1))
{
mapAggregatedDataDict[dynamicStaticContainer] += 1; mapAggregatedDataDict[dynamicStaticContainer] += 1;
} }
} }
@ -128,17 +133,17 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
Probability = GetStaticContainerProbability(kv.Key, td, mapDumpCounter) // kv.Key = map name Probability = GetStaticContainerProbability(kv.Key, td, mapDumpCounter) // kv.Key = map name
} }
).ToList() ).ToList()
).ToList().ForEach(kv => staticContainers[kv.Key].StaticContainers = kv.Value); ).ToList().ForEach(kv => staticContainers[kv.Key].StaticContainers = kv.Value); // Hydrate staticContainers.StaticContainers
// Static containers // Static containers
output.Add(OutputFileType.StaticContainer, staticContainers); output.Add(OutputFileType.StaticContainer, staticContainers);
if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info))
LoggerFactory.GetInstance().Log("Processing ammo distribution", LogLevel.Info); LoggerFactory.GetInstance().Log("Processing ammo distribution", LogLevel.Info);
// Ammo distribution // Ammo distribution
output.Add( //output.Add(
OutputFileType.StaticAmmo, // OutputFileType.StaticAmmo,
StaticLootProcessor.CreateAmmoDistribution(dumpProcessData.ContainerCounts) // StaticLootProcessor.CreateAmmoDistribution(dumpProcessData.ContainerCounts)
); //);
if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info))
LoggerFactory.GetInstance().Log("Processing static loot distribution", LogLevel.Info); LoggerFactory.GetInstance().Log("Processing static loot distribution", LogLevel.Info);
@ -198,23 +203,23 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
.ToList() .ToList()
.ForEach(tuple => .ForEach(tuple =>
{ {
var mapi = tuple.Key; var mapName = tuple.Key;
var g = tuple.ToList(); var partialFileMetaData = tuple.ToList();
if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info)) if (LoggerFactory.GetInstance().CanBeLogged(LogLevel.Info))
LoggerFactory.GetInstance().Log( LoggerFactory.GetInstance().Log(
$"Processing map {mapi}, total dump data to process: {g.Count}", $"Processing map {mapName}, total dump data to process: {partialFileMetaData.Count}",
LogLevel.Info LogLevel.Info
); );
dumpProcessData.MapCounts[mapi] = g.Count; dumpProcessData.MapCounts[mapName] = partialFileMetaData.Count;
var lockObjectContainerCounts = new object(); var lockObjectContainerCounts = new object();
var lockObjectCounts = new object(); var lockObjectCounts = new object();
var counts = new LooseLootCounts(); var looseLootCounts = new LooseLootCounts();
var lockObjectDictionaryCounts = new object(); var lockObjectDictionaryCounts = new object();
var dictionaryCounts = new FlatKeyableDictionary<string, int>(); var dictionaryCounts = new FlatKeyableDictionary<string, int>();
counts.Counts = dictionaryCounts.GetKey(); looseLootCounts.Counts = dictionaryCounts.GetKey();
/* /*
var dictionaryItemCounts = new FlatKeyableDictionary<string, List<string>>(); var dictionaryItemCounts = new FlatKeyableDictionary<string, List<string>>();
@ -225,22 +230,21 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
var dictionaryItemProperties = new FlatKeyableDictionary<string, FlatKeyableList<Template>>(); var dictionaryItemProperties = new FlatKeyableDictionary<string, FlatKeyableList<Template>>();
var actualDictionaryItemProperties = new FlatKeyableDictionary<string, IKey>(); var actualDictionaryItemProperties = new FlatKeyableDictionary<string, IKey>();
counts.ItemProperties = actualDictionaryItemProperties.GetKey(); looseLootCounts.ItemProperties = actualDictionaryItemProperties.GetKey();
dumpProcessData.LooseLootCounts.Add(mapi, counts.GetKey()); dumpProcessData.LooseLootCounts.Add(mapName, looseLootCounts.GetKey());
// add the items to the queue // add the items to the queue
foreach (var gi in g) foreach (var partialData in partialFileMetaData)
{ {
_partialDataToProcess.Add(gi); _partialDataToProcess.Add(partialData);
} }
// Call GC before running threads // Call GC before running threads
g = null; partialFileMetaData = null;
tuple = null; tuple = null;
GCHandler.Collect(); GCHandler.Collect();
// The data storage factory has a lock, we dont want the locks to occur when multithreading // The data storage factory has a lock, we dont want the locks to occur when multithreading
for (int i = 0; i < LootDumpProcessorContext.GetConfig().Threads; i++) for (int i = 0; i < LootDumpProcessorContext.GetConfig().Threads; i++)
{ {
Runners.Add( Runners.Add(
@ -253,26 +257,35 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
try try
{ {
var dumpData = _dataStorage.GetItem<ParsedDump>(partialData.ParsedDumpKey); var dumpData = _dataStorage.GetItem<ParsedDump>(partialData.ParsedDumpKey);
// Static containers
lock (lockObjectContainerCounts) lock (lockObjectContainerCounts)
{ {
dumpProcessData.ContainerCounts.AddRange(dumpData.Containers); if (!dumpProcessData.ContainerCounts.ContainsKey(mapName))
{
dumpProcessData.ContainerCounts.Add(mapName, dumpData.Containers);
}
else
{
dumpProcessData.ContainerCounts[mapName].AddRange(dumpData.Containers);
}
} }
// loose loot into ids on files // Loose loot into ids on files
var loadedDictionary = var loadedDictionary =
_dataStorage _dataStorage
.GetItem<SubdivisionedKeyableDictionary<string, List<Template>>>( .GetItem<SubdivisionedKeyableDictionary<string, List<Template>>>(
dumpData.LooseLoot.ItemProperties dumpData.LooseLoot.ItemProperties
); );
foreach (var (k, v) in loadedDictionary) foreach (var (uniqueKey, containerTemplate) in loadedDictionary)
{ {
var count = dumpData.LooseLoot.Counts[k]; var count = dumpData.LooseLoot.Counts[uniqueKey];
lock (lockObjectDictionaryCounts) lock (lockObjectDictionaryCounts)
{ {
if (dictionaryCounts.ContainsKey(k)) if (dictionaryCounts.ContainsKey(uniqueKey))
dictionaryCounts[k] += count; dictionaryCounts[uniqueKey] += count;
else else
dictionaryCounts[k] = count; dictionaryCounts[uniqueKey] = count;
} }
/* /*
@ -287,20 +300,20 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
lock (lockObjectDictionaryItemProperties) lock (lockObjectDictionaryItemProperties)
{ {
if (!dictionaryItemProperties.TryGetValue(k, out var values)) if (!dictionaryItemProperties.TryGetValue(uniqueKey, out var values))
{ {
values = new FlatKeyableList<Template>(); values = new FlatKeyableList<Template>();
dictionaryItemProperties.Add(k, values); dictionaryItemProperties.Add(uniqueKey, values);
actualDictionaryItemProperties.Add(k, values.GetKey()); actualDictionaryItemProperties.Add(uniqueKey, values.GetKey());
} }
values.AddRange(v); values.AddRange(containerTemplate);
} }
} }
lock (lockObjectCounts) lock (lockObjectCounts)
{ {
counts.MapSpawnpointCount.Add(dumpData.LooseLoot.MapSpawnpointCount); looseLootCounts.MapSpawnpointCount.Add(dumpData.LooseLoot.MapSpawnpointCount);
} }
} }
catch (Exception e) catch (Exception e)
@ -345,8 +358,8 @@ public class MultithreadSteppedDumpProcessor : IDumpProcessor
_dataStorage.Store(actualDictionaryItemProperties); _dataStorage.Store(actualDictionaryItemProperties);
actualDictionaryItemProperties = null; actualDictionaryItemProperties = null;
GCHandler.Collect(); GCHandler.Collect();
_dataStorage.Store(counts); _dataStorage.Store(looseLootCounts);
counts = null; looseLootCounts = null;
GCHandler.Collect(); GCHandler.Collect();
}); });
return dumpProcessData; return dumpProcessData;

View File

@ -112,41 +112,86 @@ public static class StaticLootProcessor
return ammo_distribution; return ammo_distribution;
} }
public static Dictionary<string, StaticItemDistribution> CreateStaticLootDistribution( /// <summary>
List<PreProcessedStaticLoot> container_counts, /// Dict key = map,
/// value = sub dit:
/// key = container Ids
/// value = items + counts
/// </summary>
public static Dictionary<string, Dictionary<string, StaticItemDistribution>> CreateStaticLootDistribution(
Dictionary<string, List<PreProcessedStaticLoot>> container_counts,
Dictionary<string, MapStaticLoot> staticContainers) Dictionary<string, MapStaticLoot> staticContainers)
{ {
var allMapsStaticLootDisto = new Dictionary< string, Dictionary<string, StaticItemDistribution>>();
// Iterate over each map we have containers for // Iterate over each map we have containers for
foreach (var map in staticContainers) foreach (var mapContainersKvp in container_counts)
{ {
var mapName = map.Key; var mapName = mapContainersKvp.Key;
var mapContainers = map.Value; var containers = mapContainersKvp.Value;
}
var static_loot_distribution = new Dictionary<string, StaticItemDistribution>(); var static_loot_distribution = new Dictionary<string, StaticItemDistribution>();
var uniqueContainerTypeIds = Enumerable.Distinct((from ci in container_counts var uniqueContainerTypeIds = Enumerable.Distinct((from ci in containers
select ci.Type).ToList()); select ci.Type).ToList());
foreach (var typeId in uniqueContainerTypeIds) foreach (var typeId in uniqueContainerTypeIds)
{ {
var container_counts_selected = (from ci in container_counts var container_counts_selected = (from ci in containers
where ci.Type == typeId where ci.Type == typeId
select ci).ToList(); select ci).ToList();
var itemscounts = new List<int>();
foreach (var ci in container_counts_selected)
{
itemscounts.Add((from cii in ci.Items
where cii.ParentId == ci.ContainerId
select cii).ToList().Count);
}
// Get array of all times a count of items was found in container
List<int> itemCountsInContainer = GetCountOfItemsInContainer(container_counts_selected);
// Create structure to hold item count + weight that it will be picked
// Group same counts together
static_loot_distribution[typeId] = new StaticItemDistribution(); static_loot_distribution[typeId] = new StaticItemDistribution();
static_loot_distribution[typeId].ItemCountDistribution = itemscounts.GroupBy(i => i) static_loot_distribution[typeId].ItemCountDistribution = itemCountsInContainer.GroupBy(i => i)
.Select(g => new ItemCountDistribution .Select(g => new ItemCountDistribution
{ {
Count = g.Key, Count = g.Key,
RelativeProbability = g.Count() RelativeProbability = g.Count()
}).ToList(); }).ToList();
static_loot_distribution[typeId].ItemDistribution = CreateItemDistribution(container_counts_selected);
}
// Key = containers tpl, value = items + count weights
allMapsStaticLootDisto.TryAdd(mapName, static_loot_distribution);
}
return allMapsStaticLootDisto;
//var static_loot_distribution = new Dictionary<string, StaticItemDistribution>();
//var uniqueContainerTypeIds = Enumerable.Distinct((from ci in container_counts
// select ci.Type).ToList());
//foreach (var typeId in uniqueContainerTypeIds)
//{
// var container_counts_selected = (from ci in container_counts
// where ci.Type == typeId
// select ci).ToList();
// // Get array of all times a count of items was found in container
// List<int> itemCountsInContainer = GetCountOfItemsInContainer(container_counts_selected);
// // Create structure to hold item count + weight that it will be picked
// // Group same counts together
// static_loot_distribution[typeId] = new StaticItemDistribution();
// static_loot_distribution[typeId].ItemCountDistribution = itemCountsInContainer.GroupBy(i => i)
// .Select(g => new ItemCountDistribution
// {
// Count = g.Key,
// RelativeProbability = g.Count()
// }).ToList();
// static_loot_distribution[typeId].ItemDistribution = CreateItemDistribution(container_counts_selected);
//}
//// Key = containers tpl, value = items + count weights
//return static_loot_distribution;
}
private static List<StaticDistribution> CreateItemDistribution(List<PreProcessedStaticLoot> container_counts_selected)
{
// TODO: Change for different algo that splits items per parent once parentid = containerid, then compose // TODO: Change for different algo that splits items per parent once parentid = containerid, then compose
// TODO: key and finally create distribution based on composed Id instead // TODO: key and finally create distribution based on composed Id instead
var itemsHitCounts = new Dictionary<string, int>(); var itemsHitCounts = new Dictionary<string, int>();
@ -161,13 +206,25 @@ public static class StaticLootProcessor
} }
} }
static_loot_distribution[typeId].ItemDistribution = itemsHitCounts.Select(v => new StaticDistribution // WIll create array of objects that have a tpl + relative probability weight value
return itemsHitCounts.Select(v => new StaticDistribution
{ {
Tpl = v.Key, Tpl = v.Key,
RelativeProbability = v.Value RelativeProbability = v.Value
}).ToList(); }).ToList();
} }
return static_loot_distribution; private static List<int> GetCountOfItemsInContainer(List<PreProcessedStaticLoot> container_counts_selected)
{
var itemCountsInContainer = new List<int>();
foreach (var containerWithItems in container_counts_selected)
{
// Only count item if its parent is the container, only root items are counted (not mod/attachment items)
itemCountsInContainer.Add((from cii in containerWithItems.Items
where cii.ParentId == containerWithItems.ContainerId
select cii).ToList().Count);
}
return itemCountsInContainer;
} }
} }

View File

@ -1,7 +1,9 @@
using LootDumpProcessor.Model.Output; using LootDumpProcessor.Model.Output;
using LootDumpProcessor.Model.Output.LooseLoot; using LootDumpProcessor.Model.Output.LooseLoot;
using LootDumpProcessor.Model.Output.StaticContainer; using LootDumpProcessor.Model.Output.StaticContainer;
using LootDumpProcessor.Model.Processing;
using LootDumpProcessor.Serializers.Json; using LootDumpProcessor.Serializers.Json;
using System.Collections.Generic;
namespace LootDumpProcessor.Process.Writer; namespace LootDumpProcessor.Process.Writer;
@ -59,16 +61,27 @@ public class FileWriter : IWriter
var staticContainer = (Dictionary<string, MapStaticLoot>)data; var staticContainer = (Dictionary<string, MapStaticLoot>)data;
File.WriteAllText($@"{_outputPath}\loot\staticContainers.json", File.WriteAllText($@"{_outputPath}\loot\staticContainers.json",
_jsonSerializer.Serialize(staticContainer)); _jsonSerializer.Serialize(staticContainer));
break; break;
case OutputFileType.StaticLoot: case OutputFileType.StaticLoot:
var staticLoot = (Dictionary<string, StaticItemDistribution>)data; var staticLootData = (Dictionary<string, Dictionary<string, StaticItemDistribution>>)data;
File.WriteAllText($@"{_outputPath}\loot\staticLoot.json", foreach (var (key, value) in staticLootData)
_jsonSerializer.Serialize(staticLoot)); {
foreach (var s in LootDumpProcessorContext.GetDirectoryMappings()[key].Name)
{
if (!Directory.Exists($@"{_outputPath}\locations\{s}"))
Directory.CreateDirectory($@"{_outputPath}\locations\{s}");
File.WriteAllText($@"{_outputPath}\locations\{s}\staticLoot.json",
_jsonSerializer.Serialize(value));
}
}
break; break;
case OutputFileType.StaticAmmo: case OutputFileType.StaticAmmo:
var staticAmmo = (Dictionary<string, List<AmmoDistribution>>)data; var staticAmmo = (Dictionary<string, List<AmmoDistribution>>)data;
File.WriteAllText($@"{_outputPath}\loot\staticAmmo.json", File.WriteAllText($@"{_outputPath}\loot\staticAmmo.json",
_jsonSerializer.Serialize(staticAmmo)); _jsonSerializer.Serialize(staticAmmo));
break; break;
default: default:
throw new ArgumentOutOfRangeException(nameof(type), type, null); throw new ArgumentOutOfRangeException(nameof(type), type, null);