diff --git a/Libraries/Core/Controllers/RagfairController.cs b/Libraries/Core/Controllers/RagfairController.cs index 004c4ed9..5eda9c81 100644 --- a/Libraries/Core/Controllers/RagfairController.cs +++ b/Libraries/Core/Controllers/RagfairController.cs @@ -345,7 +345,7 @@ public class RagfairController var fleaPrices = _databaseService.GetPrices(); if (!fleaPrices.TryGetValue(getPriceRequest.TemplateId, out var tplPrice)) { - tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId); + tplPrice = _handbookHelper.GetTemplatePrice(getPriceRequest.TemplateId) ?? 0; } return new GetItemPriceResult{ Avg = tplPrice, Min = tplPrice, Max = tplPrice }; diff --git a/Libraries/Core/Generators/BotLootGenerator.cs b/Libraries/Core/Generators/BotLootGenerator.cs index baccc5a9..56c3cb8b 100644 --- a/Libraries/Core/Generators/BotLootGenerator.cs +++ b/Libraries/Core/Generators/BotLootGenerator.cs @@ -559,7 +559,7 @@ public class BotLootGenerator( // Stop adding items to bots pool if rolling total is over total limit if (totalValueLimitRub > 0) { - currentTotalRub += _handbookHelper.GetTemplatePrice(itemToAddTemplate.Id); + currentTotalRub += _handbookHelper.GetTemplatePrice(itemToAddTemplate.Id) ?? 0; if (currentTotalRub > totalValueLimitRub) { break; diff --git a/Libraries/Core/Helpers/HandbookHelper.cs b/Libraries/Core/Helpers/HandbookHelper.cs index 4aef8514..8270305e 100644 --- a/Libraries/Core/Helpers/HandbookHelper.cs +++ b/Libraries/Core/Helpers/HandbookHelper.cs @@ -1,17 +1,69 @@ using SptCommon.Annotations; using Core.Models.Eft.Common.Tables; +using Core.Models.Enums; +using Core.Models.Spt.Config; +using Core.Servers; +using Core.Services; +using Core.Utils.Cloners; namespace Core.Helpers; [Injectable] -public class HandbookHelper +public class HandbookHelper( + DatabaseService _databaseService, + ConfigServer _configServer, + ICloner _cloner +) { + protected ItemConfig _itemConfig = _configServer.GetConfig(); + protected bool _lookupCacheGenerated = false; + protected LookupCollection _handbookPriceCache = new LookupCollection(); + /// /// Create an in-memory cache of all items with associated handbook price in handbookPriceCache class /// public void HydrateLookup() { - throw new NotImplementedException(); + var handbook = _databaseService.GetHandbook(); + // Add handbook overrides found in items.json config into db + foreach (var itemTplKey in _itemConfig.HandbookPriceOverride) { + var data = _itemConfig.HandbookPriceOverride[itemTplKey.Key]; + + var itemToUpdate = handbook.Items.FirstOrDefault(item => item.Id == itemTplKey.Key); + if (itemToUpdate is null) { + handbook.Items.Add( new HandbookItem { + Id = itemTplKey.Key, + ParentId = data.ParentId, + Price = data.Price, + }); + itemToUpdate = handbook.Items.FirstOrDefault(item => item.Id == itemTplKey.Key); + } + + itemToUpdate.Price = data.Price; + } + + var handbookDbClone = _cloner.Clone(handbook); + foreach (var handbookItem in handbookDbClone.Items) { + _handbookPriceCache.Items.ById.TryAdd(handbookItem.Id, handbookItem.Price ?? 0); + if (!_handbookPriceCache.Items.ByParent.TryGetValue(handbookItem.ParentId, out var _)) { + _handbookPriceCache.Items.ByParent.TryAdd(handbookItem.ParentId, []); + } + + _handbookPriceCache.Items.ByParent.TryGetValue(handbookItem.ParentId, out var array); + array.Add(handbookItem.Id); + } + + foreach (var handbookCategory in handbookDbClone.Categories) { + _handbookPriceCache.Categories.ById.TryAdd(handbookCategory.Id, handbookCategory.ParentId); + if (handbookCategory.ParentId is not null) { + if (!_handbookPriceCache.Categories.ByParent.TryGetValue(handbookCategory.ParentId, out var _)) { + _handbookPriceCache.Categories.ByParent.TryAdd(handbookCategory.ParentId, []); + } + + _handbookPriceCache.Categories.ByParent.TryGetValue(handbookCategory.ParentId, out var array); + array.Add(handbookCategory.Id); + } + } } /// @@ -20,14 +72,47 @@ public class HandbookHelper /// /// Item tpl to look up price for /// price in roubles - public double GetTemplatePrice(string tpl) + public double? GetTemplatePrice(string tpl) { - throw new NotImplementedException(); + if (!_lookupCacheGenerated) + { + HydrateLookup(); + _lookupCacheGenerated = true; + } + + if (_handbookPriceCache.Items.ById.TryGetValue(tpl, out var item)) + { + return item; + } + + var handbookItem = _databaseService.GetHandbook().Items?.FirstOrDefault(item => item.Id == tpl); + if (handbookItem is null) + { + var newValue = 0; + + if (!_handbookPriceCache.Items.ById.TryAdd(tpl, newValue)) + { + _handbookPriceCache.Items.ById[tpl] = newValue; + } + + return newValue; + } + + if (!_handbookPriceCache.Items.ById.TryAdd(tpl, handbookItem.Price ?? 0)) + { + _handbookPriceCache.Items.ById[tpl] = handbookItem.Price ?? 0; + } + return handbookItem.Price; } public double GetTemplatePriceForItems(List items) { - throw new NotImplementedException(); + var total = 0D; + foreach (var item in items) { + total += GetTemplatePrice(item.Template) ?? 0; + } + + return total; } /// @@ -37,7 +122,9 @@ public class HandbookHelper /// string array public List TemplatesWithParent(string parentId) { - throw new NotImplementedException(); + _handbookPriceCache.Items.ByParent.TryGetValue(parentId, out var template); + + return template ?? []; } /// @@ -47,7 +134,7 @@ public class HandbookHelper /// true if exists in cache public bool IsCategory(string category) { - throw new NotImplementedException(); + return _handbookPriceCache.Categories.ById.TryGetValue(category, out var _); } /// @@ -57,7 +144,8 @@ public class HandbookHelper /// string array public List ChildrenCategories(string categoryParent) { - throw new NotImplementedException(); + _handbookPriceCache.Categories.ByParent.TryGetValue(categoryParent, out var category); + return category ?? []; } /// @@ -68,7 +156,9 @@ public class HandbookHelper /// Count in roubles public double InRUB(double nonRoubleCurrencyCount, string currencyTypeFrom) { - throw new NotImplementedException(); + return currencyTypeFrom == Money.ROUBLES + ? nonRoubleCurrencyCount + : Math.Round(nonRoubleCurrencyCount * (GetTemplatePrice(currencyTypeFrom) ?? 0)); } /// @@ -87,3 +177,27 @@ public class HandbookHelper throw new NotImplementedException(); } } + +public class LookupItem +{ + public Dictionary ById { get; set; } + public Dictionary> ByParent { get; set; } + + public LookupItem() + { + ById = new Dictionary(); + ByParent = new Dictionary>(); + } +} + +public class LookupCollection +{ + public LookupItem Items { get; set; } + public LookupItem Categories { get; set; } + + public LookupCollection() + { + Items = new LookupItem(); + Categories = new LookupItem(); + } +} diff --git a/Libraries/Core/Helpers/ItemHelper.cs b/Libraries/Core/Helpers/ItemHelper.cs index e481db4e..8f51b412 100644 --- a/Libraries/Core/Helpers/ItemHelper.cs +++ b/Libraries/Core/Helpers/ItemHelper.cs @@ -384,7 +384,7 @@ public class ItemHelper( /// /// Item to look price up of /// Price in roubles - public double GetItemPrice(string tpl) + public double? GetItemPrice(string tpl) { var handbookPrice = GetStaticItemPrice(tpl); if (handbookPrice >= 1) @@ -406,7 +406,7 @@ public class ItemHelper( var staticPrice = GetStaticItemPrice(tpl); var dynamicPrice = GetDynamicItemPrice(tpl); - return Math.Max(staticPrice, dynamicPrice); + return Math.Max(staticPrice ?? 0, dynamicPrice); } /// @@ -414,7 +414,7 @@ public class ItemHelper( /// /// Items tpl id to look up price /// Price in roubles (0 if not found) - public double GetStaticItemPrice(string tpl) + public double? GetStaticItemPrice(string tpl) { var handbookPrice = _handbookHelper.GetTemplatePrice(tpl); if (handbookPrice >= 1) diff --git a/Libraries/Core/Models/Eft/Common/Tables/HandbookBase.cs b/Libraries/Core/Models/Eft/Common/Tables/HandbookBase.cs index bf994d5d..c94807ee 100644 --- a/Libraries/Core/Models/Eft/Common/Tables/HandbookBase.cs +++ b/Libraries/Core/Models/Eft/Common/Tables/HandbookBase.cs @@ -41,5 +41,5 @@ public record HandbookItem public string? ParentId { get; set; } [JsonPropertyName("Price")] - public decimal? Price { get; set; } + public double? Price { get; set; } } diff --git a/Libraries/Core/Models/Spt/Config/ItemConfig.cs b/Libraries/Core/Models/Spt/Config/ItemConfig.cs index 605983f5..2c962201 100644 --- a/Libraries/Core/Models/Spt/Config/ItemConfig.cs +++ b/Libraries/Core/Models/Spt/Config/ItemConfig.cs @@ -40,7 +40,7 @@ public record HandbookPriceOverride { /** Price in roubles */ [JsonPropertyName("price")] - public decimal Price { get; set; } + public double Price { get; set; } /** NOT parentId from items.json, but handbook.json */ [JsonPropertyName("parentId")] diff --git a/Libraries/Core/Services/RagfairPriceService.cs b/Libraries/Core/Services/RagfairPriceService.cs index 866146de..49898c5e 100644 --- a/Libraries/Core/Services/RagfairPriceService.cs +++ b/Libraries/Core/Services/RagfairPriceService.cs @@ -38,7 +38,7 @@ public class RagfairPriceService( { foreach (var item in _databaseService.GetItems().Where((x) => x.Value.Type == "Item")) { - _prices.StaticPrices[item.Key] = Math.Round(_handbookHelper.GetTemplatePrice(item.Key)); + _prices.StaticPrices[item.Key] = Math.Round(_handbookHelper.GetTemplatePrice(item.Key) ?? 0); } }