From d6be694ddaa2c74b83e53b8915e78c266cb68c32 Mon Sep 17 00:00:00 2001 From: Cherry Date: Tue, 27 Feb 2024 20:50:23 +0300 Subject: [PATCH] add: add config reader --- .../tosu/src/entities/AllTimesData/index.ts | 197 ++++++++++++++++-- packages/tosu/src/entities/Settings/index.ts | 69 ++++++ .../objects/instanceManager/osuInstance.ts | 6 +- packages/tosu/src/objects/memoryBase.ts | 4 +- packages/tosu/src/objects/memoryPatterns.ts | 4 +- 5 files changed, 254 insertions(+), 26 deletions(-) diff --git a/packages/tosu/src/entities/AllTimesData/index.ts b/packages/tosu/src/entities/AllTimesData/index.ts index 65c625c9..4cc8b902 100644 --- a/packages/tosu/src/entities/AllTimesData/index.ts +++ b/packages/tosu/src/entities/AllTimesData/index.ts @@ -1,6 +1,14 @@ +import { Process } from 'tsprocess/dist/process'; + import { DataRepo } from '@/entities/DataRepoList'; import { AbstractEntity } from '../AbstractEntity'; +import { Settings } from '../Settings'; + +interface ConfigBindable { + type: 'bool' | 'byte' | 'int' | 'double' | 'string' | 'bstring' | 'enum'; + setValue: (settings: Settings, value: any) => void; +} export class AllTimesData extends AbstractEntity { Status: number = 0; @@ -13,10 +21,173 @@ export class AllTimesData extends AbstractEntity { ShowInterface: boolean = false; IsWatchingReplay: number = 0; + private configList: Record = { + VolumeUniversal: { + type: 'int', + setValue: (settings, value) => { + settings.volume.master = value; + } + }, + VolumeEffect: { + type: 'int', + setValue: (settings, value) => { + settings.volume.effect = value; + } + }, + VolumeMusic: { + type: 'int', + setValue: (settings, value) => { + settings.volume.music = value; + } + }, + _ReleaseStream: { + type: 'enum', + setValue: (settings, value) => { + settings.client.branch = value; + } + }, + DimLevel: { + type: 'int', + setValue: (settings, value) => { + settings.background.dim = value; + } + }, + ShowStoryboard: { + type: 'bool', + setValue: (settings, value) => { + settings.background.storyboard = value; + } + }, + ShowInterface: { + type: 'bool', + setValue: (settings, value) => { + settings.showInterface = value; + } + }, + BeatmapDirectory: { + type: 'bstring', + setValue: (settings, value) => { + settings.songsFolder = value; + } + }, + ScoreMeter: { + type: 'enum', + setValue: (settings, value) => { + settings.scoreMeter.type = value; + } + }, + ScoreMeterScale: { + type: 'double', + setValue: (settings, value) => { + settings.scoreMeter.size = value; + } + }, + Offset: { + type: 'int', + setValue: (settings, value) => { + settings.offset.universal = value; + } + }, + CursorSize: { + type: 'double', + setValue: (settings, value) => { + settings.cursor.size = value; + } + }, + MouseSpeed: { + type: 'double', + setValue: (settings, value) => { + settings.mouse.sensitivity = value; + } + }, + Fullscreen: { + type: 'bool', + setValue: (settings, value) => { + settings.window.fullscreen = value; + } + }, + Width: { + type: 'int', + setValue: (settings, value) => { + settings.window.width = value; + } + }, + Height: { + type: 'int', + setValue: (settings, value) => { + settings.window.height = value; + } + }, + WidthFullscreen: { + type: 'int', + setValue: (settings, value) => { + settings.window.widthFullscreen = value; + } + }, + HeightFullscreen: { + type: 'int', + setValue: (settings, value) => { + settings.window.heightFullscreen = value; + } + } + }; + constructor(services: DataRepo) { super(services); } + async updateConfigState( + process: Process, + settings: Settings, + configurationAddr: number + ) { + const items = process.readInt(configurationAddr + 0x8); + const size = process.readInt(configurationAddr + 0x1c); + + for (let i = 0; i < size; i++) { + const current = items + 0x8 + 0x10 * i; + + const key = process.readSharpString(process.readInt(current)); + const bindable = process.readInt(current + 0x4); + + const configBindable = this.configList[key]; + + if (configBindable !== undefined) { + let value: any; + + switch (configBindable.type) { + case 'byte': + value = process.readByte(bindable + 0xc); + break; + case 'bool': + value = process.readByte(bindable + 0xc) == 1; + break; + case 'int': + case 'double': + value = process.readDouble(bindable + 0x4); + break; + case 'string': + value = process.readSharpString( + process.readInt(current + 0x4) + ); + break; + case 'bstring': + value = process.readSharpString( + process.readInt(bindable + 0x4) + ); + break; + case 'enum': + value = process.readInt(bindable + 0xc); + break; + default: + return; + } + + configBindable.setValue(settings, value); + } + } + } + async updateState() { const { process, patterns, settings } = this.services.getServices([ 'process', @@ -30,7 +201,7 @@ export class AllTimesData extends AbstractEntity { menuModsPtr, chatCheckerAddr, skinDataAddr, - settingsClassAddr, + configurationAddr, canRunSlowlyAddr, gameTimePtr } = patterns.getPatterns([ @@ -39,7 +210,7 @@ export class AllTimesData extends AbstractEntity { 'menuModsPtr', 'chatCheckerAddr', 'skinDataAddr', - 'settingsClassAddr', + 'configurationAddr', 'canRunSlowlyAddr', 'gameTimePtr' ]); @@ -62,26 +233,14 @@ export class AllTimesData extends AbstractEntity { this.SkinFolder = process.readSharpString( process.readInt(skinOsuBase + 0x44) ); - // [[SettingsClass + 0x8] + 0x4] + 0xC - this.ShowInterface = Boolean( - process.readByte( - process.readInt( - process.readInt(settingsClassAddr + 0x8) + 0x4 - ) + 0xc - ) - ); - this.SongsFolder = process.readSharpString( - process.readInt( - process.readInt( - process.readInt(settingsClassAddr + 0x8) + 0xb8 - ) + 0x4 - ) - ); - this.IsWatchingReplay = process.readByte( process.readInt(canRunSlowlyAddr + 0x46) ); - settings.setShowInterface(this.ShowInterface); + this.updateConfigState( + process, + settings, + process.readPointer(configurationAddr) + ); } } diff --git a/packages/tosu/src/entities/Settings/index.ts b/packages/tosu/src/entities/Settings/index.ts index c6bbe98f..3428d5e2 100644 --- a/packages/tosu/src/entities/Settings/index.ts +++ b/packages/tosu/src/entities/Settings/index.ts @@ -1,4 +1,73 @@ +enum ReleaseStream { + CuttingEdge, + Stable, + Beta, + Fallback +} + +enum ScoreMeterType { + None, + Colour, + Error +} + +interface Volume { + master: number; + music: number; + effect: number; +} + +interface Background { + dim: number; + video: boolean; + storyboard: boolean; +} + +interface Client { + branch: ReleaseStream; +} + +interface Window { + fullscreen: boolean; + width: number; + height: number; + widthFullscreen: number; + heightFullscreen: number; +} + +interface ScoreMeter { + type: ScoreMeterType; + size: number; +} + +interface Offset { + universal: number; +} + +interface Cursor { + size: number; +} + +interface Mouse { + sensitivity: number; +} + export class Settings { + volume: Volume = { master: 0, music: 0, effect: 0 }; + background: Background = { dim: 0, video: false, storyboard: false }; + client: Client = { branch: 0 }; + window: Window = { + fullscreen: false, + width: 0, + height: 0, + widthFullscreen: 0, + heightFullscreen: 0 + }; + scoreMeter: ScoreMeter = { type: ScoreMeterType.None, size: 0 }; + offset: Offset = { universal: 0 }; + cursor: Cursor = { size: 0 }; + mouse: Mouse = { sensitivity: 0 }; + showInterface: boolean = false; gameFolder: string = ''; skinFolder: string = ''; diff --git a/packages/tosu/src/objects/instanceManager/osuInstance.ts b/packages/tosu/src/objects/instanceManager/osuInstance.ts index 655cee03..f368a4f1 100644 --- a/packages/tosu/src/objects/instanceManager/osuInstance.ts +++ b/packages/tosu/src/objects/instanceManager/osuInstance.ts @@ -40,12 +40,12 @@ const SCAN_PATTERNS: { chatCheckerAddr: { pattern: '0A D7 23 3C 00 00 ?? 01' }, - skinDataAddr: { pattern: '74 2C 85 FF 75 28 A1 ?? ?? ?? ?? 8D 15' }, - settingsClassAddr: { - pattern: '83 E0 20 85 C0 7E 2F' + configurationAddr: { + pattern: '8B 0D ?? ?? ?? ?? 39 09 E8 ?? ?? ?? ?? 85 C0 7E', + offset: 0x2 }, rulesetsAddr: { pattern: '7D 15 A1 ?? ?? ?? ?? 85 C0' diff --git a/packages/tosu/src/objects/memoryBase.ts b/packages/tosu/src/objects/memoryBase.ts index 7771d05a..74d2b26a 100644 --- a/packages/tosu/src/objects/memoryBase.ts +++ b/packages/tosu/src/objects/memoryBase.ts @@ -9,7 +9,7 @@ export interface BaseData { playTimeAddr: number; chatCheckerAddr: number; skinDataAddr: number; - settingsClassAddr: number; + configurationAddr: number; rulesetsAddr: number; canRunSlowlyAddr: number; getAudioLengthAddr: number; @@ -32,7 +32,7 @@ export class MemoryBase { playTimeAddr: 0, chatCheckerAddr: 0, skinDataAddr: 0, - settingsClassAddr: 0, + configurationAddr: 0, rulesetsAddr: 0, canRunSlowlyAddr: 0, getAudioLengthAddr: 0, diff --git a/packages/tosu/src/objects/memoryPatterns.ts b/packages/tosu/src/objects/memoryPatterns.ts index 4d0d9119..4f6420b5 100644 --- a/packages/tosu/src/objects/memoryPatterns.ts +++ b/packages/tosu/src/objects/memoryPatterns.ts @@ -5,7 +5,7 @@ export interface PatternData { playTimeAddr: number; chatCheckerAddr: number; skinDataAddr: number; - settingsClassAddr: number; + configurationAddr: number; rulesetsAddr: number; canRunSlowlyAddr: number; statusPtr: number; @@ -28,7 +28,7 @@ export class MemoryPatterns { playTimeAddr: 0, chatCheckerAddr: 0, skinDataAddr: 0, - settingsClassAddr: 0, + configurationAddr: 0, rulesetsAddr: 0, canRunSlowlyAddr: 0, statusPtr: 0,