From 823f7fbaadf6143515626b3ea6eed51e9488937b Mon Sep 17 00:00:00 2001 From: ChetdeJong Date: Sat, 23 Mar 2024 22:23:43 +0400 Subject: [PATCH] added new output format in 2 function of parser script --- README.md | 8 ++++ package.json | 4 +- src/main.ts | 125 +++++++++++++++++++++++++++++++++++++------------- src/parser.ts | 91 +++++++++++++++++++++++++++++------- src/utils.ts | 29 +++++++++++- 5 files changed, 206 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index fba226d..8f0d6c6 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,14 @@ It will generate `.csv` file which is formatted with tabs. Means you can copy pa ## 2) Get frags for killfeed template +**Update: 23 march 2024** + +> Now there is new option to get killfeed exactly as each group provided. Might be useful e.g. if you want to treat group as one round. The input format is the same, it's just different type of output. + +It will prompt if you want to use groups as is or if you want the default behaviour. + +Default: + Provide starting index (optional). Provide demos data in following format. You can copy paste output from first function for ease of use. diff --git a/package.json b/package.json index 283d895..3911276 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cs2-killfeed-thing", - "version": "0.3.1", + "version": "0.4.0", "description": "Parse demos for frags and get formatted output for killfeed template", "scripts": { "start": "tsc & node ./dist/main.js", @@ -21,6 +21,6 @@ "zip-webpack-plugin": "^4.0.1" }, "dependencies": { - "@laihoe/demoparser2": "^0.21.0" + "@laihoe/demoparser2": "^0.22.5" } } diff --git a/src/main.ts b/src/main.ts index 81f2a55..f567c85 100644 --- a/src/main.ts +++ b/src/main.ts @@ -17,40 +17,101 @@ const askForDemos = async (): Promise => { let startingindex: number; return new Promise((resolve) => { + const opt = () => + rl.question('Use groups as is? y or n \nDefault is n\n\n', (answer) => { + if (answer === 'n' || answer === '') { + console.clear(); + n(); + return; + } + if (answer !== 'y' && answer !== 'n') { + console.log('Invalid answer: type y or n'); + opt(); + } + if (answer === 'y') { + console.clear(); + y(); + } + }); + console.clear(); - rl.question('Enter starting index:', (answer) => { - startingindex = parseInt(answer); - if (isNaN(Number(startingindex)) || startingindex <= 0) { - startingindex = 1; - } - console.log('Starting index:', startingindex); - console.log('Paste frags data line by line in following format:'); - console.log(''); - console.log('demoname steamid tick'); - console.log(''); - console.log('Note, there these are separated by tabs.'); - console.log('Separate groups by empty line.'); - console.log(''); - console.log('Example:'); - console.log( - 'faze-vs-g2-m1-inferno 76561197998926770 141134\nfaze-vs-g2-m1-inferno 76561197998926770 141282\nfaze-vs-g2-m1-inferno 76561197998926770 141373' - ); - console.log(''); - console.log( - 'faze-vs-g2-m2-ancient 76561198074762801 162312\nfaze-vs-g2-m2-ancient 76561198074762801 164096\nfaze-vs-g2-m2-ancient 76561198074762801 165597' - ); - console.log(''); - console.log('When done type "run" on new line and press enter'); - console.log(''); - }); + opt(); - rl.on('line', (line) => { - if (line === 'run') { - const res = getKillfeed(lines.join('\n'), startingindex); - res ? resolve(res) : resolve(''); - } - lines.push(line); - }); + const y = () => { + rl.question('Enter starting index:', (answer) => { + startingindex = parseInt(answer); + if (isNaN(Number(startingindex)) || startingindex <= 0) { + startingindex = 1; + } + console.log('Starting index:', startingindex); + console.log('Paste frags data line by line in following format:'); + console.log(''); + console.log('demoname steamid tick'); + console.log(''); + console.log('Note, there these are separated by tabs.'); + console.log('Separate groups by empty line.'); + console.log('When done type "run" on new line and press enter'); + console.log(''); + + console.log('Example:'); + console.log(''); + console.log( + 'spirit-vs-falcons-m1-anubis 76561198386265483 184277\nspirit-vs-falcons-m1-anubis 76561198995880877 184834\nspirit-vs-falcons-m1-anubis 76561199063238565 185508\nspirit-vs-falcons-m1-anubis 76561197989423065 186176\nspirit-vs-falcons-m1-anubis 76561197989423065 186208\nspirit-vs-falcons-m1-anubis 76561198386265483 186515' + ); + console.log(''); + console.log('Note: in this mode frags will be interpreted as is.'); + console.log( + 'It means killfeed data will be returned as exactly as frags data provided.' + ); + console.log(''); + }); + + rl.on('line', (line) => { + if (line === 'run') { + console.clear(); + const res = getKillfeed(lines.join('\n'), startingindex, true); + res ? resolve(res) : resolve(''); + } + lines.push(line); + }); + }; + + const n = () => { + rl.question('Enter starting index:', (answer) => { + startingindex = parseInt(answer); + if (isNaN(Number(startingindex)) || startingindex <= 0) { + startingindex = 1; + } + console.log('Starting index:', startingindex); + console.log('Paste frags data line by line in following format:'); + console.log(''); + console.log('demoname steamid tick'); + console.log(''); + console.log('Note, there these are separated by tabs.'); + console.log('Separate groups by empty line.'); + console.log(''); + console.log('Example:'); + console.log( + 'faze-vs-g2-m1-inferno 76561197998926770 141134\nfaze-vs-g2-m1-inferno 76561197998926770 141282\nfaze-vs-g2-m1-inferno 76561197998926770 141373' + ); + console.log(''); + console.log( + 'faze-vs-g2-m2-ancient 76561198074762801 162312\nfaze-vs-g2-m2-ancient 76561198074762801 164096\nfaze-vs-g2-m2-ancient 76561198074762801 165597' + ); + console.log(''); + console.log('When done type "run" on new line and press enter'); + console.log(''); + }); + + rl.on('line', (line) => { + if (line === 'run') { + console.clear(); + const res = getKillfeed(lines.join('\n'), startingindex); + res ? resolve(res) : resolve(''); + } + lines.push(line); + }); + }; }); }; diff --git a/src/parser.ts b/src/parser.ts index 46ae2c7..e227c9a 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,6 +1,6 @@ import { parseEvent, parsePlayerInfo } from '@laihoe/demoparser2'; import { player_death, playerinfo } from './types'; -import { getFrag } from './utils'; +import { formatKills, getFrag, isNotNull } from './utils'; import path from 'path'; import { rootdir } from './main'; @@ -21,9 +21,7 @@ export const getKills = (file: string) => { } catch (error) { if (error instanceof Error) { console.log('Parsing error:'); - console.log(error.name); console.log(error.message); - console.log(error.stack); } else { console.error(error); } @@ -56,17 +54,8 @@ export const getPlayers = (file: string) => { return formattedPlayers; }; -export const parseDemo = (input: string, startIndex: number = 1) => { - const demoname = input.split('\t')[0]; - const values = input.split('\t')[1].split(','); - const file = path.resolve(rootdir, 'demos', `${demoname}.dem`); - - const kills = getKills(file); - - if (!kills) { - console.log(`Kills were not parsed in demo ${demoname}`); - return []; - } +export const parseDemo = (input: string, kills: player_death[], startIndex: number = 1) => { + const values = input.split(','); const out: string[][][] = []; @@ -82,10 +71,43 @@ export const parseDemo = (input: string, startIndex: number = 1) => { return out.map((frag) => frag.map((line) => line.join('\t')).join('\n')); }; -export const getKillfeed = (input: string, startIndex: number = 1) => { +export const parseGroupAsIs = ( + group: string[], + kills: Map, + index: number +) => { + const groupKills = group + .map((line) => { + const demoname = line.split(',')[0]; + const steamId = line.split(',')[1]; + const tick = line.split(',')[2]; + const lineKills = kills.get(demoname) as player_death[]; + if (!lineKills) return null; + const filteredKills = lineKills + .filter((kill) => kill.attacker_steamid === steamId) + .filter((kill) => kill.tick >= parseInt(tick) - 5) + .slice(0, 1); + + if (filteredKills.length === 0) return null; + return filteredKills[0]; + }) + .filter(isNotNull); + + const formattedKills = formatKills(groupKills); + + return ( + ['GROUP', `${index.toString()}`, `${formattedKills.length}k`].join('\t') + + '\n' + + formattedKills.map((kill) => kill.join('\t')).join('\n') + ); +}; + +export const getKillfeed = (input: string, startIndex: number = 1, asIs?: boolean) => { try { const rows = input.split('\n'); + const demoNames = new Set(); + const demos: string[] = []; let frags: string[] = []; @@ -106,10 +128,41 @@ export const getKillfeed = (input: string, startIndex: number = 1) => { return; } frags.push([line[0], line[1], line[2]].join(',')); + demoNames.add(line[0]); }); groups.push(frags); + const demoKills = new Map(); + + demoNames.forEach((demoname) => { + const kills = getKills(path.resolve(rootdir, 'demos', `${demoname}.dem`)); + if (!kills) { + console.log(`Kills were not parsed in demo ${demoname}`); + return; + } + demoKills.set(demoname, kills); + }); + + if (asIs) { + const out = groups.map((group, index) => { + if (group.length === 0) return ''; + + const kills = new Map(); + + group.forEach((row) => { + const demoname = row.split(',')[0]; + if (!kills.has(demoname)) + kills.set(demoname, demoKills.get(demoname) as player_death[]); + }); + + const res = parseGroupAsIs(group, kills, index + startIndex); + return res; + }); + + return out.join('\n'); + } + groups.forEach((group) => { if (group.length === 0) return; @@ -135,7 +188,13 @@ export const getKillfeed = (input: string, startIndex: number = 1) => { const out = demos.map((demo, index) => { if (demo === '') return ''; - const res = parseDemo(demo, index + startIndex); + const demoname = demo.split('\t')[0]; + if (!demoKills.has(demoname)) return ''; + const input = demo.split('\t')[1]; + if (!input) return ''; + const kills = demoKills.get(demoname) as player_death[]; + if (!kills) return ''; + const res = parseDemo(input, kills, index + startIndex); if (res.length === 0) { startIndex--; return ''; diff --git a/src/utils.ts b/src/utils.ts index 224a319..c01cc5a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -148,6 +148,30 @@ export const mostCommonWeapon = (values: string[]) => { return mostCommonItem.toLowerCase(); }; +export const getOneFrag = (tick: number, steamId: string, kills: player_death[], index: number) => { + const filteredKills = kills + .filter((kill) => kill.attacker_steamid === steamId) + .filter((kill) => kill.tick >= tick) + .slice(0, 1); + + if (filteredKills.length === 0) return null; + const formattedKills = formatKills(filteredKills); + + const weapon = filteredKills.map((kill) => + kill.weapon.trim().replace(/\s/g, '').toLowerCase() + )[0]; + + formattedKills.unshift([ + 'GROUP', + `${index.toString()}`, + `${filteredKills[0].attacker_name}-${ + filteredKills.length + }k-${weapon}-vs-${filteredKills[0].user_team_clan_name.trim().replace(/\s/g, '')}` + ]); + + return formattedKills; +}; + export const getFrag = (values: string, kills: player_death[], index: number) => { const inputArray = values.split('-'); const providedtick = parseInt(inputArray[0]); @@ -192,7 +216,6 @@ export const saveToCSV = (data: string) => { console.clear(); console.error('An error occurred:', err); } else { - console.clear(); console.log(`Saved to ${current_date}.csv`); } }); @@ -286,3 +309,7 @@ export const getFormattedKills = ( return frags.map((frag) => frag.join('\t')).join('\n'); }; + +export function isNotNull(value: T | null): value is T { + return value !== null; +}