Skip to content

Commit 4c3fe9b

Browse files
committed
Released 9.2.5
1 parent 5822708 commit 4c3fe9b

File tree

21 files changed

+503
-383
lines changed

21 files changed

+503
-383
lines changed

backend/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ express.use(require("./structure/matchmaking.js"));
3535
express.use(require("./structure/cloudstorage.js"));
3636
express.use(require("./structure/mcp.js"));
3737

38-
const port = process.env.PORT || 3551;
38+
const port = 3551;
3939
express.listen(port, () => {
4040
console.log("LawinServer started listening on port", port);
4141

common/lib/src/constant/game.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const List<String> kCorruptedBuildErrors = [
1111
"Critical error",
1212
"when 0 bytes remain",
1313
"Pak chunk signature verification failed!",
14-
"Couldn't find pak signature file"
14+
"LogWindows:Error: Fatal error!"
1515
];
1616
const List<String> kCannotConnectErrors = [
1717
"port 3551 failed: Connection refused",

common/lib/src/extension/path.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,22 @@ extension FortniteVersionExtension on FortniteVersion {
99

1010
static File? findFile(Directory directory, String name) {
1111
try{
12-
final result = directory.listSync(recursive: true)
13-
.firstWhere((element) => path.basename(element.path) == name);
14-
return File(result.path);
12+
for(final child in directory.listSync()) {
13+
if(child is Directory) {
14+
if(!path.basename(child.path).startsWith("\.")) {
15+
final result = findFile(child, name);
16+
if(result != null) {
17+
return result;
18+
}
19+
}
20+
}else if(child is File) {
21+
if(path.basename(child.path) == name) {
22+
return child;
23+
}
24+
}
25+
}
26+
27+
return null;
1528
}catch(_){
1629
return null;
1730
}

common/lib/src/util/backend.dart

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

18-
Future<Process> startEmbeddedBackend(bool detached) async {
18+
Future<Process> startEmbeddedBackend(bool detached, {void Function(String)? onError}) async {
1919
final process = await startProcess(
2020
executable: backendStartExecutable,
2121
window: detached,
2222
);
2323
process.stdOutput.listen((message) => log("[BACKEND] Message: $message"));
24-
process.stdError.listen((error) => log("[BACKEND] Error: $error"));
24+
process.stdError.listen((error) {
25+
log("[BACKEND] Error: $error");
26+
onError?.call(error);
27+
});
2528
process.exitCode.then((exitCode) => log("[BACKEND] Exit code: $exitCode"));
2629
return process;
2730
}

common/lib/src/util/process.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ Future<bool> startElevatedProcess({required String executable, required String a
102102
shellInput.ref.fMask = ES_AWAYMODE_REQUIRED;
103103
shellInput.ref.lpVerb = "runas".toNativeUtf16();
104104
shellInput.ref.cbSize = sizeOf<SHELLEXECUTEINFO>();
105-
var shellResult = ShellExecuteEx(shellInput);
106-
return shellResult == 1;
105+
return ShellExecuteEx(shellInput) == 1;
107106
}
108107

109108
Future<Process> startProcess({required File executable, List<String>? args, bool useTempBatch = true, bool window = false, String? name, Map<String, String>? environment}) async {
@@ -313,7 +312,14 @@ final class _ExtendedProcess implements Process {
313312

314313

315314
@override
316-
Future<int> get exitCode => _delegate.exitCode;
315+
Future<int> get exitCode {
316+
try {
317+
return _delegate.exitCode;
318+
}catch(_) {
319+
return watchProcess(_delegate.pid)
320+
.then((_) => -1);
321+
}
322+
}
317323

318324
@override
319325
bool kill([ProcessSignal signal = ProcessSignal.sigterm]) => _delegate.kill(signal);

gui/assets/backend/lawinserver.exe

-20 Bytes
Binary file not shown.

gui/lib/l10n/reboot_en.arb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,7 @@
118118
"settingsUtilsResetDefaultsName": "Reset settings",
119119
"settingsUtilsResetDefaultsSubtitle": "Resets the launcher's settings to their default values",
120120
"settingsUtilsDialogTitle": "Do you want to reset all the setting in this tab to their default values? This action is irreversible",
121-
"settingsUtilsResetDefaultsContent": "Reset",
122121
"settingsUtilsDialogSecondaryAction": "Close",
123-
"settingsUtilsDialogPrimaryAction": "Reset",
124122
"selectFortniteName": "Fortnite version",
125123
"selectFortniteDescription": "Select the version of Fortnite you want to use",
126124
"manageVersionsName": "Manage versions",
@@ -262,6 +260,7 @@
262260
"missingCustomDllError": "The custom {dll}.dll doesn't exist: check your settings",
263261
"tokenError": "Cannot log in into Fortnite: authentication error (injected dlls: {dlls})",
264262
"unknownFortniteError": "An unknown error occurred while launching Fortnite: {error}",
263+
"fortniteCrashError": "The {name} crashed after being launched",
265264
"serverNoLongerAvailableUnnamed": "The previous server is no longer available",
266265
"noServerFound": "No server found: invalid or expired link",
267266
"settingsUtilsThemeName": "Theme",
@@ -321,6 +320,7 @@
321320
"none": "none",
322321
"openLog": "Open log",
323322
"backendProcessError": "The backend shut down unexpectedly",
323+
"backendErrorMessage": "The backend reported an unexpected error",
324324
"welcomeTitle": "Welcome to Reboot Launcher",
325325
"welcomeDescription": "If you have never used a Fortnite game server, or this launcher in particular, please click on take a tour\nPlease don't ask for support on Discord without taking the tour: this helps me prioritize real bugs\nYou can always take the tour again in the Info tab",
326326
"welcomeAction": "Take the tour",
@@ -364,5 +364,8 @@
364364
"promptSettingsTabActionLabel": "Done",
365365
"automaticGameServerDialogContent": "The launcher detected that you are not running a game server, but that your matchmaker is set to your local machine. If you don't want to join another player's server, you should start a game server. This is necessary to be able to play!",
366366
"automaticGameServerDialogIgnore": "Ignore",
367-
"automaticGameServerDialogStart": "Start server"
367+
"automaticGameServerDialogStart": "Start server",
368+
"gameResetDefaultsName": "Reset",
369+
"gameResetDefaultsDescription": "Resets the game's settings to their default values",
370+
"gameResetDefaultsContent": "Reset"
368371
}

gui/lib/main.dart

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:local_notifier/local_notifier.dart';
1212
import 'package:package_info_plus/package_info_plus.dart';
1313
import 'package:reboot_common/common.dart';
1414
import 'package:reboot_launcher/src/controller/backend_controller.dart';
15+
import 'package:reboot_launcher/src/controller/dll_controller.dart';
1516
import 'package:reboot_launcher/src/controller/game_controller.dart';
1617
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
1718
import 'package:reboot_launcher/src/controller/settings_controller.dart';
@@ -188,10 +189,11 @@ void _initWindow() => doWhenWindowReady(() async {
188189
Future<List<Object>> _initStorage() async {
189190
final errors = <Object>[];
190191
try {
191-
await GetStorage("game_storage", settingsDirectory.path).initStorage;
192-
await GetStorage("backend_storage", settingsDirectory.path).initStorage;
193-
await GetStorage("settings_storage", settingsDirectory.path).initStorage;
194-
await GetStorage("hosting_storage", settingsDirectory.path).initStorage;
192+
await GetStorage(GameController.storageName, settingsDirectory.path).initStorage;
193+
await GetStorage(BackendController.storageName, settingsDirectory.path).initStorage;
194+
await GetStorage(SettingsController.storageName, settingsDirectory.path).initStorage;
195+
await GetStorage(HostingController.storageName, settingsDirectory.path).initStorage;
196+
await GetStorage(DllController.storageName, settingsDirectory.path).initStorage;
195197
}catch(error) {
196198
appWithNoStorage = true;
197199
errors.add("The Reboot Launcher configuration in ${settingsDirectory.path} cannot be accessed: running with in memory storage");
@@ -223,6 +225,12 @@ Future<List<Object>> _initStorage() async {
223225
errors.add(error);
224226
}
225227

228+
try {
229+
Get.put(DllController());
230+
}catch(error) {
231+
errors.add(error);
232+
}
233+
226234

227235
return errors;
228236
}

gui/lib/src/controller/backend_controller.dart

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@ import 'dart:async';
22
import 'dart:io';
33

44
import 'package:fluent_ui/fluent_ui.dart';
5+
import 'package:flutter/services.dart';
56
import 'package:get/get.dart';
67
import 'package:get_storage/get_storage.dart';
78
import 'package:reboot_common/common.dart';
89
import 'package:reboot_launcher/main.dart';
10+
import 'package:reboot_launcher/src/util/keyboard.dart';
911

1012
class BackendController extends GetxController {
11-
late final GetStorage? storage;
13+
static const String storageName = "backend_storage";
14+
static const PhysicalKeyboardKey _kDefaultConsoleKey = PhysicalKeyboardKey(0x00070041);
15+
16+
late final GetStorage? _storage;
1217
late final TextEditingController host;
1318
late final TextEditingController port;
1419
late final Rx<ServerType> type;
1520
late final TextEditingController gameServerAddress;
1621
late final FocusNode gameServerAddressFocusNode;
22+
late final Rx<PhysicalKeyboardKey> consoleKey;
1723
late final RxBool started;
1824
late final RxBool detached;
1925
StreamSubscription? worker;
@@ -22,13 +28,13 @@ class BackendController extends GetxController {
2228
HttpServer? remoteServer;
2329

2430
BackendController() {
25-
storage = appWithNoStorage ? null : GetStorage("backend_storage");
31+
_storage = appWithNoStorage ? null : GetStorage(storageName);
2632
started = RxBool(false);
27-
type = Rx(ServerType.values.elementAt(storage?.read("type") ?? 0));
33+
type = Rx(ServerType.values.elementAt(_storage?.read("type") ?? 0));
2834
type.listen((value) {
2935
host.text = _readHost();
3036
port.text = _readPort();
31-
storage?.write("type", value.index);
37+
_storage?.write("type", value.index);
3238
if (!started.value) {
3339
return;
3440
}
@@ -37,13 +43,13 @@ class BackendController extends GetxController {
3743
});
3844
host = TextEditingController(text: _readHost());
3945
host.addListener(() =>
40-
storage?.write("${type.value.name}_host", host.text));
46+
_storage?.write("${type.value.name}_host", host.text));
4147
port = TextEditingController(text: _readPort());
4248
port.addListener(() =>
43-
storage?.write("${type.value.name}_port", port.text));
44-
detached = RxBool(storage?.read("detached") ?? false);
45-
detached.listen((value) => storage?.write("detached", value));
46-
final address = storage?.read("game_server_address");
49+
_storage?.write("${type.value.name}_port", port.text));
50+
detached = RxBool(_storage?.read("detached") ?? false);
51+
detached.listen((value) => _storage?.write("detached", value));
52+
final address = _storage?.read("game_server_address");
4753
gameServerAddress = TextEditingController(text: address == null || address.isEmpty ? "127.0.0.1" : address);
4854
var lastValue = gameServerAddress.text;
4955
writeMatchmakingIp(lastValue);
@@ -55,7 +61,7 @@ class BackendController extends GetxController {
5561

5662
lastValue = newValue;
5763
gameServerAddress.selection = TextSelection.collapsed(offset: newValue.length);
58-
storage?.write("game_server_address", newValue);
64+
_storage?.write("game_server_address", newValue);
5965
writeMatchmakingIp(newValue);
6066
});
6167
watchMatchmakingIp().listen((event) {
@@ -64,6 +70,37 @@ class BackendController extends GetxController {
6470
}
6571
});
6672
gameServerAddressFocusNode = FocusNode();
73+
consoleKey = Rx(_readConsoleKey());
74+
_writeConsoleKey(consoleKey.value);
75+
consoleKey.listen((newValue) {
76+
_storage?.write("console_key", newValue.usbHidUsage);
77+
_writeConsoleKey(newValue);
78+
});
79+
}
80+
81+
PhysicalKeyboardKey _readConsoleKey() {
82+
final consoleKeyValue = _storage?.read("console_key");
83+
if(consoleKeyValue == null) {
84+
return _kDefaultConsoleKey;
85+
}
86+
87+
final consoleKeyNumber = int.tryParse(consoleKeyValue.toString());
88+
if(consoleKeyNumber == null) {
89+
return _kDefaultConsoleKey;
90+
}
91+
92+
final consoleKey = PhysicalKeyboardKey(consoleKeyNumber);
93+
if(!consoleKey.isUnrealEngineKey) {
94+
return _kDefaultConsoleKey;
95+
}
96+
97+
return consoleKey;
98+
}
99+
100+
Future<void> _writeConsoleKey(PhysicalKeyboardKey keyValue) async {
101+
final defaultInput = File("${backendDirectory.path}\\CloudStorage\\DefaultInput.ini");
102+
await defaultInput.parent.create(recursive: true);
103+
await defaultInput.writeAsString("[/Script/Engine.InputSettings]\n+ConsoleKeys=Tilde\n+ConsoleKeys=${keyValue.unrealEngineName}", flush: true);
67104
}
68105

69106
void joinLocalhost() {
@@ -73,18 +110,19 @@ class BackendController extends GetxController {
73110
void reset() async {
74111
type.value = ServerType.values.elementAt(0);
75112
for (final type in ServerType.values) {
76-
storage?.write("${type.name}_host", null);
77-
storage?.write("${type.name}_port", null);
113+
_storage?.write("${type.name}_host", null);
114+
_storage?.write("${type.name}_port", null);
78115
}
79116

80117
host.text = type.value != ServerType.remote ? kDefaultBackendHost : "";
81118
port.text = kDefaultBackendPort.toString();
82119
gameServerAddress.text = "127.0.0.1";
120+
consoleKey.value = _kDefaultConsoleKey;
83121
detached.value = false;
84122
}
85123

86124
String _readHost() {
87-
String? value = storage?.read("${type.value.name}_host");
125+
String? value = _storage?.read("${type.value.name}_host");
88126
if (value != null && value.isNotEmpty) {
89127
return value;
90128
}
@@ -97,9 +135,9 @@ class BackendController extends GetxController {
97135
}
98136

99137
String _readPort() =>
100-
storage?.read("${type.value.name}_port") ?? kDefaultBackendPort.toString();
138+
_storage?.read("${type.value.name}_port") ?? kDefaultBackendPort.toString();
101139

102-
Stream<ServerResult> start() async* {
140+
Stream<ServerResult> start({required void Function() onExit, required void Function(String) onError}) async* {
103141
try {
104142
if(started.value) {
105143
return;
@@ -144,7 +182,18 @@ class BackendController extends GetxController {
144182

145183
switch(serverType){
146184
case ServerType.embedded:
147-
final process = await startEmbeddedBackend(detached.value);
185+
final process = await startEmbeddedBackend(detached.value, onError: (errorMessage) {
186+
if(started.value) {
187+
started.value = false;
188+
onError(errorMessage);
189+
}
190+
});
191+
watchProcess(process.pid).then((_) {
192+
if(started.value) {
193+
started.value = false;
194+
onExit();
195+
}
196+
});
148197
embeddedProcessPid = process.pid;
149198
break;
150199
case ServerType.remote:
@@ -237,11 +286,14 @@ class BackendController extends GetxController {
237286
}
238287
}
239288

240-
Stream<ServerResult> toggle() async* {
289+
Stream<ServerResult> toggle({required void Function() onExit, required void Function(String) onError}) async* {
241290
if(started()) {
242291
yield* stop();
243292
}else {
244-
yield* start();
293+
yield* start(
294+
onExit: onExit,
295+
onError: onError
296+
);
245297
}
246298
}
247299
}

0 commit comments

Comments
 (0)