multithreaded ragfair and botgen

This commit is contained in:
Alex
2025-01-27 20:57:47 +00:00
parent a63365fc11
commit 87dd6f6e0f
4 changed files with 139 additions and 68 deletions
+20 -10
View File
@@ -149,21 +149,31 @@ public class BotController(
_pmcConfig.AllPMCsHavePlayerNameWithRandomPrefixChance
);
var tasks = new List<Task>();
// Map conditions to promises for bot generation
foreach (var condition in request.Conditions ?? [])
{
var botGenerationDetails = GetBotGenerationDetailsForWave(
condition,
pmcProfile,
allPmcsHaveSameNameAsPlayer,
raidSettings,
_botConfig.PresetBatch!.GetValueOrDefault(condition.Role, 15),
_botHelper.IsBotPmc(condition.Role)
);
tasks.Add(
Task.Factory.StartNew(
() =>
{
var botGenerationDetails = GetBotGenerationDetailsForWave(
condition,
pmcProfile,
allPmcsHaveSameNameAsPlayer,
raidSettings,
_botConfig.PresetBatch!.GetValueOrDefault(condition.Role, 15),
_botHelper.IsBotPmc(condition.Role)
);
// Generate bots for the current condition
GenerateWithBotDetails(condition, botGenerationDetails, sessionId);
// Generate bots for the current condition
GenerateWithBotDetails(condition, botGenerationDetails, sessionId);
}
)
);
}
Task.WaitAll(tasks.ToArray());
return [];
}
@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Runtime.InteropServices.JavaScript;
using Core.Helpers;
using SptCommon.Annotations;
@@ -327,15 +328,26 @@ public class RagfairOfferGenerator(
{
var replacingExpiredOffers = (expiredOffers?.Count ?? 0) > 0;
var stopwatch = Stopwatch.StartNew();
// get assort items from param if they exist, otherwise grab freshly generated assorts
var assortItemsToProcess = replacingExpiredOffers
? expiredOffers ?? []
: ragfairAssortGenerator.GetAssortItems();
stopwatch.Stop();
logger.Info($"Took {stopwatch.ElapsedMilliseconds}ms to GetRagfairAssorts");
stopwatch.Restart();
var tasks = new List<Task>();
foreach (var assortItem in assortItemsToProcess)
{
CreateOffersFromAssort(assortItem, replacingExpiredOffers, ragfairConfig.Dynamic);
tasks.Add(
Task.Factory.StartNew(
() => { CreateOffersFromAssort(assortItem, replacingExpiredOffers, ragfairConfig.Dynamic); }
)
);
}
Task.WaitAll(tasks.ToArray());
stopwatch.Stop();
logger.Info($"Took {stopwatch.ElapsedMilliseconds}ms to CreateOffersFromAssort");
}
@@ -11,9 +11,9 @@ public class BotGenerationCacheService(
LocalisationService _localisationService
)
{
protected Dictionary<string, List<BotBase>> _storedBots = new Dictionary<string, List<BotBase>>();
protected Dictionary<string, List<BotBase>> _storedBots = new();
protected Queue<BotBase> _activeBotsInRaid = [];
protected Lock _lock = new Lock();
protected object _lock = new();
/**
@@ -108,16 +108,25 @@ public class BotGenerationCacheService(
*/
public bool CacheHasBotWithKey(string key, int size = 0)
{
return _storedBots.ContainsKey(key) && _storedBots[key].Count > size;
lock (_lock)
{
return _storedBots.ContainsKey(key) && _storedBots[key].Count > size;
}
}
public int GetCachedBotCount(string key)
{
return _storedBots.TryGetValue(key, out var bot) ? bot.Count : 0;
lock (_lock)
{
return _storedBots.TryGetValue(key, out var bot) ? bot.Count : 0;
}
}
public string CreateCacheKey(string? role, string? difficulty)
{
return $"{role?.ToLower()}{difficulty?.ToLower()}";
lock (_lock)
{
return $"{role?.ToLower()}{difficulty?.ToLower()}";
}
}
}
+91 -51
View File
@@ -10,29 +10,42 @@ namespace Core.Utils;
public class RagfairOfferHolder(
RagfairServerHelper ragfairServerHelper,
ProfileHelper profileHelper,
HashUtil hashUtil,
ConfigServer configServer)
{
protected Dictionary<string, RagfairOffer> _offersById = new();
protected object _offersByIdLock = new();
protected Dictionary<string, Dictionary<string, RagfairOffer>> _offersByTemplate = new();
protected object _offersByTemplateLock = new();
protected Dictionary<string, Dictionary<string, RagfairOffer>> _offersByTrader = new();
protected object _offersByTraderLock = new();
protected int _maxOffersPerTemplate = (int) configServer.GetConfig<RagfairConfig>().Dynamic.OfferItemCount.Max;
public RagfairOffer? GetOfferById(string id)
{
return _offersById.GetValueOrDefault(id);
lock (_offersByIdLock)
{
return _offersById.GetValueOrDefault(id);
}
}
public List<RagfairOffer>? GetOffersByTemplate(string templateId)
{
return _offersByTemplate.TryGetValue(templateId, out var value) ? value.Values.ToList() : null;
lock (_offersByTemplateLock)
{
return _offersByTemplate.TryGetValue(templateId, out var value) ? value.Values.ToList() : null;
}
}
public List<RagfairOffer> GetOffersByTrader(string traderId)
{
if (_offersByTrader.ContainsKey(traderId))
lock (_offersByTraderLock)
{
return _offersByTrader[traderId].Values.ToList();
if (_offersByTrader.ContainsKey(traderId))
{
return _offersByTrader[traderId].Values.ToList();
}
}
return null;
@@ -40,9 +53,12 @@ public class RagfairOfferHolder(
public List<RagfairOffer> GetOffers()
{
if (_offersById.Count > 0)
lock (_offersByIdLock)
{
return _offersById.Values.ToList();
if (_offersById.Count > 0)
{
return _offersById.Values.ToList();
}
}
return [];
@@ -55,22 +71,28 @@ public class RagfairOfferHolder(
public void AddOffer(RagfairOffer offer)
{
var trader = offer.User.Id;
var offerId = offer.Id;
var itemTpl = offer.Items.FirstOrDefault().Template;
// If its an NPC PMC offer AND we have already reached the maximum amount of possible offers
// for this template, just dont add in more
if (
!(ragfairServerHelper.IsTrader(trader) || profileHelper.IsPlayer(trader)) &&
(GetOffersByTemplate(itemTpl)?.Count ?? 0) >= _maxOffersPerTemplate
)
lock (_offersByIdLock)
{
return;
var trader = offer.User.Id;
// keep generating IDs until we get a new one
while (_offersById.ContainsKey(offer.Id))
offer.Id = hashUtil.Generate();
var offerId = offer.Id;
var itemTpl = offer.Items.FirstOrDefault().Template;
// If its an NPC PMC offer AND we have already reached the maximum amount of possible offers
// for this template, just dont add in more
if (!(ragfairServerHelper.IsTrader(trader) || profileHelper.IsPlayer(trader)) &&
(GetOffersByTemplate(itemTpl)?.Count ?? 0) >= _maxOffersPerTemplate
)
{
return;
}
_offersById.Add(offerId, offer);
AddOfferByTrader(trader, offer);
AddOfferByTemplates(itemTpl, offer);
}
_offersById.Add(offerId, offer);
AddOfferByTrader(trader, offer);
AddOfferByTemplates(itemTpl, offer);
}
/**
@@ -79,25 +101,34 @@ public class RagfairOfferHolder(
*/
public void RemoveOffer(RagfairOffer offer)
{
if (_offersById.ContainsKey(offer.Id))
lock (_offersByIdLock)
{
_offersById.Remove(offer.Id);
if (_offersByTrader.ContainsKey(offer.User.Id))
if (_offersById.ContainsKey(offer.Id))
{
_offersByTrader[offer.User.Id].Remove(offer.Id);
// This was causing a memory leak, we need to make sure that we remove
// the user ID from the cached offers after they dont have anything else
// on the flea placed. We regenerate the ID for the NPC users, making it
// continuously grow otherwise
if (_offersByTrader[offer.User.Id].Count == 0)
_offersById.Remove(offer.Id);
lock (_offersByTraderLock)
{
_offersByTrader.Remove(offer.User.Id);
if (_offersByTrader.ContainsKey(offer.User.Id))
{
_offersByTrader[offer.User.Id].Remove(offer.Id);
// This was causing a memory leak, we need to make sure that we remove
// the user ID from the cached offers after they dont have anything else
// on the flea placed. We regenerate the ID for the NPC users, making it
// continuously grow otherwise
if (_offersByTrader[offer.User.Id].Count == 0)
{
_offersByTrader.Remove(offer.User.Id);
}
}
}
}
if (_offersByTemplate.ContainsKey(offer.Items.FirstOrDefault().Template))
{
_offersByTemplate[offer.Items[0].Template].Remove(offer.Id);
lock (_offersByTemplateLock)
{
if (_offersByTemplate.ContainsKey(offer.Items.FirstOrDefault().Template))
{
_offersByTemplate[offer.Items[0].Template].Remove(offer.Id);
}
}
}
}
}
@@ -109,9 +140,12 @@ public class RagfairOfferHolder(
public void RemoveAllOffersByTrader(string traderId)
{
if (_offersByTrader.ContainsKey(traderId))
lock (_offersByTraderLock)
{
RemoveOffers(_offersByTrader[traderId].Values.ToList());
if (_offersByTrader.ContainsKey(traderId))
{
RemoveOffers(_offersByTrader[traderId].Values.ToList());
}
}
}
@@ -126,28 +160,34 @@ public class RagfairOfferHolder(
protected void AddOfferByTemplates(string template, RagfairOffer offer)
{
if (_offersByTemplate.ContainsKey(template))
lock (_offersByTemplateLock)
{
_offersByTemplate[template].Add(offer.Id, offer);
}
else
{
var valueMapped = new Dictionary<string, RagfairOffer>();
valueMapped.Add(offer.Id, offer);
_offersByTemplate.Add(template, valueMapped);
if (_offersByTemplate.ContainsKey(template))
{
_offersByTemplate[template].Add(offer.Id, offer);
}
else
{
var valueMapped = new Dictionary<string, RagfairOffer>();
valueMapped.Add(offer.Id, offer);
_offersByTemplate.Add(template, valueMapped);
}
}
}
protected void AddOfferByTrader(string trader, RagfairOffer offer)
{
if (_offersByTrader.ContainsKey(trader))
lock (_offersByTraderLock)
{
_offersByTrader[trader].Add(offer.Id, offer);
}
else
{
var valueMapped = new Dictionary<string, RagfairOffer> { { offer.Id, offer } };
_offersByTrader.Add(trader, valueMapped);
if (_offersByTrader.ContainsKey(trader))
{
_offersByTrader[trader].Add(offer.Id, offer);
}
else
{
var valueMapped = new Dictionary<string, RagfairOffer> { { offer.Id, offer } };
_offersByTrader.Add(trader, valueMapped);
}
}
}