Skip to content

Commit c3ede3b

Browse files
committed
10.0.9
1 parent dc2d4c4 commit c3ede3b

File tree

15 files changed

+374
-200
lines changed

15 files changed

+374
-200
lines changed

cli/lib/main.dart

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@ const Command _build = Command(name: 'versions', parameters: [], subCommands: [_
1616
const Command _play = Command(name: 'play', parameters: [], subCommands: []);
1717
const Command _host = Command(name: 'host', parameters: [], subCommands: []);
1818
const Command _backend = Command(name: 'backend', parameters: [], subCommands: []);
19-
final List<String> _versions = downloadableBuilds.map((build) => build.version.toString()).toList(growable: false);
19+
final List<String> _versions = downloadableBuilds.map((build) => build.gameVersion).toList(growable: false);
20+
const String _playVersionAction = 'Play';
21+
const String _hostVersionAction = 'Host';
22+
const String _deleteVersionAction = 'Delete';
23+
const String _infoVersionAction = 'Info';
24+
const List<String> _versionActions = [_playVersionAction, _hostVersionAction, _deleteVersionAction, _infoVersionAction];
2025

2126
void main(List<String> args) async {
2227
enableLoggingToConsole = false;
@@ -98,19 +103,46 @@ Future<void> _handleBuildCommand(CommandCall? call) async {
98103
}
99104

100105
void _handleBuildListCommand(CommandCall commandCall) {
101-
final versions = readVersions();
106+
List<FortniteVersion> versions;
107+
try {
108+
versions = readVersions();
109+
}catch(error) {
110+
print("❌ $error");
111+
return;
112+
}
113+
114+
if(versions.isEmpty) {
115+
print("❌ No versions found");
116+
return;
117+
}
118+
102119
final versionSelector = Select.withTheme(
103120
prompt: ' Select a version:',
104-
options: versions.map((version) => version.content.toString()).toList(growable: false),
121+
options: versions.map((version) => version.gameVersion).toList(growable: false),
105122
theme: Theme.colorfulTheme.copyWith(inputPrefix: '❓', inputSuffix: '', successSuffix: '', errorPrefix: '❌')
106123
);
107124
final version = versions[versionSelector.interact()];
108125
final actionSelector = Select.withTheme(
109126
prompt: ' Select an action:',
110-
options: ['Play', 'Host', 'Delete', 'Open in Explorer'],
127+
options: _versionActions,
111128
theme: Theme.colorfulTheme.copyWith(inputPrefix: '❓', inputSuffix: '', successSuffix: '', errorPrefix: '❌')
112129
);
113-
actionSelector.interact();
130+
final action = _versionActions[actionSelector.interact()];
131+
switch(action) {
132+
case _playVersionAction:
133+
break;
134+
case _hostVersionAction:
135+
break;
136+
case _deleteVersionAction:
137+
break;
138+
case _infoVersionAction:
139+
print('');
140+
print("""
141+
🏷️ ${"Version: ".cyan()} ${version.gameVersion}
142+
📁 ${"Location:".cyan()} ${version.location.path}
143+
""".green());
144+
break;
145+
}
114146
}
115147

116148
Future<void> _handleBuildImportCommand(CommandCall call) async {
@@ -125,8 +157,8 @@ Future<void> _handleBuildImportCommand(CommandCall call) async {
125157
}
126158

127159
final fortniteVersion = FortniteVersion(
128-
name: "dummy",
129-
content: Version.parse(version),
160+
name: '',
161+
gameVersion: version,
130162
location: Directory(path)
131163
);
132164
writeVersion(fortniteVersion);
@@ -197,18 +229,32 @@ Future<bool> _checkBuildPath(String path, bool existing) async {
197229
if (existing) {
198230
final checker = Spinner.withTheme(
199231
icon: '✅',
200-
rightPrompt: (status) => status != SpinnerStateType.inProgress ? 'Finished looking for FortniteClient-Win64-Shipping.exe' : 'Looking for FortniteClient-Win64-Shipping.exe...',
232+
rightPrompt: (status) {
233+
switch(status) {
234+
case SpinnerStateType.inProgress:
235+
return 'Looking for FortniteClient-Win64-Shipping.exe...';
236+
case SpinnerStateType.done:
237+
return 'Finished looking for FortniteClient-Win64-Shipping.exe';
238+
case SpinnerStateType.failed:
239+
return 'Failed to look for FortniteClient-Win64-Shipping.exe';
240+
}
241+
},
201242
theme: Theme.colorfulTheme.copyWith(successSuffix: '', errorPrefix: '❌', spinners: '🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙 🕚 🕛'.split(' '))
202243
).interact();
203-
final result = await Future.wait([
204-
Future.delayed(const Duration(seconds: 1)).then((_) => true),
205-
Isolate.run(() => FortniteVersionExtension.findFiles(directory, "FortniteClient-Win64-Shipping.exe") != null)
206-
]).then((values) => values.reduce((first, second) => first && second));
207-
checker.done();
208-
if(!result) {
209-
print("❌ Cannot find FortniteClient-Win64-Shipping.exe: $path");
244+
245+
final files = await findFiles(directory, "FortniteClient-Win64-Shipping.exe")
246+
.withMinimumDuration(const Duration(seconds: 1));
247+
if(files.isEmpty) {
248+
print("❌ Cannot find FortniteClient-Win64-Shipping.exe in $path");
210249
return false;
211250
}
251+
252+
if(files.length > 1) {
253+
print("❌ There must be only one executable named FortniteClient-Win64-Shipping.exe in $path");
254+
return false;
255+
}
256+
257+
checker.done();
212258
}
213259

214260
return true;
@@ -309,7 +355,7 @@ Future<void> _handleBuildDownloadCommand(CommandCall call) async {
309355
}
310356

311357
final parsedVersion = Version.parse(version);
312-
final build = downloadableBuilds.firstWhereOrNull((build) => build.version == parsedVersion);
358+
final build = downloadableBuilds.firstWhereOrNull((build) => Version.parse(build.gameVersion) == parsedVersion);
313359
if(build == null) {
314360
print('');
315361
print("❌ Cannot find mirror for version: $parsedVersion");
@@ -339,8 +385,8 @@ Future<void> _handleBuildDownloadCommand(CommandCall call) async {
339385
downloader.done();
340386
receivePort.close();
341387
final fortniteVersion = FortniteVersion(
342-
name: "dummy",
343-
content: parsedVersion,
388+
name: "dummy",
389+
gameVersion: version,
344390
location: parsedDirectory
345391
);
346392
writeVersion(fortniteVersion);

cli/lib/src/controller/config.dart

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,20 @@ List<FortniteVersion> readVersions() {
99
return [];
1010
}
1111

12-
Iterable decodedVersionsJson = jsonDecode(file.readAsStringSync());
13-
return decodedVersionsJson
14-
.map((entry) => FortniteVersion.fromJson(entry))
15-
.toList();
12+
try {
13+
Iterable decodedVersionsJson = jsonDecode(file.readAsStringSync());
14+
return decodedVersionsJson
15+
.map((entry) {
16+
try {
17+
return FortniteVersion.fromJson(entry);
18+
}catch(error) {
19+
throw "Cannot parse version: $error";
20+
}
21+
})
22+
.toList();
23+
}catch(error) {
24+
throw "Cannot parse versions: $error";
25+
}
1626
}
1727

1828
void writeVersion(FortniteVersion version) {

cli/lib/src/util/extensions.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,14 @@ extension IterableExtension<E> on Iterable<E> {
77
}
88
return null;
99
}
10+
}
11+
12+
extension FutureExtension<T> on Future<T> {
13+
Future<T> withMinimumDuration(Duration duration) async {
14+
final result = await Future.wait([
15+
Future.delayed(duration),
16+
this
17+
]);
18+
return result.last;
19+
}
1020
}

common/lib/src/constant/game.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ const String kShippingExe = "FortniteClient-Win64-Shipping.exe";
3030
const String kLauncherExe = "FortniteLauncher.exe";
3131
const String kEacExe = "FortniteClient-Win64-Shipping_EAC.exe";
3232
const String kCrashReportExe = "CrashReportClient.exe";
33+
const String kGFSDKAftermathLibDll = "GFSDK_Aftermath_Lib.dll";
3334
final Version kMaxAllowedVersion = Version.parse("30.10");

common/lib/src/model/game_instance.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import 'dart:io';
22

33
import 'package:reboot_common/common.dart';
4-
import 'package:version/version.dart';
54

65

76
class GameInstance {
87
final String version;
8+
final bool host;
99
final int gamePid;
1010
final int? launcherPid;
1111
final int? eacPid;
@@ -18,6 +18,7 @@ class GameInstance {
1818

1919
GameInstance({
2020
required this.version,
21+
required this.host,
2122
required this.gamePid,
2223
required this.launcherPid,
2324
required this.eacPid,

common/lib/src/util/backend.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ final Semaphore _semaphore = Semaphore();
1515
String? _lastIp;
1616
String? _lastPort;
1717

18-
Stream<ServerResult> startBackend({required ServerType type, required String host, required String port, required bool detached, required void Function(String) onError}) async* {
18+
Stream<ServerResult> startBackend({
19+
required ServerType type,
20+
required String host,
21+
required String port,
22+
required bool detached,
23+
required void Function(String) onError
24+
}) async* {
1925
Process? process;
2026
HttpServer? server;
2127
try {
@@ -147,7 +153,13 @@ Future<Process> startEmbeddedBackend(bool detached, {void Function(String)? onEr
147153
}
148154
});
149155
if(!detached) {
150-
process.exitCode.then((exitCode) => log("[BACKEND] Exit code: $exitCode"));
156+
process.exitCode.then((exitCode) {
157+
if(!killed) {
158+
log("[BACKEND] Exit code: $exitCode");
159+
onError?.call("Exit code: $exitCode");
160+
killed = true;
161+
}
162+
});
151163
}
152164
return process;
153165
}

common/lib/src/util/game.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ Future<String> extractGameVersion(Directory directory) => Isolate.run(() async {
369369
log("[VERSION] Engine build: $engineVersionBuild");
370370
gameVersion = _buildToGameVersion[engineVersionBuild] ?? defaultGameVersion;
371371
}
372-
log("[VERSION] Returning $gameVersion");
372+
log("[VERSION] Parsed game version: $gameVersion");
373373
return gameVersion;
374374
}
375375
}

gui/lib/l10n/reboot_en.arb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@
243243
"gameServerStarted": "The game server was started successfully",
244244
"gameClientStarted": "The game client was started successfully",
245245
"checkingGameServer": "Checking if other players can join the game server...",
246-
"checkGameServerFixMessage": "Other players can't join the game server as port {port} isn't open",
247-
"checkGameServerFixAction": "Fix",
246+
"checkGameServerFixMessage": "The game server was started successfully, but other players can't join yet as port {port} isn't open",
247+
"checkGameServerFixAction": "Learn more",
248248
"infoName": "Info",
249249
"emptyVersionName": "Empty version name",
250250
"versionAlreadyExists": "This version already exists",
@@ -379,5 +379,9 @@
379379
"importedVersion": "Successfully imported version",
380380
"importVersionMissingShippingExeError": "Cannot import version: {name} should exist in the directory",
381381
"importVersionMultipleShippingExesError": "Cannot import version: only one {name} should exist in the directory",
382-
"importVersionUnsupportedVersionError": "This version of Fortnite is not supported by the launcher"
382+
"importVersionUnsupportedVersionError": "This version of Fortnite is not supported by the launcher",
383+
"downloadManually": "Download manually",
384+
"gameServerPortEqualsBackendPort": "The game server port cannot be {backendPort} as its reserved for the backend",
385+
"gameServer": "game server",
386+
"client": "client"
383387
}

gui/lib/src/controller/backend_controller.dart

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -163,24 +163,26 @@ class BackendController extends GetxController {
163163
port: port.text,
164164
detached: detached.value,
165165
onError: (errorMessage) {
166-
stop(interactive: false);
167-
Get.find<GameController>()
168-
.instance
169-
.value
170-
?.kill();
171-
Get.find<HostingController>()
172-
.instance
173-
.value
174-
?.kill();
175-
_showRebootInfoBar(
176-
translations.backendErrorMessage,
177-
severity: InfoBarSeverity.error,
178-
duration: infoBarLongDuration,
179-
action: Button(
180-
onPressed: () => launchUrl(launcherLogFile.uri),
181-
child: Text(translations.openLog),
182-
)
183-
);
166+
if(started.value) {
167+
stop(interactive: false);
168+
Get.find<GameController>()
169+
.instance
170+
.value
171+
?.kill();
172+
Get.find<HostingController>()
173+
.instance
174+
.value
175+
?.kill();
176+
_showRebootInfoBar(
177+
translations.backendErrorMessage,
178+
severity: InfoBarSeverity.error,
179+
duration: infoBarLongDuration,
180+
action: Button(
181+
onPressed: () => launchUrl(launcherLogFile.uri),
182+
child: Text(translations.openLog),
183+
)
184+
);
185+
}
184186
}
185187
);
186188
final completer = Completer<bool>();

gui/lib/src/messenger/info_bar.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const infoBarLongDuration = Duration(seconds: 4);
55
const infoBarShortDuration = Duration(seconds: 2);
66
const _height = 64.0;
77

8-
InfoBarEntry showRebootInfoBar(dynamic text, {
8+
InfoBarEntry showRebootInfoBar(String text, {
99
InfoBarSeverity severity = InfoBarSeverity.info,
1010
bool loading = false,
1111
Duration? duration = infoBarShortDuration,

0 commit comments

Comments
 (0)