diff --git a/.gitignore b/.gitignore index 90739b78..1295422b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,4 @@ node_modules yarn-error.log static/ package-lock.json -config.ini -gameOverlay/ \ No newline at end of file +config.ini \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 672e7a96..92042178 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [1.4.0](https://github.com/KotRikD/tosu/compare/v1.3.4...v1.4.0) (2023-12-16) + + +### Features + +* gosumemory gameOverlay implementation ([1b1b987](https://github.com/KotRikD/tosu/commit/1b1b987dc523db9160423c8b39b0fbb6b92f34f9)) + ### [1.3.4](https://github.com/KotRikD/tosu/compare/v1.3.3...v1.3.4) (2023-12-15) diff --git a/package.json b/package.json index 831a8369..204a6541 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "Mikhail Babynichev", "license": "GPL-3.0", - "version": "1.3.4", + "version": "1.4.0", "scripts": { "prepare": "husky install", "start": "pnpm run -C packages/tosu run:dev", diff --git a/packages/gameOverlay/README.md b/packages/gameOverlay/README.md new file mode 100644 index 00000000..2c6a9495 --- /dev/null +++ b/packages/gameOverlay/README.md @@ -0,0 +1,3 @@ +@tosu/game-overlay +--- +A temp project to allow users use gosu memory game Overlay, probably in future will be replaced with own interpretation of this thing. I just wouldn't make it, due I agree with BlackShark's position about this (that it can give rise to a certain set of people who will use it for the evil of the game (cheats, etc.)) for the same reason, he doesn't even want to tell me how he compiled original `gameOverlay` project. Yes, this file that your `gosumemory` downloads at first launch! \ No newline at end of file diff --git a/packages/gameOverlay/package.json b/packages/gameOverlay/package.json new file mode 100644 index 00000000..706f9421 --- /dev/null +++ b/packages/gameOverlay/package.json @@ -0,0 +1,15 @@ +{ + "name": "game-overlay", + "private": "true", + "version": "0.0.1", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "prepare": "npm run build", + "build": "tsc" + }, + "dependencies": { + "decompress": "^4.2.1", + "tsprocess": "workspace:*" + } +} \ No newline at end of file diff --git a/packages/gameOverlay/src/features/downloader/index.ts b/packages/gameOverlay/src/features/downloader/index.ts new file mode 100644 index 00000000..99cbcabe --- /dev/null +++ b/packages/gameOverlay/src/features/downloader/index.ts @@ -0,0 +1,63 @@ +import fs from 'fs'; +import https from 'https'; + +const progressBarWidth = 40; + +const updateProgressBar = (progress: number): void => { + const filledWidth = Math.round(progressBarWidth * progress); + const emptyWidth = progressBarWidth - filledWidth; + const progressBar = '█'.repeat(filledWidth) + '░'.repeat(emptyWidth); + process.stdout.write( + `Progress: [${progressBar}] ${(progress * 100).toFixed(2)}%\r` + ); +}; + +/** + * A cyperdark's downloadFile implmentation based on pure node api + * @param url {string} + * @param destination {string} + * @returns {Promise} + */ +export const downloadFile = ( + url: string, + destination: string +): Promise => + new Promise((resolve, reject) => { + const options = { + headers: { + Accept: 'application/octet-stream', + 'User-Agent': '@KotRikD/tosu' + } + }; + + const file = fs.createWriteStream(destination); + + file.on('error', (err) => { + fs.unlinkSync(destination); + reject(err); + }); + + file.on('finish', () => { + file.close(); + resolve(destination); + }); + + // find url + https + .get(url, options, (response) => { + const totalSize = parseInt( + response.headers['content-length']!, + 10 + ); + let downloadedSize = 0; + + response.on('data', (data) => { + downloadedSize += data.length; + const progress = downloadedSize / totalSize; + updateProgressBar(progress); + }); + + response.pipe(file); + }) + .on('error', reject); + }); diff --git a/packages/gameOverlay/src/index.ts b/packages/gameOverlay/src/index.ts new file mode 100644 index 00000000..70c53bda --- /dev/null +++ b/packages/gameOverlay/src/index.ts @@ -0,0 +1,82 @@ +import decompress from 'decompress'; +import { execFile } from 'node:child_process'; +import { existsSync, writeFileSync } from 'node:fs'; +import { mkdir, rm } from 'node:fs/promises'; +import path from 'node:path'; +import { Process } from 'tsprocess/dist/process'; + +import { downloadFile } from './features/downloader'; + +const checkGameOverlayConfig = () => { + const configPath = path.join(process.cwd(), 'config.ini'); + if (!existsSync(configPath)) { + writeFileSync( + configPath, + `[GameOverlay]; https://github.com/l3lackShark/gosumemory/wiki/GameOverlay +enabled = false +gameWidth = 1920 +gameHeight = 1080 +overlayURL = http://127.0.0.1:24050/InGame2/index.html +overlayWidth = 380 +overlayHeight = 110 +overlayOffsetX = 0 +overlayOffsetY = 0 +overlayScale = 10` + ); + } +}; + +export const injectGameOverlay = async (p: Process) => { + if (process.platform !== 'win32') { + throw new Error( + 'Gameoverlay can run only under windows, sorry linux/darwin user!' + ); + } + + // Check for DEPRECATED GOSU CONFIG, due its needed to read [GameOverlay] section from original configuration + checkGameOverlayConfig(); + + if (!existsSync(path.join(process.cwd(), 'gameOverlay'))) { + const gameOverlayPath = path.join(process.cwd(), 'gameOverlay'); + const archivePath = path.join(gameOverlayPath, 'gosu-gameoverlay.zip'); + + await mkdir(gameOverlayPath); + await downloadFile( + 'https://dl.kotworks.cyou/gosu-gameoverlay.zip', + archivePath + ); + await decompress(archivePath, gameOverlayPath); + await rm(archivePath); + } + + if ( + !existsSync( + path.join(process.cwd(), 'gameOverlay', 'gosumemoryoverlay.dll') + ) + ) { + console.log('Please delete gameOverlay folder, and restart program!'); + process.exit(1); + } + + return await new Promise((resolve, reject) => { + const child = execFile( + path.join(process.cwd(), 'gameOverlay', 'a.exe'), + [ + p.id.toString(), + path.join(process.cwd(), 'gameOverlay', 'gosumemoryoverlay.dll') + ], + { + windowsHide: true + } + ); + child.on('error', (err) => { + reject(err); + }); + child.on('exit', () => { + console.log( + '[gosu-overlay] initialized successfully, see https://github.com/l3lackShark/gosumemory/wiki/GameOverlay for tutorial' + ); + resolve(true); + }); + }); +}; diff --git a/packages/gameOverlay/tsconfig.json b/packages/gameOverlay/tsconfig.json new file mode 100644 index 00000000..54f830fc --- /dev/null +++ b/packages/gameOverlay/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "lib": ["ES2020"], + "module": "commonjs", + "moduleResolution": "Node", + "allowJs": true, + "esModuleInterop": true, + "outDir": "dist", + "rootDir": "src", + "sourceMap": false, + "declaration": false, + "strict": true, + "noImplicitAny": false, + "target": "ES2020", + "strictPropertyInitialization": false, + "baseUrl": ".", + }, + "exclude": ["node_modules"], + "include": ["src"] +} diff --git a/packages/tosu/package.json b/packages/tosu/package.json index 9bc12b78..d4451d92 100644 --- a/packages/tosu/package.json +++ b/packages/tosu/package.json @@ -27,6 +27,7 @@ "@vercel/ncc": "^0.36.1", "dotenv": "^16.0.3", "find-process": "^1.4.7", + "game-overlay": "workspace:*", "koa": "^2.14.1", "koa-mount": "^4.0.0", "koa-send": "^5.0.1", @@ -43,7 +44,6 @@ "rosu-pp": "^0.9.4", "ts-node": "^10.9.1", "tsprocess": "workspace:*", - "winston": "^3.8.2", - "@tosu/game-overlay": "workspace:*" + "winston": "^3.8.2" } } \ No newline at end of file diff --git a/packages/tosu/src/objects/instanceManager/osuInstance.ts b/packages/tosu/src/objects/instanceManager/osuInstance.ts index f6d89249..20abc596 100644 --- a/packages/tosu/src/objects/instanceManager/osuInstance.ts +++ b/packages/tosu/src/objects/instanceManager/osuInstance.ts @@ -1,6 +1,6 @@ -import { injectGameOverlay } from '@tosu/game-overlay'; import EventEmitter from 'events'; import fs from 'fs'; +import { injectGameOverlay } from 'game-overlay'; import path from 'path'; import { Process } from 'tsprocess/dist/process'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 774cdf21..ec688446 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@types/node': specifier: ^18.14.6 - version: 18.18.11 + version: 18.19.3 tsconfig-paths: specifier: ^3.14.2 - version: 3.14.2 + version: 3.15.0 typescript: specifier: ^4.9.5 version: 4.9.5 @@ -45,9 +45,6 @@ importers: '@koa/router': specifier: ^12.0.0 version: 12.0.1 - '@tosu/game-overlay': - specifier: workspace:* - version: link:../gameOverlay '@types/koa': specifier: ^2.13.5 version: 2.13.12 @@ -63,6 +60,9 @@ importers: find-process: specifier: ^1.4.7 version: 1.4.7 + game-overlay: + specifier: workspace:* + version: link:../gameOverlay koa: specifier: ^2.14.1 version: 2.14.2 @@ -107,7 +107,7 @@ importers: version: 0.9.4 ts-node: specifier: ^10.9.1 - version: 10.9.1(@types/node@18.18.11)(typescript@4.9.5) + version: 10.9.2(@types/node@18.19.3)(typescript@4.9.5) tsprocess: specifier: workspace:* version: link:../tsprocess @@ -126,8 +126,8 @@ importers: packages: - /@babel/code-frame@7.23.4: - resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} + /@babel/code-frame@7.23.5: + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.23.4 @@ -152,11 +152,11 @@ packages: jsesc: 2.5.2 dev: false - /@babel/generator@7.23.4: - resolution: {integrity: sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==} + /@babel/generator@7.23.6: + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.6 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 @@ -172,21 +172,21 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.22.15 - '@babel/types': 7.23.4 + '@babel/types': 7.23.6 dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.6 dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.4 + '@babel/types': 7.23.6 dev: true /@babel/helper-string-parser@7.23.4: @@ -214,8 +214,8 @@ packages: '@babel/types': 7.19.0 dev: false - /@babel/parser@7.23.4: - resolution: {integrity: sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==} + /@babel/parser@7.23.6: + resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} engines: {node: '>=6.0.0'} hasBin: true dependencies: @@ -226,23 +226,23 @@ packages: resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.4 - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 dev: true /@babel/traverse@7.23.2: resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.4 - '@babel/generator': 7.23.4 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.4 - '@babel/types': 7.23.4 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -266,8 +266,8 @@ packages: to-fast-properties: 2.0.0 dev: false - /@babel/types@7.23.4: - resolution: {integrity: sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==} + /@babel/types@7.23.6: + resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.23.4 @@ -397,7 +397,7 @@ packages: optional: true dependencies: '@babel/generator': 7.17.7 - '@babel/parser': 7.23.4 + '@babel/parser': 7.23.6 '@babel/traverse': 7.23.2 '@babel/types': 7.17.0 javascript-natural-sort: 0.7.1 @@ -426,20 +426,20 @@ packages: /@types/accepts@1.3.7: resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} dependencies: - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/body-parser@1.19.5: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.38 - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/content-disposition@0.5.8: @@ -452,13 +452,13 @@ packages: '@types/connect': 3.4.38 '@types/express': 4.17.21 '@types/keygrip': 1.0.6 - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/express-serve-static-core@4.17.41: resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} dependencies: - '@types/node': 18.18.11 + '@types/node': 18.19.3 '@types/qs': 6.9.10 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -505,7 +505,7 @@ packages: '@types/http-errors': 2.0.4 '@types/keygrip': 1.0.6 '@types/koa-compose': 3.2.8 - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/koa__router@12.0.4: @@ -522,8 +522,8 @@ packages: resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} dev: false - /@types/node@18.18.11: - resolution: {integrity: sha512-c1vku6qnTeujJneYH94/4aq73XrVcsJe35UPyAsSok1ijiKrkRzK+AxQPSpNMUnC03roWBBwJx/9I8V7lQoxmA==} + /@types/node@18.19.3: + resolution: {integrity: sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==} dependencies: undici-types: 5.26.5 dev: false @@ -540,7 +540,7 @@ packages: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/serve-static@1.15.5: @@ -548,7 +548,7 @@ packages: dependencies: '@types/http-errors': 2.0.4 '@types/mime': 3.0.4 - '@types/node': 18.18.11 + '@types/node': 18.19.3 dev: false /@types/triple-beam@1.3.5: @@ -572,8 +572,8 @@ packages: negotiator: 0.6.3 dev: false - /acorn-walk@8.3.0: - resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + /acorn-walk@8.3.1: + resolution: {integrity: sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==} engines: {node: '>=0.4.0'} dev: false @@ -1706,7 +1706,7 @@ packages: co: 4.6.0 debug: 4.3.4 koa-compose: 4.1.0 - ws: 8.14.2 + ws: 8.15.1 transitivePeerDependencies: - bufferutil - supports-color @@ -2031,8 +2031,8 @@ packages: engines: {node: '>= 0.6'} dev: false - /node-abi@3.51.0: - resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==} + /node-abi@3.52.0: + resolution: {integrity: sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==} engines: {node: '>=10'} dependencies: semver: 7.5.4 @@ -2328,7 +2328,7 @@ packages: minimist: 1.2.8 mkdirp-classic: 0.5.3 napi-build-utils: 1.0.2 - node-abi: 3.51.0 + node-abi: 3.52.0 pump: 3.0.0 rc: 1.2.8 simple-get: 4.0.1 @@ -2799,8 +2799,8 @@ packages: engines: {node: '>= 14.0.0'} dev: false - /ts-node@10.9.1(@types/node@18.18.11)(typescript@4.9.5): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + /ts-node@10.9.2(@types/node@18.19.3)(typescript@4.9.5): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: '@swc/core': '>=1.2.50' @@ -2818,9 +2818,9 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.18.11 + '@types/node': 18.19.3 acorn: 8.11.2 - acorn-walk: 8.3.0 + acorn-walk: 8.3.1 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -2830,8 +2830,8 @@ packages: yn: 3.1.1 dev: false - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 json5: 1.0.2 @@ -2984,8 +2984,8 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false - /ws@8.14.2: - resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} + /ws@8.15.1: + resolution: {integrity: sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1