Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add linux support #173

Merged
merged 17 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 18 additions & 13 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
build:
strategy:
matrix:
os: [ windows-latest ]
os: [ windows-latest, ubuntu-latest ]

runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -56,29 +56,34 @@ jobs:
- name: 🛠️ - Install Deps
run: npm install -g pnpm@^8 && pnpm install --frozen-lockfile

- name: 📦 - Build
run: pnpm build
- name: 📦 - Build (windows)
if: ${{ matrix.os == 'windows-latest' }}
run: pnpm build:win

- name: 📦 - Build (linux)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: pnpm build:linux

- name: 🚀 - Upload artifacts for windows
if: matrix.os == 'windows-latest'
if: ${{ matrix.os == 'windows-latest' }}
uses: actions/upload-artifact@v4
with: {
name: "tosu-${{ matrix.os }}-${{ steps.set-pr-sha.outputs.SHORT_PR_SHA || github.ref_name }}",
name: "tosu-windows-${{ steps.set-pr-sha.outputs.SHORT_PR_SHA || github.ref_name }}",
path: packages/tosu/dist/tosu.exe
}

# - name: 🚀 - Upload artifacts for linux
# if: matrix.os == 'ubuntu-latest'
# uses: actions/upload-artifact@v3
# with: {
# name: "${{ steps.set-artifact-name.outputs.ARTIFACT_NAME }}",
# path: packages/tosu/dist/tosu.exe
# }
- name: 🚀 - Upload artifacts for linux
if: ${{ matrix.os == 'ubuntu-latest' }}
uses: actions/upload-artifact@v4
with: {
name: "tosu-linux-${{ steps.set-pr-sha.outputs.SHORT_PR_SHA || github.ref_name }}",
path: packages/tosu/dist/tosu
}

# - name: 🚀 - Upload artifacts for mac
# if: matrix.os == 'macos-latest'
# uses: actions/upload-artifact@v3
# with: {
# name: "${{ steps.set-artifact-name.outputs.ARTIFACT_NAME }}",
# path: packages/tosu/dist/tosu.exe
# }
# }
Empty file modified .husky/pre-commit
100644 → 100755
Empty file.
9 changes: 8 additions & 1 deletion development.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,15 @@ pnpm run start


6. Compile tosu

For Windows:
```
pnpm install && pnpm build:win
```

For Linux
```
pnpm install && pnpm build
pnpm install && pnpm build:linux
```

7. Go to `/tosu/packages/tosu/dist`, and there is your's tosu build
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"scripts": {
"prepare": "husky install",
"start": "pnpm run -C packages/tosu run:dev",
"build": "pnpm run -C packages/tosu compile",
"build:win": "pnpm run -C packages/tosu compile:win",
"build:linux": "pnpm run -C packages/tosu compile:linux",
"release": "standard-version",
"prettier:fix": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"",
"prettier:ci": "prettier --check \"**/*.{js,jsx,ts,tsx,css}\"",
Expand Down
3 changes: 2 additions & 1 deletion packages/tosu/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"ts:compile": "ncc build src/index.ts -o dist -m -d",
"run:dev": "pnpm run genver && pnpm run ts:run src/index.ts",
"compile:prepare-htmls": "cp -rf node_modules/@tosu/server/assets ./dist",
"compile": "pnpm run genver && pnpm run ts:compile && pnpm run compile:prepare-htmls && pkg --output dist/tosu.exe --debug --config pkg.json --compress brotli dist/index.js && pnpm run ts:run src/postBuild.ts"
"compile:win": "pnpm run genver && pnpm run ts:compile && pnpm run compile:prepare-htmls && pkg --output dist/tosu.exe --debug --config pkg.win.json --compress brotli dist/index.js && pnpm run ts:run src/postBuild.ts",
"compile:linux": "pnpm run genver && pnpm run ts:compile && pnpm run compile:prepare-htmls && pkg --output dist/tosu --debug --config pkg.linux.json --compress brotli dist/index.js"
},
"dependencies": {
"@tosu/common": "workspace:*",
Expand Down
4 changes: 2 additions & 2 deletions packages/tosu/pkg.json → packages/tosu/pkg.linux.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dist/assets/**/*"
],
"targets": [
"node20-win-x64"
"node20-linux-x64"
],
"outputPath": "dist"
}
}
14 changes: 14 additions & 0 deletions packages/tosu/pkg.win.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"scripts": "dist/**/*.js",
"assets": [
"dist/**/*.node",
"dist/**/*.wasm",
"dist/target/**/*",
"dist/_version.js",
"dist/assets/**/*"
],
"targets": [
"node20-win-x64"
],
"outputPath": "dist"
}
39 changes: 8 additions & 31 deletions packages/tosu/src/entities/AllTimesData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ import { wLogger } from '@tosu/common';

import { AbstractEntity } from '@/entities/AbstractEntity';

// NOTE: NOT AVAILABLE IN TOURNAMENT MODE!!!!
const GAME_TIME_PTR = {
pattern: '8B 35 ?? ?? ?? ?? 8B C6 B9',
offset: 0x2
};

export class AllTimesData extends AbstractEntity {
gameTimePtr: number = 0;

IsWatchingReplay: number = 0;
isReplayUiHidden: boolean = false;
ShowInterface: boolean = false;
Expand Down Expand Up @@ -49,30 +41,33 @@ export class AllTimesData extends AbstractEntity {
const {
statusPtr,
menuModsPtr,
chatCheckerAddr,
chatCheckerPtr,
skinDataAddr,
settingsClassAddr,
canRunSlowlyAddr,
rulesetsAddr
rulesetsAddr,
gameTimePtr
} = patterns.getPatterns([
'statusPtr',
'menuModsPtr',
'chatCheckerAddr',
'chatCheckerPtr',
'skinDataAddr',
'settingsClassAddr',
'canRunSlowlyAddr',
'rulesetsAddr'
'rulesetsAddr',
'gameTimePtr'
]);

// [Status - 0x4]
this.Status = process.readPointer(statusPtr);
// [MenuMods + 0x9]
this.MenuMods = process.readPointer(menuModsPtr);
// ChatChecker - 0x20
this.ChatStatus = process.readByte(chatCheckerAddr - 0x20);
this.ChatStatus = process.readByte(process.readInt(chatCheckerPtr));
this.IsWatchingReplay = process.readByte(
process.readInt(canRunSlowlyAddr + 0x46)
);
this.GameTime = process.readPointer(gameTimePtr);
this.MemorySongsFolder = process.readSharpString(
process.readInt(
process.readInt(
Expand Down Expand Up @@ -117,24 +112,6 @@ export class AllTimesData extends AbstractEntity {
return;
}

if (
!this.osuInstance.isTourneyManager &&
!this.osuInstance.isTourneySpectator
) {
if (this.gameTimePtr === 0) {
this.gameTimePtr = await process.scanAsync(
GAME_TIME_PTR.pattern,
true
);
wLogger.debug('ATD(updateState) gameTimePtr area found');
return;
} else {
this.GameTime = process.readPointer(
this.gameTimePtr + GAME_TIME_PTR.offset
);
}
}

this.resetReportCount('ATD(updateState)');
} catch (exc) {
this.reportError(
Expand Down
5 changes: 1 addition & 4 deletions packages/tosu/src/entities/TourneyManagerData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ export class TourneyManagerData extends AbstractEntity {

if (this.ChatAreaAddr === 0) {
await sleep(1000);
this.ChatAreaAddr = process.scanSync(
TOURNAMENT_CHAT_ENGINE,
true
);
this.ChatAreaAddr = process.scanSync(TOURNAMENT_CHAT_ENGINE);
wLogger.debug('TMD(updateState) Chat area found');
return;
}
Expand Down
69 changes: 31 additions & 38 deletions packages/tosu/src/objects/instanceManager/osuInstance.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { config, sleep, updateProgressBar, wLogger } from '@tosu/common';
import { config, sleep, wLogger } from '@tosu/common';
import { injectGameOverlay } from '@tosu/game-overlay';
import EventEmitter from 'events';
import fs from 'fs';
Expand Down Expand Up @@ -36,8 +36,9 @@ const SCAN_PATTERNS: {
playTimeAddr: {
pattern: '5E 5F 5D C3 A1 ?? ?? ?? ?? 89 ?? 04'
},
chatCheckerAddr: {
pattern: '0A D7 23 3C 00 00 ?? 01'
chatCheckerPtr: {
pattern: '83 3D ?? ?? ?? ?? 00 75 ?? 80 3D',
offset: 0x2
},
skinDataAddr: {
pattern: '74 2C 85 FF 75 28 A1 ?? ?? ?? ?? 8D 15'
Expand All @@ -64,7 +65,7 @@ const SCAN_PATTERNS: {
offset: -0x4
},
menuModsPtr: {
pattern: 'C8 FF 00 00 00 00 00 81 0D 00 00 00 00 00 08 00 00',
pattern: 'C8 FF ?? ?? ?? ?? ?? 81 0D ?? ?? ?? ?? ?? 08 00 00',
offset: 0x9
},
getAudioLengthPtr: {
Expand All @@ -82,6 +83,10 @@ const SCAN_PATTERNS: {
spectatingUserPtr: {
pattern: '8B 0D ?? ?? ?? ?? 85 C0 74 05 8B 50 30',
offset: -0x4
},
gameTimePtr: {
pattern: 'A1 ?? ?? ?? ?? 89 46 04 8B D6 E8',
offset: 0x1
}
};

Expand Down Expand Up @@ -143,7 +148,7 @@ export class OsuInstance {
}

async start() {
wLogger.info(`[${this.pid}] Running memory chimera..`);
wLogger.info(`[${this.pid}] Running memory chimera...`);
while (!this.isReady) {
const patternsRepo = this.entities.get('patterns');
if (!patternsRepo) {
Expand All @@ -153,38 +158,30 @@ export class OsuInstance {
}

try {
const total = Object.keys(SCAN_PATTERNS).length;
let completed = 0;
for (const baseKey in SCAN_PATTERNS) {
const s1 = performance.now();
const patternValue = this.process.scanSync(
SCAN_PATTERNS[baseKey].pattern,
true
);
completed += 1;
if (patternValue === 0) {
updateProgressBar(
`[${this.pid}] Scanning`,
completed / total,
`${(performance.now() - s1).toFixed(
2
)}ms ${baseKey}`
);
continue;
}
const s1 = performance.now();

patternsRepo.setPattern(
baseKey as never,
patternValue + (SCAN_PATTERNS[baseKey].offset || 0)
);
const results = this.process.scanBatch(
Object.values(SCAN_PATTERNS).map((x) => x.pattern)
);

const indexToKey = Object.keys(SCAN_PATTERNS);

for (let i = 0; i < results.length; i++) {
const baseKey = indexToKey[
results[i].index
] as keyof PatternData;

updateProgressBar(
`[${this.pid}] Scanning`,
completed / total,
`${(performance.now() - s1).toFixed(2)}ms ${baseKey}`
patternsRepo.setPattern(
baseKey,
results[i].address +
(SCAN_PATTERNS[baseKey].offset || 0)
);
}

wLogger.debug(
`[${this.pid}] Took ${(performance.now() - s1).toFixed(2)} ms to scan patterns`
);

if (!patternsRepo.checkIsBasesValid()) {
throw new Error('Memory resolve failed');
}
Expand Down Expand Up @@ -261,7 +258,7 @@ export class OsuInstance {
}

if (!allTimesData.GameFolder) {
allTimesData.setGameFolder(path.join(this.path, '..'));
allTimesData.setGameFolder(this.path);

// condition when user have different BeatmapDirectory in osu! config
if (fs.existsSync(allTimesData.MemorySongsFolder)) {
Expand All @@ -270,11 +267,7 @@ export class OsuInstance {
);
} else {
allTimesData.setSongsFolder(
path.join(
this.path,
'../',
allTimesData.MemorySongsFolder
)
path.join(this.path, allTimesData.MemorySongsFolder)
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/tosu/src/objects/memoryBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface BaseData {
baseAddr: number;
menuModsAddr: number;
playTimeAddr: number;
chatCheckerAddr: number;
chatCheckerPtr: number;
skinDataAddr: number;
configurationAddr: number;
bindingsAddr: number;
Expand All @@ -31,7 +31,7 @@ export class MemoryBase {
baseAddr: 0,
menuModsAddr: 0,
playTimeAddr: 0,
chatCheckerAddr: 0,
chatCheckerPtr: 0,
skinDataAddr: 0,
configurationAddr: 0,
bindingsAddr: 0,
Expand Down
8 changes: 5 additions & 3 deletions packages/tosu/src/objects/memoryPatterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { wLogger } from '@tosu/common';
export interface PatternData {
baseAddr: number;
playTimeAddr: number;
chatCheckerAddr: number;
chatCheckerPtr: number;
skinDataAddr: number;
settingsClassAddr: number;
configurationAddr: number;
Expand All @@ -16,6 +16,7 @@ export interface PatternData {
userProfilePtr: number;
rawLoginStatusPtr: number;
spectatingUserPtr: number;
gameTimePtr: number;
}

export class MemoryPatterns {
Expand All @@ -28,7 +29,7 @@ export class MemoryPatterns {
this.patterns = {
baseAddr: 0,
playTimeAddr: 0,
chatCheckerAddr: 0,
chatCheckerPtr: 0,
skinDataAddr: 0,
settingsClassAddr: 0,
configurationAddr: 0,
Expand All @@ -40,7 +41,8 @@ export class MemoryPatterns {
getAudioLengthPtr: 0,
userProfilePtr: 0,
rawLoginStatusPtr: 0,
spectatingUserPtr: 0
spectatingUserPtr: 0,
gameTimePtr: 0
};

if (process.platform !== 'win32') {
Expand Down
2 changes: 1 addition & 1 deletion packages/tsprocess/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
build/
disat/
dist/
Loading
Loading