Improved Fake PMC offer count fluctuations #527

Added fake PMC offer count index to `RagfairOfferHolder` and made use of it when checking if offer count is over desired count
This commit is contained in:
Chomp
2025-08-02 11:22:27 +01:00
parent 0f1bea6151
commit 08815da10d
4 changed files with 75 additions and 40 deletions
@@ -45,4 +45,19 @@ public static class RagfairOfferExtensions
return false;
}
/// <summary>
/// Was this offer created by a fake player
/// </summary>
/// <param name="offer"></param>
/// <returns></returns>
public static bool IsFakePlayerOffer(this RagfairOffer offer)
{
if (offer.CreatedBy is not null)
{
return offer.CreatedBy == OfferCreator.FakePlayer;
}
return false;
}
}
@@ -35,21 +35,11 @@ public class RagfairAssortGenerator(
BaseClasses.BUILT_IN_INSERTS,
];
/// <summary>
/// Get a list of lists that can be sold on the flea. <br />
/// Each sub list contains item + children (if any)
/// </summary>
/// <returns> List with children lists of items </returns>
public IEnumerable<List<Item>> GetAssortItems()
{
return GenerateRagfairAssortItems();
}
/// <summary>
/// Generate a list of lists (item + children) the flea can sell
/// </summary>
/// <returns> List of lists (item + children)</returns>
protected IEnumerable<List<Item>> GenerateRagfairAssortItems()
public IEnumerable<List<Item>> GenerateRagfairAssortItems()
{
IEnumerable<List<Item>> results = [];
@@ -74,26 +74,24 @@ public class RagfairOfferGenerator(
/// <returns>RagfairOffer</returns>
protected RagfairOffer CreateOffer(CreateFleaOfferDetails details)
{
var offerRequirements = details
.BarterScheme.Select(barter =>
var offerRequirements = details.BarterScheme.Select(barter =>
{
var offerRequirement = new OfferRequirement
{
var offerRequirement = new OfferRequirement
{
TemplateId = barter.Template,
Count = Math.Round(barter.Count.Value, 2),
OnlyFunctional = barter.OnlyFunctional ?? false,
};
TemplateId = barter.Template,
Count = Math.Round(barter.Count.Value, 2),
OnlyFunctional = barter.OnlyFunctional ?? false,
};
// Dogtags define level and side
if (barter.Level != null)
{
offerRequirement.Level = barter.Level;
offerRequirement.Side = barter.Side;
}
// Dogtags define level and side
if (barter.Level != null)
{
offerRequirement.Level = barter.Level;
offerRequirement.Side = barter.Side;
}
return offerRequirement;
})
.ToList();
return offerRequirement;
});
// Clone to avoid modifying original array
var itemsClone = cloner.Clone(details.Items);
@@ -295,7 +293,7 @@ public class RagfairOfferGenerator(
var stopwatch = Stopwatch.StartNew();
// get assort items from param if they exist, otherwise grab freshly generated assorts
var assortItemsToProcess = replacingExpiredOffers ? expiredOffers ?? [] : ragfairAssortGenerator.GetAssortItems();
var assortItemsToProcess = replacingExpiredOffers ? expiredOffers ?? [] : ragfairAssortGenerator.GenerateRagfairAssortItems();
stopwatch.Stop();
if (logger.IsLogEnabled(LogLevel.Debug) && stopwatch.ElapsedMilliseconds > 0)
{
@@ -38,6 +38,11 @@ public class RagfairOfferHolder(
/// </summary>
private readonly ConcurrentDictionary<MongoId, HashSet<MongoId>> _offersByTrader = new();
/// <summary>
/// Fake player offer ids keyed by itemTPl
/// </summary>
private readonly ConcurrentDictionary<MongoId, HashSet<MongoId>> _fakePlayerOffers = new();
private readonly Lock _expiredOfferIdsLock = new();
private readonly Lock _ragfairOperationLock = new();
@@ -136,20 +141,16 @@ public class RagfairOfferHolder(
offer.Id = new MongoId();
}
var itemTpl = offer.Items?.FirstOrDefault()?.Template ?? new MongoId(null);
var sellerId = offer.User.Id;
var sellerIsTrader = offer.IsTraderOffer();
var itemSoldTemplate = _itemHelper.GetItem(itemTpl);
var itemTpl = offer.Items?.FirstOrDefault()?.Template ?? new MongoId();
if (
!itemTpl.IsEmpty() // Has tpl
&& !(sellerIsTrader || offer.IsPlayerOffer())
&& _offersByTemplate.TryGetValue(itemTpl, out var offers)
&& offers?.Count >= _ragfairServerHelper.GetOfferCountByBaseType(itemSoldTemplate.Value.Parent)
&& offer.IsFakePlayerOffer()
&& _fakePlayerOffers.TryGetValue(itemTpl, out var offers)
&& offers?.Count >= _ragfairServerHelper.GetOfferCountByBaseType(_itemHelper.GetItem(itemTpl).Value.Parent)
)
{
// If it is an NPC PMC offer AND we have already reached the maximum amount of possible offers
// for this template, just don't add in more
// for this template, don't add more
return;
}
@@ -158,9 +159,14 @@ public class RagfairOfferHolder(
_logger.Warning($"Offer: {offer.Id} already exists");
}
if (sellerIsTrader)
if (offer.IsTraderOffer())
{
AddOfferByTrader(sellerId, offer.Id);
AddOfferByTrader(offer.User.Id, offer.Id);
}
if (offer.IsFakePlayerOffer())
{
AddFakePlayerOffer(itemTpl, offer.Id);
}
AddOfferByTemplates(itemTpl, offer.Id);
@@ -206,6 +212,11 @@ public class RagfairOfferHolder(
{
offers.Remove(offer.Id);
}
if (offer.IsFakePlayerOffer() && _fakePlayerOffers.TryGetValue(offer.Items.FirstOrDefault().Template, out var fakePlayerOfferIds))
{
fakePlayerOfferIds.Remove(offer.Id);
}
}
/// <summary>
@@ -286,6 +297,27 @@ public class RagfairOfferHolder(
return false;
}
protected bool AddFakePlayerOffer(MongoId itemTpl, MongoId offerId)
{
// Look for hashset for trader first
if (_fakePlayerOffers.TryGetValue(itemTpl, out var fakePlayerOfferIds))
{
fakePlayerOfferIds.Add(offerId);
return true;
}
// Add new KvP of trader and offer id in new hashset
if (_fakePlayerOffers.TryAdd(itemTpl, [offerId]))
{
return true;
}
_logger.Error($"Unable to add offer: {offerId} to _fakePlayerOffers");
return false;
}
/// <summary>
/// Add a stale offers id to _expiredOfferIds collection for later processing
/// </summary>