diff --git a/src/Perpetuum.Bootstrapper/PerpetuumBootstrapper.cs b/src/Perpetuum.Bootstrapper/PerpetuumBootstrapper.cs index abff49268..c567ca56e 100644 --- a/src/Perpetuum.Bootstrapper/PerpetuumBootstrapper.cs +++ b/src/Perpetuum.Bootstrapper/PerpetuumBootstrapper.cs @@ -1641,6 +1641,7 @@ private void InitRelayManager() _builder.RegisterType(); _builder.RegisterType(); + _builder.RegisterType().As(); _builder.RegisterType().OnActivated(e => { e.Instance.Init(); diff --git a/src/Perpetuum/Services/ProductionEngine/Facilities/ProductionFacility.cs b/src/Perpetuum/Services/ProductionEngine/Facilities/ProductionFacility.cs index ee2b661b1..df17f0b28 100644 --- a/src/Perpetuum/Services/ProductionEngine/Facilities/ProductionFacility.cs +++ b/src/Perpetuum/Services/ProductionEngine/Facilities/ProductionFacility.cs @@ -226,9 +226,8 @@ private int GetStandingPoints(Character character) //Overload method for price/sec public virtual double GetPricePerSecond(int targetDefinition) { - var mod = Math.Max(1, ProductionDataAccess.GetProductionPriceModifier(targetDefinition)); - mod = Math.Min(10, mod); - return GetPricePerSecond() * mod; + var mod = ProductionDataAccess.GetProductionPriceModifier(targetDefinition); + return GetPricePerSecond() * mod.Clamp(1, 10); } public virtual double GetPricePerSecond() diff --git a/src/Perpetuum/Services/ProductionEngine/IProductionDataAccess.cs b/src/Perpetuum/Services/ProductionEngine/IProductionDataAccess.cs index 1d4209ce6..b7e273ba6 100644 --- a/src/Perpetuum/Services/ProductionEngine/IProductionDataAccess.cs +++ b/src/Perpetuum/Services/ProductionEngine/IProductionDataAccess.cs @@ -11,8 +11,7 @@ public interface IProductionDataAccess IDictionary ResearchLevels { get; } ILookup ProductionComponents { get; } IDictionary ProductionDurations { get; } - IDictionary ProductionCostByCategory { get; } - IDictionary ProductionCostByTechLevel { get; } + IDictionary ProductionCost { get; } IDictionary CalibrationDefaults { get; } ProductionDecalibration GetDecalibration(int targetDefinition); diff --git a/src/Perpetuum/Services/ProductionEngine/ProductionCost.cs b/src/Perpetuum/Services/ProductionEngine/ProductionCost.cs index 9e1fa664c..93d25613b 100644 --- a/src/Perpetuum/Services/ProductionEngine/ProductionCost.cs +++ b/src/Perpetuum/Services/ProductionEngine/ProductionCost.cs @@ -1,4 +1,9 @@ - +using System.Collections.Generic; +using System.Linq; +using Perpetuum.Data; +using Perpetuum.EntityFramework; +using Perpetuum.ExportedTypes; + namespace Perpetuum.Services.ProductionEngine { public class ProductionCost @@ -8,4 +13,61 @@ public class ProductionCost public int? tierLevel; public double costModifier; } -} + + public interface IProductionCostReader + { + IEnumerable ProductionCost { get; } + ProductionCost GetProductionCostByED(EntityDefault ed); + double GetProductionCostModByED(EntityDefault ed); + } + + public class ProductionCostReader : IProductionCostReader + { + private const double MIN = 1.0; + private const double MAX = 10.0; + + public IEnumerable ProductionCost + { + get { return _costTable.Values; } + } + private readonly IDictionary _costTable; + public ProductionCostReader() + { + _costTable = Database.CreateCache("productioncost", "id", r => + { + var cost = new ProductionCost + { + categoryFlag = r.GetValue(k.category), + tierType = r.GetValue(k.tierType), + tierLevel = r.GetValue(k.tierLevel), + costModifier = r.GetValue("costmodifier") + }; + return cost; + }); + } + + /// + /// Map an EntityDefault to a ProductionCost based on matching CategoryFlags, tierType, tierLevel. + /// Tiebreaker logic is weighted such that a match on Category > TierLevel > TierType + /// And where a match on TierLevel and Type will not outweigh Category + /// + /// EntityDefault + /// ProductionCost + public ProductionCost GetProductionCostByED(EntityDefault ed) + { + var matchScores = ProductionCost.GroupBy(c => + (((CategoryFlags)(c.categoryFlag ?? 0) == ed.CategoryFlags) ? 5 : 0) + + (((TierType)(c.tierType ?? 0) == ed.Tier.type) ? 1 : 0) + + (((c.tierLevel ?? 0) == ed.Tier.level) ? 3 : 0)); + + var bestMatchScore = matchScores.Max(x => x.Key); + return matchScores.FirstOrDefault(x => x.Key == bestMatchScore).Select(g => g).FirstOrDefault(); + } + + public double GetProductionCostModByED(EntityDefault ed) + { + var prodCost = GetProductionCostByED(ed) ?? (new ProductionCost { costModifier = MIN }); + return prodCost.costModifier.Clamp(MIN, MAX); + } + } +} \ No newline at end of file diff --git a/src/Perpetuum/Services/ProductionEngine/ProductionDataAccess.cs b/src/Perpetuum/Services/ProductionEngine/ProductionDataAccess.cs index 60b63db8a..497e812af 100644 --- a/src/Perpetuum/Services/ProductionEngine/ProductionDataAccess.cs +++ b/src/Perpetuum/Services/ProductionEngine/ProductionDataAccess.cs @@ -16,14 +16,14 @@ public class ProductionDataAccess : IProductionDataAccess private IDictionary _researchlevels; private ILookup _productionComponents; private IDictionary _productionDurations; - private IDictionary _productionCostByCategory; - private IDictionary _productionCostByTechLevel; private IDictionary _calibrationDefaults; private IDictionary _productionDecalibrations; + private IProductionCostReader _productionCostReader; - public ProductionDataAccess(IEntityDefaultReader entityDefaultReader) + public ProductionDataAccess(IEntityDefaultReader entityDefaultReader, IProductionCostReader costReader) { _entityDefaultReader = entityDefaultReader; + _productionCostReader = costReader; } public void Init() @@ -68,46 +68,11 @@ public void Init() return level; }, ItemResearchLevelFilter); - _productionCostByCategory = Database.CreateCache("productioncost", k.category, r => + ProductionCost = new Dictionary(); + foreach (var ed in EntityDefault.All) { - var cost = new ProductionCost - { - categoryFlag = r.GetValue(k.category), - tierType = r.GetValue(k.tierType), - tierLevel = r.GetValue(k.tierLevel), - costModifier = r.GetValue("costmodifier") - }; - return cost; - }, ProductionCostCategoryFilter); - - _productionCostByTechLevel = Database.CreateCache("productioncost", k.tierLevel, r => - { - var cost = new ProductionCost - { - categoryFlag = r.GetValue(k.category), - tierType = r.GetValue(k.tierType), - tierLevel = r.GetValue(k.tierLevel), - costModifier = r.GetValue("costmodifier") - }; - return cost; - }, ProductionCostTechFilter); - } - - public bool ProductionCostCategoryFilter(IDataRecord record) - { - long? categoryFlag = record.GetValue(k.category); - if (categoryFlag == null) - return false; - CategoryFlags flag = (CategoryFlags)categoryFlag; - return flag.IsCategoryExists(); - } - - public bool ProductionCostTechFilter(IDataRecord record) - { - int? level = record.GetValue(k.tierLevel); - if (level == null) - return false; - return level > 0; + ProductionCost.Add(ed.Definition, _productionCostReader.GetProductionCostModByED(ed)); + } } public bool ItemResearchLevelFilter(IDataRecord record) @@ -135,9 +100,8 @@ public bool ItemResearchLevelFilter(IDataRecord record) public IDictionary ResearchLevels => _researchlevels; public ILookup ProductionComponents => _productionComponents; public IDictionary ProductionDurations => _productionDurations; - public IDictionary ProductionCostByCategory => _productionCostByCategory; - public IDictionary ProductionCostByTechLevel => _productionCostByTechLevel; public IDictionary CalibrationDefaults => _calibrationDefaults; + public IDictionary ProductionCost { get; private set; } public ProductionDecalibration GetDecalibration(int targetDefinition) { diff --git a/src/Perpetuum/Services/ProductionEngine/ProductionDataAccessExtensions.cs b/src/Perpetuum/Services/ProductionEngine/ProductionDataAccessExtensions.cs index 0bb609879..89c2bd621 100644 --- a/src/Perpetuum/Services/ProductionEngine/ProductionDataAccessExtensions.cs +++ b/src/Perpetuum/Services/ProductionEngine/ProductionDataAccessExtensions.cs @@ -71,25 +71,25 @@ public static double GetProductionDuration(this IProductionDataAccess dataAccess return 1.0; } + /// + /// Applies EntityDefault specific cost modifiers based on tech level/type and category + /// + /// + /// + /// factor to multiply cost public static double GetProductionPriceModifier(this IProductionDataAccess dataAccess, int targetDefinition) { + var modifier = 1.0; if (!EntityDefault.TryGet(targetDefinition, out EntityDefault ed)) { Logger.Error("definition was not found: " + targetDefinition); - return 1.0; + return modifier; } - var modifier = 1.0; - - if (dataAccess.ProductionCostByCategory.TryGetValue(ed.CategoryFlags, out ProductionCost costByCat)) + if (dataAccess.ProductionCost.TryGetValue(ed.Definition, out double value)) { - modifier = costByCat.costModifier; + modifier = value; } - else if (dataAccess.ProductionCostByTechLevel.TryGetValue(ed.Tier.level, out ProductionCost costByLevel)) - { - modifier = costByLevel.costModifier; - } - return modifier; }