From 86497afc1c442301894555ab710229085dab6266 Mon Sep 17 00:00:00 2001 From: idinium96 <47635037+idinium96@users.noreply.github.com> Date: Mon, 19 Apr 2021 23:20:18 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20support=20processing=20Non-TF2?= =?UTF-8?q?=20items=20(offer=20only)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Commands/sub-classes/Review.ts | 6 +- src/classes/MyHandler/MyHandler.ts | 114 +++++++++--------- .../offer/accepted/processAccepted.ts | 10 +- .../offer/accepted/updateListings.ts | 5 + .../offer/review/reasons/invalidItems.ts | 3 +- src/lib/extend/item/getSKU.ts | 4 + src/lib/tools/export.ts | 4 +- src/lib/tools/getHighValue.ts | 5 + src/lib/tools/summarizeItems.ts | 4 +- src/lib/tools/summarizeOffer.ts | 15 ++- src/lib/tools/testSKU.ts | 5 + 11 files changed, 103 insertions(+), 72 deletions(-) create mode 100644 src/lib/tools/testSKU.ts diff --git a/src/classes/Commands/sub-classes/Review.ts b/src/classes/Commands/sub-classes/Review.ts index b683f1c19..a2e229a05 100644 --- a/src/classes/Commands/sub-classes/Review.ts +++ b/src/classes/Commands/sub-classes/Review.ts @@ -7,7 +7,7 @@ import SKU from 'tf2-sku-2'; import SchemaManager from 'tf2-schema-2'; import Bot from '../../Bot'; import CommandParser from '../../CommandParser'; -import { generateLinks } from '../../../lib/tools/export'; +import { generateLinks, testSKU } from '../../../lib/tools/export'; // Manual review commands @@ -146,7 +146,9 @@ export default class ReviewCommands { continue; } - summary.push(schema.getName(SKU.fromString(sku), false) + (dict[sku] > 1 ? ` x${dict[sku]}` : '')); // dict[sku] = amount + const name = testSKU(sku) ? schema.getName(SKU.fromString(sku), false) : sku; + + summary.push(name + (dict[sku] > 1 ? ` x${dict[sku]}` : '')); // dict[sku] = amount } if (summary.length === 0) { diff --git a/src/classes/MyHandler/MyHandler.ts b/src/classes/MyHandler/MyHandler.ts index c50601b09..f4a6f6aeb 100644 --- a/src/classes/MyHandler/MyHandler.ts +++ b/src/classes/MyHandler/MyHandler.ts @@ -42,7 +42,7 @@ import { exponentialBackoff } from '../../lib/helpers'; import { noiseMakers } from '../../lib/data'; import { sendAlert, sendStats } from '../../lib/DiscordWebhook/export'; -import { summarize, uptime, getHighValueItems } from '../../lib/tools/export'; +import { summarize, uptime, getHighValueItems, testSKU } from '../../lib/tools/export'; import genPaths from '../../resources/paths'; import Pricer, { RequestCheckFn } from '../Pricer'; @@ -758,7 +758,7 @@ export default class MyHandler extends Handler { let isNoiseMakerNotFullUses = false; const noiseMakerNotFullSKUs: string[] = []; - let hasInvalidItems = false; + // let hasInvalidItems = false; const states = [false, true]; for (let i = 0; i < states.length; i++) { @@ -770,10 +770,10 @@ export default class MyHandler extends Handler { continue; } - if (sku === 'unknown') { - // Offer contains an item that is not from TF2 - hasInvalidItems = true; - } + // if (sku === 'unknown') { + // // Offer contains an item that is not from TF2 + // hasInvalidItems = true; + // } if (sku === '5000;6') { exchange.contains.metal = true; @@ -907,11 +907,11 @@ export default class MyHandler extends Handler { return; } - if (hasInvalidItems) { - // Using boolean because items dict always needs to be saved - offer.log('info', 'contains items not from TF2, declining...'); - return { action: 'decline', reason: '🟨_INVALID_ITEMS_CONTAINS_NON_TF2' }; - } + // if (hasInvalidItems) { + // // Using boolean because items dict always needs to be saved + // offer.log('info', 'contains items not from TF2, declining...'); + // return { action: 'decline', reason: '🟨_INVALID_ITEMS_CONTAINS_NON_TF2' }; + // } const offerMessage = offer.message.toLowerCase(); @@ -1111,8 +1111,12 @@ export default class MyHandler extends Handler { } else { const match = which === 'our' - ? this.bot.pricelist.getPrice(sku) - : this.bot.pricelist.getPrice(sku, false, true); + ? testSKU(sku) + ? this.bot.pricelist.getPrice(sku) + : null + : testSKU(sku) + ? this.bot.pricelist.getPrice(sku, false, true) + : null; const notIncludeCraftweapons = this.isWeaponsAsCurrency.enable ? !( @@ -1227,59 +1231,61 @@ export default class MyHandler extends Handler { (match !== null && match.intent === (buying ? 1 : 0)) ) { // Offer contains an item that we are not trading - hasInvalidItems = true; + // hasInvalidItems = true; // If that particular item is on our side, then put to review if (which === 'our') { hasInvalidItemsOur = true; } - // await sleepasync().Promise.sleep(1 * 1000); - const price = await this.bot.pricelist.getItemPrices(sku); - const item = SKU.fromString(sku); - - const isCrateOrCases = item.crateseries !== null || ['5737;6', '5738;6'].includes(sku); - // 5737;6 and 5738;6 - Mann Co. Stockpile Crate + let itemSuggestedValue = 'No price'; - const isWinterNoiseMaker = ['673;6'].includes(sku); + if (testSKU(sku)) { + // await sleepasync().Promise.sleep(1 * 1000); + const price = await this.bot.pricelist.getItemPrices(sku); + const item = SKU.fromString(sku); - const isSkinsOrWarPaints = item.wear !== null; + const isCrateOrCases = item.crateseries !== null || ['5737;6', '5738;6'].includes(sku); + // 5737;6 and 5738;6 - Mann Co. Stockpile Crate - let itemSuggestedValue: string; - if (price === null) { - itemSuggestedValue = 'No price'; - hasNoPrice = true; - } else { - price.buy = new Currencies(price.buy); - price.sell = new Currencies(price.sell); + const isWinterNoiseMaker = ['673;6'].includes(sku); - itemPrices[sku] = { - buy: price.buy, - sell: price.sell - }; + const isSkinsOrWarPaints = item.wear !== null; - if ( - opt.offerReceived.invalidItems.givePrice && - !isSkinsOrWarPaints && - !isCrateOrCases && - !isWinterNoiseMaker // all of these (with !) should be false in order to be true - ) { - // if offerReceived.invalidItems.givePrice is set to true (enable) and items is not skins/war paint/crate/cases, - // then give that item price and include in exchange - exchange[which].value += price[intentString].toValue(keyPrice.metal) * amount; - exchange[which].keys += price[intentString].keys * amount; - exchange[which].scrap += Currencies.toScrap(price[intentString].metal) * amount; + if (price === null) { + hasNoPrice = true; + } else { + price.buy = new Currencies(price.buy); + price.sell = new Currencies(price.sell); + + itemPrices[sku] = { + buy: price.buy, + sell: price.sell + }; + + if ( + opt.offerReceived.invalidItems.givePrice && + !isSkinsOrWarPaints && + !isCrateOrCases && + !isWinterNoiseMaker // all of these (with !) should be false in order to be true + ) { + // if offerReceived.invalidItems.givePrice is set to true (enable) and items is not skins/war paint/crate/cases, + // then give that item price and include in exchange + exchange[which].value += price[intentString].toValue(keyPrice.metal) * amount; + exchange[which].keys += price[intentString].keys * amount; + exchange[which].scrap += Currencies.toScrap(price[intentString].metal) * amount; + } + const valueInRef = { + buy: Currencies.toRefined(price.buy.toValue(keyPrice.metal)), + sell: Currencies.toRefined(price.sell.toValue(keyPrice.metal)) + }; + + itemSuggestedValue = + (intentString === 'buy' ? valueInRef.buy : valueInRef.sell) >= keyPrice.metal + ? `${valueInRef.buy.toString()} ref (${price.buy.toString()})` + + ` / ${valueInRef.sell.toString()} ref (${price.sell.toString()})` + : `${price.buy.toString()} / ${price.sell.toString()}`; } - const valueInRef = { - buy: Currencies.toRefined(price.buy.toValue(keyPrice.metal)), - sell: Currencies.toRefined(price.sell.toValue(keyPrice.metal)) - }; - - itemSuggestedValue = - (intentString === 'buy' ? valueInRef.buy : valueInRef.sell) >= keyPrice.metal - ? `${valueInRef.buy.toString()} ref (${price.buy.toString()})` + - ` / ${valueInRef.sell.toString()} ref (${price.sell.toString()})` - : `${price.buy.toString()} / ${price.sell.toString()}`; } wrongAboutOffer.push({ diff --git a/src/classes/MyHandler/offer/accepted/processAccepted.ts b/src/classes/MyHandler/offer/accepted/processAccepted.ts index a59440d41..1551c8b1c 100644 --- a/src/classes/MyHandler/offer/accepted/processAccepted.ts +++ b/src/classes/MyHandler/offer/accepted/processAccepted.ts @@ -41,13 +41,9 @@ export default function processAccepted( // doing this so it will only executed if includes 🟨_INVALID_ITEMS reason. (meta.reasons.filter(el => el.reason === '🟨_INVALID_ITEMS') as i.InvalidItems[]).forEach(el => { - accepted.invalidItems.push( - `${ - isWebhookEnabled - ? `_${bot.schema.getName(SKU.fromString(el.sku), false)}_` - : bot.schema.getName(SKU.fromString(el.sku), false) - } - ${el.price}` - ); + const name = t.testSKU(el.sku) ? bot.schema.getName(SKU.fromString(el.sku), false) : el.sku; + + accepted.invalidItems.push(`${isWebhookEnabled ? `_${name}_` : name} - ${el.price}`); }); } if (meta?.uniqueReasons?.includes('🟧_DISABLED_ITEMS')) { diff --git a/src/classes/MyHandler/offer/accepted/updateListings.ts b/src/classes/MyHandler/offer/accepted/updateListings.ts index 4239d00ed..008940476 100644 --- a/src/classes/MyHandler/offer/accepted/updateListings.ts +++ b/src/classes/MyHandler/offer/accepted/updateListings.ts @@ -10,6 +10,7 @@ import { EntryData } from '../../../Pricelist'; import log from '../../../../lib/logger'; import { sendAlert } from '../../../../lib/DiscordWebhook/export'; import { PaintedNames } from '../../../Options'; +import { testSKU } from '../../../../lib/tools/export'; let itemsFromPreviousTrades: string[] = []; @@ -43,6 +44,10 @@ export default function updateListings( continue; } + if (!testSKU(sku)) { + continue; + } + const item = SKU.fromString(sku); const name = bot.schema.getName(item, false); const pure = ['5000;6', '5001;6', '5002;6']; diff --git a/src/classes/MyHandler/offer/review/reasons/invalidItems.ts b/src/classes/MyHandler/offer/review/reasons/invalidItems.ts index f9dcb3f6c..1116fd3f2 100644 --- a/src/classes/MyHandler/offer/review/reasons/invalidItems.ts +++ b/src/classes/MyHandler/offer/review/reasons/invalidItems.ts @@ -2,6 +2,7 @@ import SKU from 'tf2-sku-2'; import pluralize from 'pluralize'; import { Meta, InvalidItems } from '@tf2autobot/tradeoffer-manager'; import Bot from '../../../../Bot'; +import { testSKU } from '../../../../../lib/tools/export'; export default function invalidItems(meta: Meta, bot: Bot): { note: string; name: string[] } { const opt = bot.options.discordWebhook.offerReview; @@ -9,7 +10,7 @@ export default function invalidItems(meta: Meta, bot: Bot): { note: string; name const invalidForOur: string[] = []; // Display for owner (meta.reasons.filter(el => el.reason.includes('🟨_INVALID_ITEMS')) as InvalidItems[]).forEach(el => { - const name = bot.schema.getName(SKU.fromString(el.sku), false); + const name = testSKU(el.sku) ? bot.schema.getName(SKU.fromString(el.sku), false) : el.sku; if (opt.enable && opt.url !== '') { // show both item name and prices.tf price diff --git a/src/lib/extend/item/getSKU.ts b/src/lib/extend/item/getSKU.ts index a74df7cf8..0959995ae 100644 --- a/src/lib/extend/item/getSKU.ts +++ b/src/lib/extend/item/getSKU.ts @@ -18,6 +18,10 @@ export = function ( const self = this as EconItem; if (self.appid != 440) { + if (self.type && self.market_name) { + return `${self.type}: ${self.market_name}`; + } + return 'unknown'; } diff --git a/src/lib/tools/export.ts b/src/lib/tools/export.ts index 148f788ea..6ec9e4cf6 100644 --- a/src/lib/tools/export.ts +++ b/src/lib/tools/export.ts @@ -9,6 +9,7 @@ import listItems from './summarizeItems'; import summarize, { summarizeToChat } from './summarizeOffer'; import profit from './profit'; import itemStats from './itemStats'; +import testSKU from './testSKU'; export { getHighValueItems, @@ -26,5 +27,6 @@ export { uptime, convertTime, profit, - itemStats + itemStats, + testSKU }; diff --git a/src/lib/tools/getHighValue.ts b/src/lib/tools/getHighValue.ts index db65fdb77..4032ddb59 100644 --- a/src/lib/tools/getHighValue.ts +++ b/src/lib/tools/getHighValue.ts @@ -3,6 +3,7 @@ import { Items } from '@tf2autobot/tradeoffer-manager'; import { spellsData, killstreakersData, sheensData } from '../data'; import Bot from '../../classes/Bot'; import { Paints, StrangeParts } from 'tf2-schema-2'; +import { testSKU } from '../tools/export'; export default function getHighValueItems( items: Items, @@ -22,6 +23,10 @@ export default function getHighValueItems( continue; } + if (!testSKU(sku)) { + continue; + } + let toString = ''; const toJoin: string[] = []; diff --git a/src/lib/tools/summarizeItems.ts b/src/lib/tools/summarizeItems.ts index 96ced38a1..a3ad18a2d 100644 --- a/src/lib/tools/summarizeItems.ts +++ b/src/lib/tools/summarizeItems.ts @@ -2,7 +2,7 @@ import { TradeOffer, Prices } from '@tf2autobot/tradeoffer-manager'; import SKU from 'tf2-sku-2'; import Currencies from 'tf2-currencies-2'; import Bot from '../../classes/Bot'; -import { replace } from '../tools/export'; +import { replace, testSKU } from '../tools/export'; export default function listItems( offer: TradeOffer, @@ -134,7 +134,7 @@ function listPrices(offer: TradeOffer, bot: Bot, isSteamChat: boolean): string { sellPrice = new Currencies(prices[sku].sell).toString(); } - const name = bot.schema.getName(SKU.fromString(sku), properName); + const name = testSKU(sku) ? bot.schema.getName(SKU.fromString(sku), properName) : sku; toJoin.push( `${ diff --git a/src/lib/tools/summarizeOffer.ts b/src/lib/tools/summarizeOffer.ts index a8f14f7f1..4ee7dc466 100644 --- a/src/lib/tools/summarizeOffer.ts +++ b/src/lib/tools/summarizeOffer.ts @@ -89,8 +89,6 @@ export function summarizeToChat( type SummarizeType = 'summary-accepted' | 'declined' | 'review-partner' | 'review-admin' | 'summary-accepting'; import Currencies from 'tf2-currencies-2'; -import SKU from 'tf2-sku-2'; -import { replace } from '../tools/export'; export default function summarize( offer: TradeOffer, @@ -144,6 +142,9 @@ export default function summarize( } } +import SKU from 'tf2-sku-2'; +import { replace, testSKU } from '../tools/export'; + function getSummary( dict: OurTheirItemsDict, bot: Bot, @@ -165,9 +166,13 @@ function getSummary( continue; } + const isTF2Items = testSKU(sku); + // compatible with pollData from before v3.0.0 / before v2.2.0 and/or v3.0.0 or later ↓ const amount = typeof dict[sku] === 'object' ? (dict[sku]['amount'] as number) : dict[sku]; - const generateName = bot.schema.getName(SKU.fromString(sku.replace(/;p\d+/, '')), properName); + const generateName = isTF2Items + ? bot.schema.getName(SKU.fromString(sku.replace(/;p\d+/, '')), properName) + : sku; // Non-TF2 items const name = properName ? generateName : replace.itemName(generateName ? generateName : 'unknown'); if (showStockChanges) { @@ -191,7 +196,7 @@ function getSummary( oldStock = currentStock; } - if (withLink) { + if (withLink && isTF2Items) { summary.push( `[${ bot.options.tradeSummary.showPureInEmoji @@ -229,7 +234,7 @@ function getSummary( ); } } else { - if (withLink) { + if (withLink && isTF2Items) { summary.push( `[${ bot.options.tradeSummary.showPureInEmoji diff --git a/src/lib/tools/testSKU.ts b/src/lib/tools/testSKU.ts new file mode 100644 index 000000000..f4dfc131a --- /dev/null +++ b/src/lib/tools/testSKU.ts @@ -0,0 +1,5 @@ +export default function testSKU(sku: string): boolean { + return /^(\d+);([0-9]|[1][0-5])(;((uncraftable)|(untrad(e)?able)|(australium)|(festive)|(strange)|((u|pk|td-|c|od-|oq-|p)\d+)|(w[1-5])|(kt-[1-3])|(n((100)|[1-9]\d?))))*?$/.test( + sku + ); +} From e4a2ff981c20e43e0ba8811ac97105d2a5dae514 Mon Sep 17 00:00:00 2001 From: idinium96 <47635037+idinium96@users.noreply.github.com> Date: Thu, 22 Apr 2021 17:04:35 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20opt=20to=20always=20decline=20n?= =?UTF-8?q?on-TF2=20items=20+=20refactor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/MyHandler/MyHandler.ts | 47 ++++++++++++++++++----------- src/classes/Options.ts | 2 ++ src/schemas/options-json/options.ts | 3 ++ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/classes/MyHandler/MyHandler.ts b/src/classes/MyHandler/MyHandler.ts index f4a6f6aeb..06ba0c8e8 100644 --- a/src/classes/MyHandler/MyHandler.ts +++ b/src/classes/MyHandler/MyHandler.ts @@ -758,7 +758,7 @@ export default class MyHandler extends Handler { let isNoiseMakerNotFullUses = false; const noiseMakerNotFullSKUs: string[] = []; - // let hasInvalidItems = false; + let hasNonTF2Items = false; const states = [false, true]; for (let i = 0; i < states.length; i++) { @@ -770,10 +770,10 @@ export default class MyHandler extends Handler { continue; } - // if (sku === 'unknown') { - // // Offer contains an item that is not from TF2 - // hasInvalidItems = true; - // } + if (!testSKU(sku)) { + // Offer contains an item that is not from TF2 + hasNonTF2Items = true; + } if (sku === '5000;6') { exchange.contains.metal = true; @@ -907,11 +907,11 @@ export default class MyHandler extends Handler { return; } - // if (hasInvalidItems) { - // // Using boolean because items dict always needs to be saved - // offer.log('info', 'contains items not from TF2, declining...'); - // return { action: 'decline', reason: '🟨_INVALID_ITEMS_CONTAINS_NON_TF2' }; - // } + if (hasNonTF2Items && opt.offerReceived.alwaysDeclineNonTF2Items) { + // Using boolean because items dict always needs to be saved + offer.log('info', 'contains items not from TF2, declining...'); + return { action: 'decline', reason: '🟨_CONTAINS_NON_TF2' }; + } const offerMessage = offer.message.toLowerCase(); @@ -1089,6 +1089,8 @@ export default class MyHandler extends Handler { const amount = items[which][sku].length; + let isNonTF2Items = false; + if (sku === '5000;6') { exchange[which].value += amount; exchange[which].scrap += amount; @@ -1109,14 +1111,23 @@ export default class MyHandler extends Handler { exchange[which].value += value; exchange[which].scrap += value; } else { - const match = - which === 'our' - ? testSKU(sku) + let match: Entry | null = null; + + if (hasNonTF2Items) { + if (testSKU(sku)) { + match = + which === 'our' + ? this.bot.pricelist.getPrice(sku) + : this.bot.pricelist.getPrice(sku, false, true); + } else { + isNonTF2Items = true; + } + } else { + match = + which === 'our' ? this.bot.pricelist.getPrice(sku) - : null - : testSKU(sku) - ? this.bot.pricelist.getPrice(sku, false, true) - : null; + : this.bot.pricelist.getPrice(sku, false, true); + } const notIncludeCraftweapons = this.isWeaponsAsCurrency.enable ? !( @@ -1240,7 +1251,7 @@ export default class MyHandler extends Handler { let itemSuggestedValue = 'No price'; - if (testSKU(sku)) { + if (!isNonTF2Items) { // await sleepasync().Promise.sleep(1 * 1000); const price = await this.bot.pricelist.getItemPrices(sku); const item = SKU.fromString(sku); diff --git a/src/classes/Options.ts b/src/classes/Options.ts index 30fbb6d23..ca2129518 100644 --- a/src/classes/Options.ts +++ b/src/classes/Options.ts @@ -273,6 +273,7 @@ export const DEFAULTS = { sendPreAcceptMessage: { enable: true }, + alwaysDeclineNonTF2Items: true, // 🟥_INVALID_VALUE invalidValue: { autoDecline: { @@ -1269,6 +1270,7 @@ interface Metals extends OnlyEnable { interface OfferReceived { sendPreAcceptMessage?: OnlyEnable; + alwaysDeclineNonTF2Items?: boolean; invalidValue?: InvalidValue; invalidItems?: InvalidItems; disabledItems?: AutoAcceptOverpayAndAutoDecline; diff --git a/src/schemas/options-json/options.ts b/src/schemas/options-json/options.ts index f492e70db..8881dc3ed 100644 --- a/src/schemas/options-json/options.ts +++ b/src/schemas/options-json/options.ts @@ -992,6 +992,9 @@ export const optionsSchema: jsonschema.Schema = { sendPreAcceptMessage: { $ref: '#/definitions/only-enable' }, + alwaysDeclineNonTF2Items: { + type: 'boolean' + }, invalidValue: { type: 'object', properties: {