From b19129776a1de6b5ca56140388c471e3d5a0fa7c Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:19:34 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=F0=9F=A7=AA=20read=20the=20tf2.backpack?= =?UTF-8?q?=20content?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 9b4df9080..8c3b04bf9 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -814,6 +814,26 @@ export default class Bot { } }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.tf2.on('backpackLoaded', () => { + fs.writeFile( + path.join(__dirname, `../../files/test/bp-${Date.now() / 1000}`), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + JSON.stringify(this.tf2.backpack), + { encoding: 'utf-8' }, + err => { + if (err) { + log.error('save backpack error', err); + return; + } + + log.debug('backpackLoaded event emitted.'); + } + ); + }); + const firstTwoChain = [ async () => { log.debug('Calling onRun'); From 6ee51ed558ae56d4026691e08d139539a74842f6 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:25:06 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=94=A8=20forgot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 8c3b04bf9..d62251274 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -817,8 +817,12 @@ export default class Bot { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.tf2.on('backpackLoaded', () => { + if (!fs.existsSync(path.join(__dirname, `../../files/test`))) { + fs.mkdirSync(path.join(__dirname, `../../files/test`)); + } + fs.writeFile( - path.join(__dirname, `../../files/test/bp-${Date.now() / 1000}`), + path.join(__dirname, `../../files/test/bp-${Date.now() / 1000}.json`), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore JSON.stringify(this.tf2.backpack), From 7582433b6d071b06b41f4f671f603f63b220fea5 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:26:29 +0800 Subject: [PATCH 03/17] =?UTF-8?q?=F0=9F=94=A8=20no=20need=20decimals?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index d62251274..937469181 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -822,7 +822,7 @@ export default class Bot { } fs.writeFile( - path.join(__dirname, `../../files/test/bp-${Date.now() / 1000}.json`), + path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore JSON.stringify(this.tf2.backpack), From 53e2c25787ac18d2d8ee0313dc915ff53b332a5d Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 00:51:57 +0800 Subject: [PATCH 04/17] =?UTF-8?q?=F0=9F=A7=AA=20test=20with=20tf2-backpack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 71 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/classes/Bot.ts | 10 ++++++- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 0e0e49f16..e2c1beded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "steam-totp": "^2.1.2", "steam-user": "^4.26.1", "steamid": "^2.0.0", + "tf2-backpack": "^1.1.5", "url": "^0.11.0", "valid-url": "^1.0.9", "winston": "^3.8.2", @@ -10449,6 +10450,42 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/tf2-backpack": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tf2-backpack/-/tf2-backpack-1.1.5.tgz", + "integrity": "sha512-iuBb1yP8uvpIk+ate8TEkmePg6hGs7e+dBXKI7m+s+XCD/50p2InDvb3LcgilFk6UO0y3St6GqDSR0d9NwFVVg==", + "dependencies": { + "protobufjs": "^7.1.2" + } + }, + "node_modules/tf2-backpack/node_modules/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, + "node_modules/tf2-backpack/node_modules/protobufjs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", + "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -19127,6 +19164,40 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "tf2-backpack": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tf2-backpack/-/tf2-backpack-1.1.5.tgz", + "integrity": "sha512-iuBb1yP8uvpIk+ate8TEkmePg6hGs7e+dBXKI7m+s+XCD/50p2InDvb3LcgilFk6UO0y3St6GqDSR0d9NwFVVg==", + "requires": { + "protobufjs": "^7.1.2" + }, + "dependencies": { + "long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, + "protobufjs": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", + "integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + } + } + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/package.json b/package.json index 1c69ae2f4..937247fe6 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "steam-totp": "^2.1.2", "steam-user": "^4.26.1", "steamid": "^2.0.0", + "tf2-backpack": "^1.1.5", "url": "^0.11.0", "valid-url": "^1.0.9", "winston": "^3.8.2", diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index fd94b0b9b..f70dc12dd 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -16,6 +16,7 @@ import pluralize from 'pluralize'; import * as timersPromises from 'timers/promises'; import fs from 'fs'; import path from 'path'; +import { BackpackParser, NodeTF2Backpack } from 'tf2-backpack'; import DiscordBot from './DiscordBot'; import { Message as DiscordMessage } from 'discord.js'; @@ -74,6 +75,8 @@ export default class Bot { readonly inventoryGetter: InventoryGetter; + private backpackParser: BackpackParser; + readonly boundInventoryGetter: ( steamID: SteamID | string, appid: number, @@ -867,11 +870,16 @@ export default class Bot { fs.mkdirSync(path.join(__dirname, `../../files/test`)); } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + this.backpackParser = new BackpackParser(this.tf2.itemSchema); + fs.writeFile( path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - JSON.stringify(this.tf2.backpack), + JSON.stringify(this.backpackParser.parseBackpack(this.tf2.backpack as NodeTF2Backpack, false)), { encoding: 'utf-8' }, err => { if (err) { From 3ae0564e71573678d5d04638f3bbc42b92aa1187 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 01:40:35 +0800 Subject: [PATCH 05/17] =?UTF-8?q?=F0=9F=94=84=EF=B8=8F=20temp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 63 +++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index f70dc12dd..d9bc6e093 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -77,6 +77,8 @@ export default class Bot { private backpackParser: BackpackParser; + private needSave = false; + readonly boundInventoryGetter: ( steamID: SteamID | string, appid: number, @@ -830,6 +832,33 @@ export default class Bot { }); } + saveBackpack(): void { + if (!fs.existsSync(path.join(__dirname, `../../files/test`))) { + fs.mkdirSync(path.join(__dirname, `../../files/test`)); + } + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + this.backpackParser = new BackpackParser(this.tf2.itemSchema); + + fs.writeFile( + path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + JSON.stringify(this.backpackParser.parseBackpack(this.tf2.backpack as NodeTF2Backpack, false)), + { encoding: 'utf-8' }, + err => { + if (err) { + log.error('save backpack error', err); + return; + } + + log.debug('backpackLoaded event emitted.'); + } + ); + } + start(): Promise { let data: { loginAttempts?: number[]; @@ -866,30 +895,24 @@ export default class Bot { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.tf2.on('backpackLoaded', () => { - if (!fs.existsSync(path.join(__dirname, `../../files/test`))) { - fs.mkdirSync(path.join(__dirname, `../../files/test`)); - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - this.backpackParser = new BackpackParser(this.tf2.itemSchema); - - fs.writeFile( - path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - JSON.stringify(this.backpackParser.parseBackpack(this.tf2.backpack as NodeTF2Backpack, false)), - { encoding: 'utf-8' }, - err => { - if (err) { - log.error('save backpack error', err); - return; - } + if (!this.tf2.itemSchema) { + this.needSave = true; + return; + } - log.debug('backpackLoaded event emitted.'); - } - ); + this.saveBackpack(); + }); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.tf2.on('itemSchemaLoaded', () => { + if (this.needSave) { + this.saveBackpack(); + this.needSave = false; + } }); return new Promise((resolve, reject) => { From e99d846d54148f086fabfbbd8f371394216274f5 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 01:53:30 +0800 Subject: [PATCH 06/17] =?UTF-8?q?=F0=9F=94=8E=20itemSchemaLoaded=20never?= =?UTF-8?q?=20emitted,=20checking...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index d9bc6e093..8d76114c7 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -915,6 +915,12 @@ export default class Bot { } }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.tf2.on('itemSchemaError', err => { + log.error('Error on tf2 getting schema', err); + }); + return new Promise((resolve, reject) => { async.eachSeries( [ From 511bf04c329961c251d389aad88418ee0708c23e Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 01:57:12 +0800 Subject: [PATCH 07/17] =?UTF-8?q?=F0=9F=94=A8=20I=20see?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 8d76114c7..cb1de014a 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -906,6 +906,15 @@ export default class Bot { this.saveBackpack(); }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this.tf2.on('itemSchema', () => { + if (this.needSave) { + this.saveBackpack(); + this.needSave = false; + } + }); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.tf2.on('itemSchemaLoaded', () => { From 48e7fb728da771c7b4789f6b91c9b0e4f1242779 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 09:24:50 +0800 Subject: [PATCH 08/17] =?UTF-8?q?=F0=9F=94=A8=F0=9F=A7=AA=20use=20differen?= =?UTF-8?q?t=20approach?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 36 +++++++++++------------------------- src/classes/TF2GC.ts | 25 ++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 2508f4966..514e6896e 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -77,7 +77,7 @@ export default class Bot { private backpackParser: BackpackParser; - private needSave = false; + needSave = false; readonly boundInventoryGetter: ( steamID: SteamID | string, @@ -877,30 +877,6 @@ export default class Bot { this.saveBackpack(); }); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.tf2.on('itemSchema', () => { - if (this.needSave) { - this.saveBackpack(); - this.needSave = false; - } - }); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.tf2.on('itemSchemaLoaded', () => { - if (this.needSave) { - this.saveBackpack(); - this.needSave = false; - } - }); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.tf2.on('itemSchemaError', err => { - log.error('Error on tf2 getting schema', err); - }); - return new Promise((resolve, reject) => { async.eachSeries( [ @@ -1216,6 +1192,16 @@ export default class Bot { callback(err); }); }, + (callback: (err?) => void): void => { + log.debug('Wait for the TF2 Schema file to load...'); + this.tf2gc.waitForSchemaLoaded(err => { + if (err) { + return callback(err); + } + + callback(null); + }); + }, (callback): void => { this.community.getTradeURL((err, url) => { if (err) { diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 32e848900..7856facd2 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -36,7 +36,8 @@ type Job = { | 'delete' | 'sort' | 'removeAttributes' - | 'craftToken'; + | 'craftToken' + | 'schemaLoad'; defindex?: number; sku?: string; skus?: string[]; @@ -151,6 +152,10 @@ export default class TF2GC { this.newJob({ type: 'craftToken', assetids, tokenType, subTokenType, callback: callback }); } + waitForSchemaLoaded(callback: (err: Error | null) => void): void { + this.newJob({ type: 'schemaLoad', callback: callback }); + } + private newJob(job: Job): void { this.jobs.push(job); this.handleJobQueue(); @@ -203,6 +208,8 @@ export default class TF2GC { func = this.handleSortJob.bind(this, job); } else if (job.type === 'craftToken') { func = this.handleCraftTokenJob.bind(this, job); + } else if (job.type === 'schemaLoad') { + func = this.handleSchemaLoadJob(); } if (func) { @@ -527,6 +534,22 @@ export default class TF2GC { ); } + private handleSchemaLoadJob(): void { + this.listenForEvent( + 'schemaLoaded', + () => { + this.finishedProcessingJob(); + + if (this.bot.needSave) { + this.bot.saveBackpack(); + } + }, + err => { + this.finishedProcessingJob(err); + } + ); + } + /** * Listens for GC event * From b66abfb30bb7e59b567c110440dbe6944cacdc01 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 09:31:12 +0800 Subject: [PATCH 09/17] =?UTF-8?q?=F0=9F=94=A8=20fix=20"Unknown=20job=20typ?= =?UTF-8?q?e"=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/TF2GC.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 7856facd2..1ba370b08 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -209,7 +209,7 @@ export default class TF2GC { } else if (job.type === 'craftToken') { func = this.handleCraftTokenJob.bind(this, job); } else if (job.type === 'schemaLoad') { - func = this.handleSchemaLoadJob(); + func = this.handleSchemaLoadJob.bind(this, job); } if (func) { From 8c5157e40cd385d6d444a7c122812ad6ee9f91ce Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:01:00 +0800 Subject: [PATCH 10/17] =?UTF-8?q?=F0=9F=9A=AE=20lel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 20 +------------------- src/classes/TF2GC.ts | 25 +------------------------ 2 files changed, 2 insertions(+), 43 deletions(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 514e6896e..acdced3d3 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -811,7 +811,7 @@ export default class Bot { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - this.backpackParser = new BackpackParser(this.tf2.itemSchema); + this.backpackParser = new BackpackParser(this.schema.raw.items_game); fs.writeFile( path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), @@ -866,14 +866,6 @@ export default class Bot { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.tf2.on('backpackLoaded', () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - if (!this.tf2.itemSchema) { - this.needSave = true; - return; - } - this.saveBackpack(); }); @@ -1192,16 +1184,6 @@ export default class Bot { callback(err); }); }, - (callback: (err?) => void): void => { - log.debug('Wait for the TF2 Schema file to load...'); - this.tf2gc.waitForSchemaLoaded(err => { - if (err) { - return callback(err); - } - - callback(null); - }); - }, (callback): void => { this.community.getTradeURL((err, url) => { if (err) { diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 1ba370b08..32e848900 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -36,8 +36,7 @@ type Job = { | 'delete' | 'sort' | 'removeAttributes' - | 'craftToken' - | 'schemaLoad'; + | 'craftToken'; defindex?: number; sku?: string; skus?: string[]; @@ -152,10 +151,6 @@ export default class TF2GC { this.newJob({ type: 'craftToken', assetids, tokenType, subTokenType, callback: callback }); } - waitForSchemaLoaded(callback: (err: Error | null) => void): void { - this.newJob({ type: 'schemaLoad', callback: callback }); - } - private newJob(job: Job): void { this.jobs.push(job); this.handleJobQueue(); @@ -208,8 +203,6 @@ export default class TF2GC { func = this.handleSortJob.bind(this, job); } else if (job.type === 'craftToken') { func = this.handleCraftTokenJob.bind(this, job); - } else if (job.type === 'schemaLoad') { - func = this.handleSchemaLoadJob.bind(this, job); } if (func) { @@ -534,22 +527,6 @@ export default class TF2GC { ); } - private handleSchemaLoadJob(): void { - this.listenForEvent( - 'schemaLoaded', - () => { - this.finishedProcessingJob(); - - if (this.bot.needSave) { - this.bot.saveBackpack(); - } - }, - err => { - this.finishedProcessingJob(err); - } - ); - } - /** * Listens for GC event * From 78a233297a264297fd2d3f2e54fca0886fd39ff9 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 10:01:56 +0800 Subject: [PATCH 11/17] =?UTF-8?q?=F0=9F=94=84=EF=B8=8F=20change=20log=20po?= =?UTF-8?q?sition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index acdced3d3..2f369dc18 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -824,8 +824,6 @@ export default class Bot { log.error('save backpack error', err); return; } - - log.debug('backpackLoaded event emitted.'); } ); } @@ -866,6 +864,7 @@ export default class Bot { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.tf2.on('backpackLoaded', () => { + log.debug('backpackLoaded event emitted.'); this.saveBackpack(); }); From 3833b29fc4c2ae36bd9eb240175707e00baf84ff Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 19:17:07 +0800 Subject: [PATCH 12/17] =?UTF-8?q?=F0=9F=A7=AA=20waitForBackpackLoaded?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/TF2GC.ts | 28 ++++++++++++++- src/classes/Trades.ts | 84 +++++++++++++++++++------------------------ 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 32e848900..9c28ca07b 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -36,7 +36,8 @@ type Job = { | 'delete' | 'sort' | 'removeAttributes' - | 'craftToken'; + | 'craftToken' + | 'backpackLoad'; defindex?: number; sku?: string; skus?: string[]; @@ -151,6 +152,12 @@ export default class TF2GC { this.newJob({ type: 'craftToken', assetids, tokenType, subTokenType, callback: callback }); } + waitForBackpackLoaded(callback: (err: Error | null) => void): void { + log.debug(`Enqueueing backpackLoaded trigger job`); + + this.newJob({ type: 'backpackLoad', callback: callback }); + } + private newJob(job: Job): void { this.jobs.push(job); this.handleJobQueue(); @@ -203,6 +210,8 @@ export default class TF2GC { func = this.handleSortJob.bind(this, job); } else if (job.type === 'craftToken') { func = this.handleCraftTokenJob.bind(this, job); + } else if (job.type === 'backpackLoad') { + func = this.handleBackpackLoadedJob.bind(this, job); } if (func) { @@ -527,6 +536,21 @@ export default class TF2GC { ); } + private handleBackpackLoadedJob(): void { + this.bot.client.gamesPlayed([]); + this.bot.client.gamesPlayed(440); + + this.listenForEvent( + 'backpackLoaded', + () => { + this.finishedProcessingJob(); + }, + err => { + this.finishedProcessingJob(err); + } + ); + } + /** * Listens for GC event * @@ -628,6 +652,8 @@ export default class TF2GC { if (job !== undefined && job.callback) { job.callback(err); + } else { + job.callback(null); } this.processingQueue = false; diff --git a/src/classes/Trades.ts b/src/classes/Trades.ts index 1f2c76824..ee297c017 100644 --- a/src/classes/Trades.ts +++ b/src/classes/Trades.ts @@ -46,9 +46,9 @@ export default class Trades { private resetRetryAcceptOfferTimeout: NodeJS.Timeout; - private retryFetchInventoryTimeout: NodeJS.Timeout; + private retryRefreshInventoryTimeout: NodeJS.Timeout; - private calledRetryFetchFreq = 0; + private calledRetryRefreshFreq = 0; private offerChangedAcc: { offer: TradeOffer; oldState: number; timeTakenToComplete: number }[] = []; @@ -1673,42 +1673,33 @@ export default class Trades { // Just handle changes this.bot.handler.onTradeOfferChanged(offer, oldState, timeTakenToComplete); } else { - // Exit all running apps ("TF2Autobot" or custom, and Team Fortress 2) - // Will play again after craft/smelt/sort inventory job - // https://github.com/TF2Autobot/tf2autobot/issues/527 - this.bot.client.gamesPlayed([]); - this.offerChangedAcc.push({ offer, oldState, timeTakenToComplete }); log.debug('Accumulated offerChanged: ', this.offerChangedAcc.length); if (this.offerChangedAcc.length <= 1) { - // Only call `fetch` if accumulated offerChanged is less than or equal to 1 - // Prevent never ending "The request is a duplicate and the action has already occurred in the past, ignored this time" - - // Accepted, Invalid trade (possible) => new item assetid - log.debug('Fetching our inventory...'); - return void this.bot.inventoryManager.getInventory - .fetch() - .then(() => { - this.onSuccessfulFetch(); - }) - .catch(err => { - log.warn('Error fetching inventory: ', err); - log.debug('Retrying to fetch inventory in 30 seconds...'); - this.calledRetryFetchFreq++; - - if (this.calledRetryFetchFreq === 1) { + log.debug('Refreshing our inventory...'); + return void this.bot.tf2gc.waitForBackpackLoaded(err => { + if (err) { + log.warn('Error running "waitForBackpackLoaded": ', err); + log.debug('Retrying to in 30 seconds...'); + this.calledRetryRefreshFreq++; + + if (this.calledRetryRefreshFreq === 1) { // Only call this once (before reset) - this.retryFetchInventory(); + this.retryRefreshInventory(); } - }); + return; + } + + this.onSuccessfulRefresh(); + }); } - log.debug('Not fetching inventory this time...'); + log.debug('Not refreshing inventory this time...'); } } - private onSuccessfulFetch(): void { + private onSuccessfulRefresh(): void { if (this.offerChangedAcc.length > 0) { this.offerChangedAcc.forEach(el => { this.bot.handler.onTradeOfferChanged(el.offer, el.oldState, el.timeTakenToComplete); @@ -1719,34 +1710,33 @@ export default class Trades { } } - private retryFetchInventory(): void { - clearTimeout(this.retryFetchInventoryTimeout); - this.retryFetchInventoryTimeout = setTimeout(() => { - this.bot.inventoryManager.getInventory - .fetch() - .then(() => { - this.onSuccessfulFetch(); - - // Reset to 0 - this.calledRetryFetchFreq = 0; - }) - .catch(err => { - log.warn('Error fetching inventory: ', err); + private retryRefreshInventory(): void { + clearTimeout(this.retryRefreshInventoryTimeout); + this.retryRefreshInventoryTimeout = setTimeout(() => { + this.bot.tf2gc.waitForBackpackLoaded(err => { + if (err) { + log.warn('Error refreshing inventory: ', err); - if (this.calledRetryFetchFreq > 3) { + if (this.calledRetryRefreshFreq > 3) { // If more than 3 times failed, then just proceed with an outdated inventory - this.onSuccessfulFetch(); + this.onSuccessfulRefresh(); // Reset to 0 - this.calledRetryFetchFreq = 0; + this.calledRetryRefreshFreq = 0; return; } - log.debug('Retrying to fetch inventory in 30 seconds...'); - this.calledRetryFetchFreq++; - this.retryFetchInventory(); - }); + log.debug('Retrying to refresh inventory in 30 seconds...'); + this.calledRetryRefreshFreq++; + return this.retryRefreshInventory(); + } + + this.onSuccessfulRefresh(); + + // Reset to 0 + this.calledRetryRefreshFreq = 0; + }); }, 30 * 1000); } From 952792402f7ce79af25da3fa64d9b7722688ca12 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 19:23:54 +0800 Subject: [PATCH 13/17] =?UTF-8?q?=F0=9F=94=A8=20fix=20job.callback=20is=20?= =?UTF-8?q?not=20a=20function?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/TF2GC.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 9c28ca07b..5b5dc62fe 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -652,7 +652,7 @@ export default class TF2GC { if (job !== undefined && job.callback) { job.callback(err); - } else { + } else if (job.callback) { job.callback(null); } From 5af62c9e7dc95b33553d618da0198dbb7829395a Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 19:28:26 +0800 Subject: [PATCH 14/17] =?UTF-8?q?=F0=9F=94=A8=20not=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/TF2GC.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/classes/TF2GC.ts b/src/classes/TF2GC.ts index 5b5dc62fe..70e646363 100644 --- a/src/classes/TF2GC.ts +++ b/src/classes/TF2GC.ts @@ -652,8 +652,6 @@ export default class TF2GC { if (job !== undefined && job.callback) { job.callback(err); - } else if (job.callback) { - job.callback(null); } this.processingQueue = false; From c446d5757ed46f0a2a50eb5cab916a78d9ecbc1d Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 22:49:03 +0800 Subject: [PATCH 15/17] =?UTF-8?q?=F0=9F=94=A8=20remove=20save=20backpack,?= =?UTF-8?q?=20refactor=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Bot.ts | 59 +++++++++------------------------------ src/classes/BotManager.ts | 1 - 2 files changed, 13 insertions(+), 47 deletions(-) diff --git a/src/classes/Bot.ts b/src/classes/Bot.ts index 2f369dc18..84d00e7da 100644 --- a/src/classes/Bot.ts +++ b/src/classes/Bot.ts @@ -16,7 +16,7 @@ import pluralize from 'pluralize'; import * as timersPromises from 'timers/promises'; import fs from 'fs'; import path from 'path'; -import { BackpackParser, NodeTF2Backpack } from 'tf2-backpack'; +import { BackpackParser } from 'tf2-backpack'; import DiscordBot from './DiscordBot'; import { Message as DiscordMessage } from 'discord.js'; @@ -75,7 +75,7 @@ export default class Bot { readonly inventoryGetter: InventoryGetter; - private backpackParser: BackpackParser; + backpackParser: BackpackParser; needSave = false; @@ -115,8 +115,6 @@ export default class Bot { spy: string[]; }; - public updateSchemaPropertiesInterval: NodeJS.Timeout; - // Settings private readonly maxLoginAttemptsWithinPeriod: number = 3; @@ -803,31 +801,6 @@ export default class Bot { }); } - saveBackpack(): void { - if (!fs.existsSync(path.join(__dirname, `../../files/test`))) { - fs.mkdirSync(path.join(__dirname, `../../files/test`)); - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - this.backpackParser = new BackpackParser(this.schema.raw.items_game); - - fs.writeFile( - path.join(__dirname, `../../files/test/bp-${Math.floor(Date.now() / 1000)}.json`), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - JSON.stringify(this.backpackParser.parseBackpack(this.tf2.backpack as NodeTF2Backpack, false)), - { encoding: 'utf-8' }, - err => { - if (err) { - log.error('save backpack error', err); - return; - } - } - ); - } - start(): Promise { let data: { loginAttempts?: number[]; @@ -861,13 +834,6 @@ export default class Bot { this.addListener(this.tf2, 'displayNotification', this.handler.onDisplayNotification.bind(this.handler), true); this.addListener(this.tf2, 'itemBroadcast', this.handler.onItemBroadcast.bind(this.handler), true); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.tf2.on('backpackLoaded', () => { - log.debug('backpackLoaded event emitted.'); - this.saveBackpack(); - }); - return new Promise((resolve, reject) => { async.eachSeries( [ @@ -1013,6 +979,17 @@ export default class Bot { log.info('Getting TF2 schema...'); void this.initializeSchema().asCallback(callback); }, + (callback): void => { + log.info('Initializing Backpack parser...'); + this.setProperties(); + this.backpackParser = new BackpackParser(this.schema.raw.items_game); + this.schemaManager.on('schema', () => { + this.backpackParser = new BackpackParser(this.schema.raw.items_game); + this.setProperties(); + }); + /* eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call */ + return callback(null); + }, (callback: (err?) => void): void => { log.info('Initializing pricelist...'); @@ -1032,7 +1009,6 @@ export default class Bot { }, (callback): void => { log.info('Initializing inventory, bptf-listings, and profile settings'); - this.setProperties(); async.parallel( [ (callback): void => { @@ -1249,15 +1225,6 @@ export default class Bot { sniper: this.schema.getWeaponsForCraftingByClass('Sniper'), spy: this.schema.getWeaponsForCraftingByClass('Spy') }; - - clearInterval(this.updateSchemaPropertiesInterval); - this.refreshSchemaProperties(); - } - - private refreshSchemaProperties(): void { - this.updateSchemaPropertiesInterval = setInterval(() => { - this.setProperties(); - }, 24 * 60 * 60 * 1000); } setCookies(cookies: string[]): Promise { diff --git a/src/classes/BotManager.ts b/src/classes/BotManager.ts index a9ee56ead..3be4a72e7 100644 --- a/src/classes/BotManager.ts +++ b/src/classes/BotManager.ts @@ -204,7 +204,6 @@ export default class BotManager { // Stop updating schema clearTimeout(this.schemaManager?._updateTimeout); clearInterval(this.schemaManager?._updateInterval); - clearInterval(this.bot.updateSchemaPropertiesInterval); // Stop heartbeat and inventory timers clearInterval(this.bot.listingManager?._heartbeatInterval); From 436eebdbff2c454976943900fc4a053203ac56f4 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Wed, 4 Jan 2023 22:49:52 +0800 Subject: [PATCH 16/17] =?UTF-8?q?=F0=9F=93=8B=20add=20TODO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Inventory.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/classes/Inventory.ts b/src/classes/Inventory.ts index 2d486dae0..22d477935 100644 --- a/src/classes/Inventory.ts +++ b/src/classes/Inventory.ts @@ -155,6 +155,8 @@ export default class Inventory { ); } + // TODO: Process internal inventory + findByAssetid(assetid: string): string | null { for (const sku in this.tradable) { if (!Object.prototype.hasOwnProperty.call(this.tradable, sku)) { From a8c5d63fcec31be07423d96fe64a8501d5656508 Mon Sep 17 00:00:00 2001 From: IdiNium <47635037+idinium96@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:22:06 +0800 Subject: [PATCH 17/17] =?UTF-8?q?=E2=9C=A8=20add=20new=20static=20methods?= =?UTF-8?q?=20(WIP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Inventory.ts | 76 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/src/classes/Inventory.ts b/src/classes/Inventory.ts index 3ceac309d..cdb8ba514 100644 --- a/src/classes/Inventory.ts +++ b/src/classes/Inventory.ts @@ -1,11 +1,12 @@ import SteamID from 'steamid'; import { EconItem, ItemAttributes, PartialSKUWithMention } from '@tf2autobot/tradeoffer-manager'; -import { Effect, Paints, StrangeParts } from '@tf2autobot/tf2-schema'; +import SchemaManager, { Item, Effect, Paints, StrangeParts } from '@tf2autobot/tf2-schema'; import SKU from '@tf2autobot/tf2-sku'; import { HighValue } from './Options'; import Bot from './Bot'; import { noiseMakers, spellsData, killstreakersData, sheensData } from '../lib/data'; import Pricelist from './Pricelist'; +import * as bp from 'tf2-backpack'; export default class Inventory { private readonly steamID: SteamID; @@ -70,7 +71,7 @@ export default class Inventory { ) => void ): Inventory { const inventory = new Inventory(steamID, bot, which, boundInventoryGetter); - inventory.setItems = items; + inventory.setItemsEcon({ items }); return inventory; } @@ -134,13 +135,13 @@ export default class Inventory { return reject(err); } - this.setItems = items; + this.setItemsEcon({ items }); resolve(); }); }); } - private set setItems(items: EconItem[]) { + private setItemsEcon({ items }: { items: EconItem[] }) { this.tradable = Inventory.createDictionary( items.filter(item => item.tradable), this.bot, @@ -597,6 +598,73 @@ export default class Inventory { return attributes; } + // For tf2-backpack + private static getSKU({ + item, + schema, + normalizeFestivizedItems, + normalizeStrangeAsSecondQuality, + normalizePainted, + normalizeCraftNumber, + paintsInOptions + }: { + item: bp.Item; + schema: SchemaManager.Schema; + normalizeFestivizedItems: boolean; + normalizeStrangeAsSecondQuality: boolean; + normalizePainted: boolean; + normalizeCraftNumber: boolean; + paintsInOptions: string[]; + }): { sku: string; isPainted: boolean } { + const paint = this.getPaint(schema, item, normalizePainted, paintsInOptions); + + const itemData: Item = { + defindex: item.defindex, + quality: item.quality, + craftable: item.craftable, + killstreak: item.killstreakTier || null, + australium: item.australium || null, + festive: !normalizeFestivizedItems ? item.festivized : false, + effect: item.effect || null, + wear: item.wear || null, + paintkit: item.paintkit || null, + quality2: !normalizeStrangeAsSecondQuality ? (item.elevated ? 11 : null) : null, + crateseries: item.crateNo || null, + target: item.target || null, + output: item.outputItem?.defindex, + outputQuality: item.outputItem?.quality, + paint: paint.decimalValue, + craftnumber: !normalizeCraftNumber ? item.craft : null + }; + + return { sku: SKU.fromObject(itemData), isPainted: paint.isPainted }; + } + + // For tf2-backpack + private static getPaint( + schema: SchemaManager.Schema, + item: bp.Item, + normalize: boolean, + inOptions: string[] + ): { decimalValue: number; isPainted: boolean } { + if (!item.paint) { + return null; + } + + if (!normalize) { + if (item.paint === 'B8383B' && item.paint_other !== '5885A2' && inOptions.includes('legacy paint')) { + // legacy paint for Team Spirit + return { decimalValue: 5801378, isPainted: true }; + } + + if (inOptions.includes(item.paint.toLowerCase())) { + return { decimalValue: schema.paints[bp.paints[item.paint]], isPainted: true }; + } + } + + return { decimalValue: null, isPainted: false }; + } + clearFetch(): void { this.tradable = undefined; this.nonTradable = undefined;