Select the installed language pack when launching MoonWell
Pass WOW_LOCALE=auto alongside the selected Data directory so inherited locale settings cannot override an installed ruRU pack. Keep language archives in the regular manifest download and verification flow. Document the contract and prepare launcher version 1.0.7+10 for the localization release. Verified on Windows through FVM: full format check and flutter analyze passed; all 76 Flutter tests passed, including manifest retention and verification of Russian archives and the game's child environment. No macOS build was run.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -286,6 +286,8 @@ When the user presses `Play`:
|
||||
- `WOW_HOST=<auth-address>`
|
||||
- `WOW_DATA=<absolute-data-directory>`
|
||||
- `BENILLA_HOME=<install-root>/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:
|
||||
|
||||
@@ -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'),
|
||||
},
|
||||
);
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user