diff --git a/AGENTS.md b/AGENTS.md index 2e44274..fa5e116 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,6 +98,8 @@ or local-only API URLs. plus legacy `WoW.exe` and DLLs directly in the installation root or `WoW`. Remove unused Data subdirectories only after their children, without recursive deletion. Preserve unrelated files and user state outside these areas. +- Language archives under `Data/ruRU` or `WoW/Data/ruRU` use the regular manifest sync. + Pass `WOW_LOCALE=auto` to the game so its selected install determines the locale. - Downloads must write to `*.moonwell.part`, verify size and SHA-256, then replace the destination file only after successful verification. - Local scans should ignore volatile client directories and launcher metadata: diff --git a/README.md b/README.md index 6a1bcfd..ddf7b15 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,12 @@ folder. For builds that pin an endpoint, set `--dart-define=MOONWELL_AUTH_ADDRESS=login.example:3724` instead. This endpoint is the vMaNGOS auth server, separate from the realm's world port and the Web API. +Russian 1.12.1 language archives are regular manifest files under `Data/ruRU` +(or `WoW/Data/ruRU` for a nested install). They are downloaded and verified with +the same size and SHA-256 checks as the base client. The launcher passes +`WOW_LOCALE=auto` to the game: an installed pack selects Russian, and a base-only +install selects English, regardless of the launcher's inherited environment. + Example run command: ```powershell diff --git a/docs/launcher_web_api_spec.md b/docs/launcher_web_api_spec.md index cf65c94..f55cbe1 100644 --- a/docs/launcher_web_api_spec.md +++ b/docs/launcher_web_api_spec.md @@ -286,6 +286,8 @@ When the user presses `Play`: - `WOW_HOST=` - `WOW_DATA=` - `BENILLA_HOME=/benilla-config` + - `WOW_LOCALE=auto` (select the installed `Data/ruRU` or `WoW/Data/ruRU` language pack, + otherwise English; override any locale inherited from the launcher's parent) 6. launcher retains a process handle; while the process is alive, it disables repeated game launches and client synchronization 7. when the process exits, the launcher returns to the ready-to-play state @@ -297,6 +299,10 @@ If the executable, data directory, or auth endpoint is missing or invalid, launch fails with an error. A consumed ticket cannot authenticate again; close the client and press Play for a fresh ticket after a session ends. +Language archives are ordinary client-manifest entries, including their nested paths, +sizes and SHA-256 hashes. Synchronization verifies and retains required `ruRU` files +and removes obsolete archives under the same manifest-authoritative Data policy. + ## Error Behavior The launcher surfaces errors for: diff --git a/lib/features/launcher/data/game_installation_service.dart b/lib/features/launcher/data/game_installation_service.dart index cb235d2..6c5061c 100644 --- a/lib/features/launcher/data/game_installation_service.dart +++ b/lib/features/launcher/data/game_installation_service.dart @@ -304,6 +304,8 @@ class GameInstallationService { 'WOW_PASS': authorization.ticket, 'WOW_HOST': authAddress, 'WOW_DATA': dataPath, + // Let the client select Data/ruRU independently of the launcher's parent environment. + 'WOW_LOCALE': 'auto', 'BENILLA_HOME': p.join(rootPath, 'benilla-config'), }, ); diff --git a/pubspec.yaml b/pubspec.yaml index 596e317..c2051af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.5+8 +version: 1.0.7+10 environment: sdk: ">=3.10.0" diff --git a/test/features/launcher/data/game_installation_service_test.dart b/test/features/launcher/data/game_installation_service_test.dart index de0b22a..9c37809 100644 --- a/test/features/launcher/data/game_installation_service_test.dart +++ b/test/features/launcher/data/game_installation_service_test.dart @@ -421,6 +421,7 @@ void main() { 'WOW_PASS': 'A1B2C3D4E5F6G7H8', 'WOW_HOST': '127.0.0.1:3724', 'WOW_DATA': '${rootDirectory.path}${Platform.pathSeparator}Data', + 'WOW_LOCALE': 'auto', 'BENILLA_HOME': '${rootDirectory.path}${Platform.pathSeparator}benilla-config', }); @@ -479,6 +480,46 @@ void main() { expect(recordingService.environment?['WOW_DATA'], nestedData.path); }); + test('verifies and retains Russian archives before launching', () async { + final paths = [ + 'MoonWell.exe', + 'Data/common.MPQ', + 'Data/ruRU/patch-1.MPQ', + 'Data/ruRU/patch-2.MPQ', + 'Data/ruRU/patch-3.MPQ', + ]; + for (final path in paths.skip(2)) { + final file = File(service.resolveClientPath(rootDirectory.path, path)); + await file.parent.create(recursive: true); + await file.writeAsString('localized archive: $path'); + } + final manifest = await _manifestForPaths(service, rootDirectory, paths); + final snapshot = await service.scanInstallation( + rootDirectory.path, + manifest: manifest, + ); + expect(snapshot.buildHash, manifest.buildHash); + expect(snapshot.stalePaths, isEmpty); + final recordingService = _RecordingGameInstallationService(); + await recordingService.launchGame( + rootDirectory.path, + authorization: _validTicket(), + ); + expect(recordingService.environment?['WOW_LOCALE'], 'auto'); + expect( + recordingService.environment?['WOW_DATA'], + '${rootDirectory.path}${Platform.pathSeparator}Data', + ); + for (final path in paths.skip(2)) { + expect( + await File( + service.resolveClientPath(rootDirectory.path, path), + ).readAsString(), + 'localized archive: $path', + ); + } + }); + test('configured auth address overrides the install realmlist', () async { final configured = _RecordingGameInstallationService( authAddress: 'login.example:3725',