From 4bb8616e27f769d4cdf4482684066eca91ead8cd Mon Sep 17 00:00:00 2001 From: Platinum Date: Wed, 7 Feb 2024 19:26:11 +1100 Subject: [PATCH] Use jsonc --- advancedConfig.json => advancedConfig.jsonc | 2 +- config.json => config.jsonc | 0 package.json | 5 +- src/helpers.ts | 28 --------- src/mod.ts | 68 +++++++++++++++------ 5 files changed, 53 insertions(+), 50 deletions(-) rename advancedConfig.json => advancedConfig.jsonc (92%) rename config.json => config.jsonc (100%) diff --git a/advancedConfig.json b/advancedConfig.jsonc similarity index 92% rename from advancedConfig.json rename to advancedConfig.jsonc index 519a345..2c0f169 100644 --- a/advancedConfig.json +++ b/advancedConfig.jsonc @@ -2,7 +2,7 @@ "baselineBulletId": "59e6906286f7746c9f75e847", "baselineBulletPrice": 1000, "bulletDamageMultiplierRedutionFactor": 0.7, - "enableDebug": false, + "enableDebug": true, "excludedCategories": ["5b5f78b786f77447ed5636af", "5b47574386f77428ca22b33c"], "useTraderPriceForOffersIfHigher": true, "handbookPriceMultiplier": 3 diff --git a/config.json b/config.jsonc similarity index 100% rename from config.json rename to config.jsonc diff --git a/package.json b/package.json index fc1acbe..172b2e5 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "fs-extra": "11.1.0", "glob": "8.0.3", "tsyringe": "4.7.0", - "typescript": "4.9.4" + "typescript": "4.9.4", + "jsonc": "^2.0.0" } -} \ No newline at end of file +} diff --git a/src/helpers.ts b/src/helpers.ts index 756e5d8..ad3d047 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -18,9 +18,6 @@ import { Category } from "@spt-aki/models/eft/common/tables/IHandbookBase"; import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem"; -import config from "../config.json"; -import advancedConfig from "../advancedConfig.json"; - // There are so many child categories of attachments, this will return all categories using recursion so I don't have to type each ID. export function getAttachmentCategoryIds(handbookCategories: Category[]): string[] { const weaponPartsAndModsId = "5b5f71a686f77447ed5636ab"; @@ -45,29 +42,4 @@ export function isBulletOrShotgunShell(item: ITemplateItem): boolean { const props = item._props; return props.ammoType === "bullet" || props.ammoType === "buckshot"; -} - -export function getUpdatedAmmoPrice(item: ITemplateItem, baselineBullet: ITemplateItem): number { - const baselinePen = baselineBullet._props.PenetrationPower; - const baselineDamage = baselineBullet._props.Damage; - - const basePenetrationMultiplier = item._props.PenetrationPower / baselinePen; - const baseDamageMultiplier = item._props.Damage / baselineDamage; - - let penetrationMultiplier: number; - if (basePenetrationMultiplier > 1) { - // A good gradient to make higher power rounds more expensive - penetrationMultiplier = 7 * basePenetrationMultiplier - 6; - } else { - // Due to maths above, its really easy to go < 1. The baseline ammo is mid tier with a reasonable 1000 rouble each. Ammo weaker than this tend to be pretty crap so we'll make it much cheaper - const newMultiplier = basePenetrationMultiplier * 0.7; - penetrationMultiplier = newMultiplier < 0.1 ? 0.1 : newMultiplier; - } - - // Reduces the effect of the damage multiplier so high DMG rounds aren't super expensive. - // Eg. let baseDamageMultiplier = 2 & bulletDamageMultiplierRedutionFactor = 0.7. Instead of a 2x price when a bullet is 2x damage, we instead get: - // 2 + (1 - 2) * 0.7 = 2 - 0.7 = 1.3x the price. - const damageMultiplier = baseDamageMultiplier + (1 - baseDamageMultiplier) * advancedConfig.bulletDamageMultiplierRedutionFactor; - - return advancedConfig.baselineBulletPrice * penetrationMultiplier * damageMultiplier * config.blacklistedAmmoAdditionalPriceMultiplier; } \ No newline at end of file diff --git a/src/mod.ts b/src/mod.ts index e386cbd..bc45690 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -16,6 +16,8 @@ // along with spt-the-blacklist. If not, see . import { DependencyContainer } from "tsyringe"; +import { jsonc } from "jsonc"; +import path from "path"; import { DatabaseServer } from "@spt-aki/servers/DatabaseServer"; import { IPostDBLoadModAsync } from "@spt-aki/models/external/IPostDBLoadModAsync"; @@ -26,9 +28,7 @@ import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { HandbookItem } from "@spt-aki/models/eft/common/tables/IHandbookBase"; -import config from "../config.json"; -import advancedConfig from "../advancedConfig.json"; -import { getAttachmentCategoryIds, getUpdatedAmmoPrice, isBulletOrShotgunShell } from "./helpers"; +import { getAttachmentCategoryIds, isBulletOrShotgunShell } from "./helpers"; class TheBlacklistMod implements IPostDBLoadModAsync { private logger: ILogger; @@ -46,9 +46,14 @@ class TheBlacklistMod implements IPostDBLoadModAsync { private nonBlacklistedItemsUpdatedCount = 0; private ammoPricesUpdatedCount = 0; + private config; + private advancedConfig; + public async postDBLoadAsync(container: DependencyContainer) { this.logger = container.resolve("WinstonLogger"); - + this.config = await jsonc.read(path.resolve(__dirname, "../config.jsonc")); + this.advancedConfig = await jsonc.read(path.resolve(__dirname, "../advancedConfig.jsonc")); + const databaseServer = container.resolve("DatabaseServer"); const tables = databaseServer.getTables(); const configServer = container.resolve("ConfigServer"); @@ -58,12 +63,12 @@ class TheBlacklistMod implements IPostDBLoadModAsync { const handbookItems = tables.templates.handbook.Items; const prices = tables.templates.prices; - ragfairConfig.dynamic.blacklist.enableBsgList = !config.disableBsgBlacklist; - ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = advancedConfig.useTraderPriceForOffersIfHigher != null ? advancedConfig.useTraderPriceForOffersIfHigher : true; + this.baselineBullet = itemTable[this.advancedConfig.baselineBulletId]; - this.baselineBullet = itemTable[advancedConfig.baselineBulletId]; + ragfairConfig.dynamic.blacklist.enableBsgList = !this.config.disableBsgBlacklist; + ragfairConfig.dynamic.useTraderPriceForOffersIfHigher = this.advancedConfig.useTraderPriceForOffersIfHigher != null ? this.advancedConfig.useTraderPriceForOffersIfHigher : true; - if (config.limitMaxPriceOfAttachments) { + if (this.config.limitMaxPriceOfAttachments) { this.attachmentCategoryIds = getAttachmentCategoryIds(tables.templates.handbook.Categories); } @@ -77,7 +82,7 @@ class TheBlacklistMod implements IPostDBLoadModAsync { return; } - if (config.limitMaxPriceOfAttachments && this.attachmentCategoryIds.includes(handbookItem.ParentId)) { + if (this.config.limitMaxPriceOfAttachments && this.attachmentCategoryIds.includes(handbookItem.ParentId)) { this.updateAttachmentPrice(handbookItem, item, prices); } @@ -89,7 +94,7 @@ class TheBlacklistMod implements IPostDBLoadModAsync { if (!itemProps.CanSellOnRagfair) { // Some blacklisted items are hard to balance or just shouldn't be allowed so we will keep them blacklisted. - if (advancedConfig.excludedCategories.some(category => category === handbookItem.ParentId)) { + if (this.advancedConfig.excludedCategories.some(category => category === handbookItem.ParentId)) { ragfairConfig.dynamic.blacklist.custom.push(item._id); this.debug(`Blacklisted item ${item._id} - ${item._name} because we are excluding handbook category ${handbookItem.ParentId}.`); return; @@ -109,16 +114,16 @@ class TheBlacklistMod implements IPostDBLoadModAsync { }); this.logger.success(`${this.modName}: Success! Found ${this.blacklistedItemsUpdatedCount} blacklisted & ${this.nonBlacklistedItemsUpdatedCount} non-blacklisted items to update.`); - if (config.limitMaxPriceOfAttachments) { + if (this.config.limitMaxPriceOfAttachments) { this.logger.success(`${this.modName}: config.limitMaxPriceOfAttachments is enabled! Updated ${this.attachmentPriceLimitedCount} flea prices of attachments.`); } - if (config.useBalancedPricingForAllAmmo) { + if (this.config.useBalancedPricingForAllAmmo) { this.logger.success(`${this.modName}: config.useBalancedPricingForAllAmmo is enabled! Updated ${this.ammoPricesUpdatedCount} ammo prices.`); } } private updateItemUsingCustomItemConfig(item: ITemplateItem , prices: Record, originalPrice: number, ragfairConfig: IRagfairConfig): boolean { - const customItemConfig = config.customItemConfigs.find(conf => conf.itemId === item._id); + const customItemConfig = this.config.customItemConfigs.find(conf => conf.itemId === item._id); if (!customItemConfig) { return false; @@ -153,7 +158,7 @@ class TheBlacklistMod implements IPostDBLoadModAsync { private updateAttachmentPrice(handbookItem: HandbookItem, item: ITemplateItem, prices: Record) { const handbookPrice = handbookItem.Price; const existingFleaPrice = prices[item._id]; - const maxFleaPrice = handbookPrice * config.maxFleaPriceOfAttachmentsToHandbookPrice; + const maxFleaPrice = handbookPrice * this.config.maxFleaPriceOfAttachmentsToHandbookPrice; if (existingFleaPrice > maxFleaPrice) { prices[item._id] = maxFleaPrice; @@ -168,11 +173,11 @@ class TheBlacklistMod implements IPostDBLoadModAsync { const itemProps = item._props; // We don't care about this standard ammo item if we haven't enabled useBalancedPricingForAllAmmo - if (itemProps.CanSellOnRagfair && !config.useBalancedPricingForAllAmmo) { + if (itemProps.CanSellOnRagfair && !this.config.useBalancedPricingForAllAmmo) { return; } - const newPrice = getUpdatedAmmoPrice(item, this.baselineBullet); + const newPrice = this.getUpdatedAmmoPrice(item); prices[item._id] = newPrice; if (!itemProps.CanSellOnRagfair) { @@ -184,19 +189,44 @@ class TheBlacklistMod implements IPostDBLoadModAsync { this.ammoPricesUpdatedCount++; } + private getUpdatedAmmoPrice(item: ITemplateItem): number { + const baselinePen = this.baselineBullet._props.PenetrationPower; + const baselineDamage = this.baselineBullet._props.Damage; + + const basePenetrationMultiplier = item._props.PenetrationPower / baselinePen; + const baseDamageMultiplier = item._props.Damage / baselineDamage; + + let penetrationMultiplier: number; + if (basePenetrationMultiplier > 1) { + // A good gradient to make higher power rounds more expensive + penetrationMultiplier = 7 * basePenetrationMultiplier - 6; + } else { + // Due to maths above, its really easy to go < 1. The baseline ammo is mid tier with a reasonable 1000 rouble each. Ammo weaker than this tend to be pretty crap so we'll make it much cheaper + const newMultiplier = basePenetrationMultiplier * 0.7; + penetrationMultiplier = newMultiplier < 0.1 ? 0.1 : newMultiplier; + } + + // Reduces the effect of the damage multiplier so high DMG rounds aren't super expensive. + // Eg. let baseDamageMultiplier = 2 & bulletDamageMultiplierRedutionFactor = 0.7. Instead of a 2x price when a bullet is 2x damage, we instead get: + // 2 + (1 - 2) * 0.7 = 2 - 0.7 = 1.3x the price. + const damageMultiplier = baseDamageMultiplier + (1 - baseDamageMultiplier) * this.advancedConfig.bulletDamageMultiplierRedutionFactor; + + return this.advancedConfig.baselineBulletPrice * penetrationMultiplier * damageMultiplier * this.config.blacklistedAmmoAdditionalPriceMultiplier; + } + private getUpdatedPrice(handbookItem: HandbookItem, item: ITemplateItem, prices: Record): number | undefined { // If a flea price doesn't exist for an item, we can multiply its handbook price which usually exists. if (prices[item._id] == null) { const handbookPrice = handbookItem.Price; - return handbookPrice * advancedConfig.handbookPriceMultiplier; + return handbookPrice * this.advancedConfig.handbookPriceMultiplier; } - return prices[item._id] * config.blacklistedItemPriceMultiplier; + return prices[item._id] * this.config.blacklistedItemPriceMultiplier; } private debug(message: string) { - if (advancedConfig.enableDebug) { + if (this.advancedConfig.enableDebug) { this.logger.debug(`${this.modName}: ${message}`); } }