mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 03:02:22 +01:00
Released 9.2.6
This commit is contained in:
@@ -145,6 +145,7 @@
|
|||||||
"defaultServerName": "Reboot Game Server",
|
"defaultServerName": "Reboot Game Server",
|
||||||
"defaultServerDescription": "Just another server",
|
"defaultServerDescription": "Just another server",
|
||||||
"downloadingDll": "Downloading {name} dll...",
|
"downloadingDll": "Downloading {name} dll...",
|
||||||
|
"dllAlreadyExists": "The {name} was already downloaded",
|
||||||
"downloadDllSuccess": "The {name} dll was downloaded successfully",
|
"downloadDllSuccess": "The {name} dll was downloaded successfully",
|
||||||
"downloadDllError": "An error occurred while downloading {name}: {error}",
|
"downloadDllError": "An error occurred while downloading {name}: {error}",
|
||||||
"downloadDllRetry": "Retry",
|
"downloadDllRetry": "Retry",
|
||||||
@@ -360,7 +361,7 @@
|
|||||||
"promptBackendDetachedActionLabel": "Next",
|
"promptBackendDetachedActionLabel": "Next",
|
||||||
"promptInfoTabText": "The Info tab contains useful links to report bugs and receive support",
|
"promptInfoTabText": "The Info tab contains useful links to report bugs and receive support",
|
||||||
"promptInfoTabActionLabel": "Next",
|
"promptInfoTabActionLabel": "Next",
|
||||||
"promptSettingsTabText": "The Settings tab contains options to customize and reset the launcher",
|
"promptSettingsTabText": "The Settings tab contains options to customize the launcher",
|
||||||
"promptSettingsTabActionLabel": "Done",
|
"promptSettingsTabActionLabel": "Done",
|
||||||
"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!",
|
"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!",
|
||||||
"automaticGameServerDialogIgnore": "Ignore",
|
"automaticGameServerDialogIgnore": "Ignore",
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ class DllController extends GetxController {
|
|||||||
late final TextEditingController url;
|
late final TextEditingController url;
|
||||||
late final RxBool customGameServer;
|
late final RxBool customGameServer;
|
||||||
late final RxnInt timestamp;
|
late final RxnInt timestamp;
|
||||||
late final Map<String, Future<bool>> _operations;
|
|
||||||
late final Rx<UpdateStatus> status;
|
late final Rx<UpdateStatus> status;
|
||||||
InfoBarEntry? infoBarEntry;
|
InfoBarEntry? infoBarEntry;
|
||||||
Future<bool>? _updater;
|
Future<bool>? _updater;
|
||||||
@@ -51,20 +50,19 @@ class DllController extends GetxController {
|
|||||||
customGameServer.listen((value) => _storage?.write("custom_game_server", value));
|
customGameServer.listen((value) => _storage?.write("custom_game_server", value));
|
||||||
timestamp = RxnInt(_storage?.read("ts"));
|
timestamp = RxnInt(_storage?.read("ts"));
|
||||||
timestamp.listen((value) => _storage?.write("ts", value));
|
timestamp.listen((value) => _storage?.write("ts", value));
|
||||||
_operations = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditingController _createController(String key, InjectableDll dll) {
|
TextEditingController _createController(String key, InjectableDll dll) {
|
||||||
final controller = TextEditingController(text: _storage?.read(key) ?? _getDefaultPath(dll));
|
final controller = TextEditingController(text: _storage?.read(key) ?? getDefaultDllPath(dll));
|
||||||
controller.addListener(() => _storage?.write(key, controller.text));
|
controller.addListener(() => _storage?.write(key, controller.text));
|
||||||
return controller;
|
return controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetGame() {
|
void resetGame() {
|
||||||
gameServerDll.text = _getDefaultPath(InjectableDll.reboot);
|
gameServerDll.text = getDefaultDllPath(InjectableDll.reboot);
|
||||||
unrealEngineConsoleDll.text = _getDefaultPath(InjectableDll.console);
|
unrealEngineConsoleDll.text = getDefaultDllPath(InjectableDll.console);
|
||||||
backendDll.text = _getDefaultPath(InjectableDll.cobalt);
|
backendDll.text = getDefaultDllPath(InjectableDll.cobalt);
|
||||||
memoryLeakDll.text = _getDefaultPath(InjectableDll.memory);
|
memoryLeakDll.text = getDefaultDllPath(InjectableDll.memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetServer() {
|
void resetServer() {
|
||||||
@@ -147,7 +145,7 @@ class DllController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(File, bool) getInjectableData(InjectableDll dll) {
|
(File, bool) getInjectableData(InjectableDll dll) {
|
||||||
final defaultPath = canonicalize(_getDefaultPath(dll));
|
final defaultPath = canonicalize(getDefaultDllPath(dll));
|
||||||
switch(dll){
|
switch(dll){
|
||||||
case InjectableDll.reboot:
|
case InjectableDll.reboot:
|
||||||
if(customGameServer.value) {
|
if(customGameServer.value) {
|
||||||
@@ -170,23 +168,10 @@ class DllController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _getDefaultPath(InjectableDll dll) => "${dllsDirectory.path}\\${dll.name}.dll";
|
String getDefaultDllPath(InjectableDll dll) => "${dllsDirectory.path}\\${dll.name}.dll";
|
||||||
|
|
||||||
Future<bool> downloadCriticalDllInteractive(String filePath, {bool silent = false}) {
|
Future<bool> downloadCriticalDllInteractive(String filePath, {bool silent = false, bool force = false}) async {
|
||||||
log("[DLL] Asking for $filePath(silent: $silent)");
|
log("[DLL] Asking for $filePath(silent: $silent)");
|
||||||
final old = _operations[filePath];
|
|
||||||
if(old != null) {
|
|
||||||
log("[DLL] Download task already exists");
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
log("[DLL] Creating new download task...");
|
|
||||||
final newRun = _downloadCriticalDllInteractive(filePath, silent);
|
|
||||||
_operations[filePath] = newRun;
|
|
||||||
return newRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _downloadCriticalDllInteractive(String filePath, bool silent) async {
|
|
||||||
final fileName = basename(filePath).toLowerCase();
|
final fileName = basename(filePath).toLowerCase();
|
||||||
log("[DLL] File name: $fileName");
|
log("[DLL] File name: $fileName");
|
||||||
InfoBarEntry? entry;
|
InfoBarEntry? entry;
|
||||||
@@ -198,7 +183,7 @@ class DllController extends GetxController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(File(filePath).existsSync()) {
|
if(!force && File(filePath).existsSync()) {
|
||||||
log("[DLL] File already exists");
|
log("[DLL] File already exists");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -225,7 +210,8 @@ class DllController extends GetxController {
|
|||||||
log("[DLL] Error: $message");
|
log("[DLL] Error: $message");
|
||||||
entry?.close();
|
entry?.close();
|
||||||
var error = message.toString();
|
var error = message.toString();
|
||||||
error = error.contains(": ") ? error.substring(error.indexOf(": ") + 2) : error;
|
error =
|
||||||
|
error.contains(": ") ? error.substring(error.indexOf(": ") + 2) : error;
|
||||||
error = error.toLowerCase();
|
error = error.toLowerCase();
|
||||||
final completer = Completer();
|
final completer = Completer();
|
||||||
await showRebootInfoBar(
|
await showRebootInfoBar(
|
||||||
@@ -243,8 +229,6 @@ class DllController extends GetxController {
|
|||||||
);
|
);
|
||||||
await completer.future;
|
await completer.future;
|
||||||
return false;
|
return false;
|
||||||
}finally {
|
|
||||||
_operations.remove(fileName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class SettingsController extends GetxController {
|
|||||||
late final RxString language;
|
late final RxString language;
|
||||||
late final Rx<ThemeMode> themeMode;
|
late final Rx<ThemeMode> themeMode;
|
||||||
late final RxBool firstRun;
|
late final RxBool firstRun;
|
||||||
|
late final RxBool debug;
|
||||||
late double width;
|
late double width;
|
||||||
late double height;
|
late double height;
|
||||||
late double? offsetX;
|
late double? offsetX;
|
||||||
@@ -38,6 +39,7 @@ class SettingsController extends GetxController {
|
|||||||
language.listen((value) => _storage?.write("language", value));
|
language.listen((value) => _storage?.write("language", value));
|
||||||
firstRun = RxBool(_storage?.read("first_run_tutorial") ?? true);
|
firstRun = RxBool(_storage?.read("first_run_tutorial") ?? true);
|
||||||
firstRun.listen((value) => _storage?.write("first_run_tutorial", value));
|
firstRun.listen((value) => _storage?.write("first_run_tutorial", value));
|
||||||
|
debug = RxBool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveWindowSize(Size size) {
|
void saveWindowSize(Size size) {
|
||||||
|
|||||||
@@ -23,19 +23,18 @@ InfoBarEntry showRebootInfoBar(dynamic text, {
|
|||||||
|
|
||||||
Widget _buildOverlay(text, Widget? action, bool loading, InfoBarSeverity severity) => ConstrainedBox(
|
Widget _buildOverlay(text, Widget? action, bool loading, InfoBarSeverity severity) => ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minWidth: double.infinity,
|
minHeight: _height
|
||||||
minHeight: _height
|
|
||||||
),
|
),
|
||||||
child: Mica(
|
child: Mica(
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
child: InfoBar(
|
child: InfoBar(
|
||||||
title: Row(
|
title: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
if(text is Widget)
|
Expanded(
|
||||||
text,
|
child: text is Widget ? text : Text(text)
|
||||||
if(text is String)
|
),
|
||||||
Text(text),
|
|
||||||
if(action != null)
|
if(action != null)
|
||||||
action
|
action
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
|
||||||
|
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||||
|
import 'package:reboot_launcher/src/messenger/implementation/onboard.dart';
|
||||||
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
import 'package:reboot_launcher/src/page/abstract/page_type.dart';
|
||||||
|
import 'package:reboot_launcher/src/util/translations.dart';
|
||||||
|
|
||||||
abstract class RebootPage extends StatefulWidget {
|
abstract class RebootPage extends StatefulWidget {
|
||||||
const RebootPage({super.key});
|
const RebootPage({super.key});
|
||||||
@@ -19,32 +24,110 @@ abstract class RebootPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class RebootPageState<T extends RebootPage> extends State<T> with AutomaticKeepAliveClientMixin<T> {
|
abstract class RebootPageState<T extends RebootPage> extends State<T> with AutomaticKeepAliveClientMixin<T> {
|
||||||
|
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
var buttonWidget = button;
|
var buttonWidget = button;
|
||||||
if(buttonWidget == null) {
|
if(buttonWidget == null) {
|
||||||
return _listView;
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildFirstLaunchInfo(),
|
||||||
|
_buildDebugInfo(),
|
||||||
|
Expanded(
|
||||||
|
child: _listView
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
_buildFirstLaunchInfo(),
|
||||||
|
_buildDebugInfo(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _listView,
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _listView,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 8.0,
|
||||||
|
),
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 1000
|
||||||
|
),
|
||||||
|
child: buttonWidget
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
|
||||||
height: 8.0,
|
|
||||||
),
|
|
||||||
ConstrainedBox(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
maxWidth: 1000
|
|
||||||
),
|
|
||||||
child: buttonWidget
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildFirstLaunchInfo() => Obx(() {
|
||||||
|
if(!_settingsController.firstRun.value) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 8.0
|
||||||
|
),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: InfoBar(
|
||||||
|
title: Text(translations.welcomeTitle),
|
||||||
|
severity: InfoBarSeverity.warning,
|
||||||
|
isLong: true,
|
||||||
|
content: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Text(translations.welcomeDescription)
|
||||||
|
),
|
||||||
|
action: Button(
|
||||||
|
child: Text(translations.welcomeAction),
|
||||||
|
onPressed: () => startOnboarding(),
|
||||||
|
),
|
||||||
|
onClose: () => _settingsController.firstRun.value = false
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Widget _buildDebugInfo() => Obx(() {
|
||||||
|
if(!_settingsController.debug.value) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
bottom: 8.0
|
||||||
|
),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: InfoBar(
|
||||||
|
title: Text("Debug mode is enabled"),
|
||||||
|
severity: InfoBarSeverity.warning,
|
||||||
|
isLong: true,
|
||||||
|
content: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Text( "• Automatic dll injection is disabled\n"
|
||||||
|
"• The game server cannot start automatically\n"
|
||||||
|
"• The game server runs in a normal window")
|
||||||
|
),
|
||||||
|
onClose: () {
|
||||||
|
_settingsController.debug.value = false;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
ListView get _listView => ListView.builder(
|
ListView get _listView => ListView.builder(
|
||||||
itemCount: settings.length,
|
itemCount: settings.length,
|
||||||
itemBuilder: (context, index) => settings[index],
|
itemBuilder: (context, index) => settings[index],
|
||||||
|
|||||||
@@ -221,11 +221,12 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
content: Obx(() => DropDownButton(
|
content: Obx(() => DropDownButton(
|
||||||
onOpen: () => inDialog = true,
|
onOpen: () => inDialog = true,
|
||||||
onClose: () => inDialog = false,
|
onClose: () => inDialog = false,
|
||||||
leading: Text(_hostingController.type.value.translatedName),
|
leading: Text(_settingsController.debug.value ? GameServerType.window.translatedName : _hostingController.type.value.translatedName),
|
||||||
items: GameServerType.values.map((entry) => MenuFlyoutItem(
|
items: GameServerType.values.map((entry) => MenuFlyoutItem(
|
||||||
text: Text(entry.translatedName),
|
text: Text(entry.translatedName),
|
||||||
onPressed: () => _hostingController.type.value = entry
|
onPressed: () => _hostingController.type.value = entry
|
||||||
)).toList()
|
)).toList(),
|
||||||
|
disabled: _settingsController.debug.value
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
SettingTile(
|
SettingTile(
|
||||||
@@ -317,7 +318,12 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
return createFileSetting(
|
return createFileSetting(
|
||||||
title: translations.settingsServerFileName,
|
title: translations.settingsServerFileName,
|
||||||
description: translations.settingsServerFileDescription,
|
description: translations.settingsServerFileDescription,
|
||||||
controller: _dllController.gameServerDll
|
controller: _dllController.gameServerDll,
|
||||||
|
onReset: () {
|
||||||
|
final path = _dllController.getDefaultDllPath(InjectableDll.reboot);
|
||||||
|
_dllController.gameServerDll.text = path;
|
||||||
|
_dllController.downloadCriticalDllInteractive(path);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
@@ -331,10 +337,29 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
),
|
),
|
||||||
title: Text(translations.settingsServerMirrorName),
|
title: Text(translations.settingsServerMirrorName),
|
||||||
subtitle: Text(translations.settingsServerMirrorDescription),
|
subtitle: Text(translations.settingsServerMirrorDescription),
|
||||||
content: TextFormBox(
|
content: Row(
|
||||||
placeholder: translations.settingsServerMirrorPlaceholder,
|
children: [
|
||||||
controller: _dllController.url,
|
Expanded(
|
||||||
validator: _checkUpdateUrl
|
child: TextFormBox(
|
||||||
|
placeholder: translations.settingsServerMirrorPlaceholder,
|
||||||
|
controller: _dllController.url,
|
||||||
|
validator: _checkUpdateUrl
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Button(
|
||||||
|
style: ButtonStyle(
|
||||||
|
padding: ButtonState.all(EdgeInsets.zero)
|
||||||
|
),
|
||||||
|
onPressed: () => _dllController.url.text = kRebootDownloadUrl,
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: 30,
|
||||||
|
child: Icon(
|
||||||
|
FluentIcons.arrow_reset_24_regular
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
@@ -343,29 +368,50 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
return SettingTile(
|
return SettingTile(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
FluentIcons.timer_24_regular
|
FluentIcons.timer_24_regular
|
||||||
),
|
),
|
||||||
title: Text(translations.settingsServerTimerName),
|
title: Text(translations.settingsServerTimerName),
|
||||||
subtitle: Text(translations.settingsServerTimerSubtitle),
|
subtitle: Text(translations.settingsServerTimerSubtitle),
|
||||||
content: Obx(() => DropDownButton(
|
content: Row(
|
||||||
onOpen: () => inDialog = true,
|
children: [
|
||||||
onClose: () => inDialog = false,
|
Expanded(
|
||||||
leading: Text(_dllController.timer.value.text),
|
child: Obx(() => DropDownButton(
|
||||||
items: UpdateTimer.values.map((entry) => MenuFlyoutItem(
|
onOpen: () => inDialog = true,
|
||||||
text: Text(entry.text),
|
onClose: () => inDialog = false,
|
||||||
onPressed: () {
|
leading: Text(_dllController.timer.value.text),
|
||||||
_dllController.timer.value = entry;
|
items: UpdateTimer.values.map((entry) => MenuFlyoutItem(
|
||||||
_dllController.infoBarEntry?.close();
|
text: Text(entry.text),
|
||||||
_dllController.updateGameServerDll(
|
onPressed: () {
|
||||||
force: true
|
_dllController.timer.value = entry;
|
||||||
);
|
_dllController.infoBarEntry?.close();
|
||||||
}
|
_dllController.updateGameServerDll(
|
||||||
)).toList()
|
force: true
|
||||||
))
|
);
|
||||||
|
}
|
||||||
|
)).toList()
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Button(
|
||||||
|
style: ButtonStyle(
|
||||||
|
padding: ButtonState.all(EdgeInsets.zero)
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
_dllController.updateGameServerDll(force: true);
|
||||||
|
},
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: 30,
|
||||||
|
child: Icon(
|
||||||
|
FluentIcons.arrow_download_24_regular
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}),
|
})
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:reboot_common/common.dart';
|
||||||
import 'package:reboot_launcher/src/controller/dll_controller.dart';
|
import 'package:reboot_launcher/src/controller/dll_controller.dart';
|
||||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||||
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
import 'package:reboot_launcher/src/controller/settings_controller.dart';
|
||||||
@@ -41,48 +42,6 @@ class _PlayPageState extends RebootPageState<PlayPage> {
|
|||||||
final GameController _gameController = Get.find<GameController>();
|
final GameController _gameController = Get.find<GameController>();
|
||||||
final DllController _dllController = Get.find<DllController>();
|
final DllController _dllController = Get.find<DllController>();
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
_buildFirstLaunchInfo(),
|
|
||||||
Expanded(
|
|
||||||
child: super.build(context),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildFirstLaunchInfo() => Obx(() {
|
|
||||||
if(!_settingsController.firstRun.value) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
bottom: 8.0
|
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: InfoBar(
|
|
||||||
title: Text(translations.welcomeTitle),
|
|
||||||
severity: InfoBarSeverity.warning,
|
|
||||||
isLong: true,
|
|
||||||
content: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: Text(translations.welcomeDescription)
|
|
||||||
),
|
|
||||||
action: Button(
|
|
||||||
child: Text(translations.welcomeAction),
|
|
||||||
onPressed: () => startOnboarding(),
|
|
||||||
),
|
|
||||||
onClose: () => _settingsController.firstRun.value = false
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget? get button => LaunchButton(
|
Widget? get button => LaunchButton(
|
||||||
startLabel: translations.launchFortnite,
|
startLabel: translations.launchFortnite,
|
||||||
@@ -110,17 +69,32 @@ class _PlayPageState extends RebootPageState<PlayPage> {
|
|||||||
createFileSetting(
|
createFileSetting(
|
||||||
title: translations.settingsClientConsoleName,
|
title: translations.settingsClientConsoleName,
|
||||||
description: translations.settingsClientConsoleDescription,
|
description: translations.settingsClientConsoleDescription,
|
||||||
controller: _dllController.unrealEngineConsoleDll
|
controller: _dllController.unrealEngineConsoleDll,
|
||||||
|
onReset: () {
|
||||||
|
final path = _dllController.getDefaultDllPath(InjectableDll.console);
|
||||||
|
_dllController.unrealEngineConsoleDll.text = path;
|
||||||
|
_dllController.downloadCriticalDllInteractive(path, force: true);
|
||||||
|
}
|
||||||
),
|
),
|
||||||
createFileSetting(
|
createFileSetting(
|
||||||
title: translations.settingsClientAuthName,
|
title: translations.settingsClientAuthName,
|
||||||
description: translations.settingsClientAuthDescription,
|
description: translations.settingsClientAuthDescription,
|
||||||
controller: _dllController.backendDll
|
controller: _dllController.backendDll,
|
||||||
|
onReset: () {
|
||||||
|
final path = _dllController.getDefaultDllPath(InjectableDll.cobalt);
|
||||||
|
_dllController.backendDll.text = path;
|
||||||
|
_dllController.downloadCriticalDllInteractive(path, force: true);
|
||||||
|
}
|
||||||
),
|
),
|
||||||
createFileSetting(
|
createFileSetting(
|
||||||
title: translations.settingsClientMemoryName,
|
title: translations.settingsClientMemoryName,
|
||||||
description: translations.settingsClientMemoryDescription,
|
description: translations.settingsClientMemoryDescription,
|
||||||
controller: _dllController.memoryLeakDll
|
controller: _dllController.memoryLeakDll,
|
||||||
|
onReset: () {
|
||||||
|
final path = _dllController.getDefaultDllPath(InjectableDll.memory);
|
||||||
|
_dllController.memoryLeakDll.text = path;
|
||||||
|
_dllController.downloadCriticalDllInteractive(path, force: true);
|
||||||
|
}
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
|||||||
List<Widget> get settings => [
|
List<Widget> get settings => [
|
||||||
_language,
|
_language,
|
||||||
_theme,
|
_theme,
|
||||||
_installationDirectory
|
_debugMode,
|
||||||
|
_installationDirectory,
|
||||||
];
|
];
|
||||||
|
|
||||||
SettingTile get _language => SettingTile(
|
SettingTile get _language => SettingTile(
|
||||||
@@ -99,6 +100,29 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
|
|||||||
child: Text(translations.settingsUtilsInstallationDirectoryContent),
|
child: Text(translations.settingsUtilsInstallationDirectoryContent),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SettingTile get _debugMode => SettingTile(
|
||||||
|
icon: Icon(
|
||||||
|
FluentIcons.developer_board_24_regular
|
||||||
|
),
|
||||||
|
title: Text("Debug mode"),
|
||||||
|
subtitle: Text("Whether the launcher should disable automatic features for troubleshooting"),
|
||||||
|
contentWidth: null,
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
_settingsController.debug.value ? translations.on : translations.off
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 16.0
|
||||||
|
),
|
||||||
|
Obx(() => ToggleSwitch(
|
||||||
|
checked: _settingsController.debug.value,
|
||||||
|
onChanged: (value) => _settingsController.debug.value = value
|
||||||
|
))
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension _ThemeModeExtension on ThemeMode {
|
extension _ThemeModeExtension on ThemeMode {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ Future<bool> pingGameServer(String address, {Duration? timeout}) async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final start = DateTime.now();
|
final start = DateTime.now();
|
||||||
var firstTime = true;
|
var firstTime = true;
|
||||||
final split = address.split(":");
|
final split = address.split(":");
|
||||||
|
|||||||
@@ -2,26 +2,55 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
|
||||||
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:reboot_launcher/src/util/translations.dart';
|
import 'package:reboot_launcher/src/util/translations.dart';
|
||||||
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
import 'package:reboot_launcher/src/widget/file_selector.dart';
|
||||||
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
import 'package:reboot_launcher/src/widget/setting_tile.dart';
|
||||||
|
|
||||||
SettingTile createFileSetting({required String title, required String description, required TextEditingController controller}) => SettingTile(
|
SettingTile createFileSetting({required String title, required String description, required TextEditingController controller, required void Function() onReset}) {
|
||||||
|
final obx = RxString(controller.text);
|
||||||
|
controller.addListener(() => obx.value = controller.text);
|
||||||
|
return SettingTile(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
FluentIcons.document_24_regular
|
FluentIcons.document_24_regular
|
||||||
),
|
),
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
subtitle: Text(description),
|
subtitle: Text(description),
|
||||||
content: FileSelector(
|
content: Row(
|
||||||
placeholder: translations.selectPathPlaceholder,
|
children: [
|
||||||
windowTitle: translations.selectPathWindowTitle,
|
Expanded(
|
||||||
controller: controller,
|
child: FileSelector(
|
||||||
validator: _checkDll,
|
placeholder: translations.selectPathPlaceholder,
|
||||||
extension: "dll",
|
windowTitle: translations.selectPathWindowTitle,
|
||||||
folder: false,
|
controller: controller,
|
||||||
validatorMode: AutovalidateMode.always
|
validator: _checkDll,
|
||||||
|
extension: "dll",
|
||||||
|
folder: false,
|
||||||
|
validatorMode: AutovalidateMode.always
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Obx(() => Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: _checkDll(obx.value) == null ? 0.0 : 20.0
|
||||||
|
),
|
||||||
|
child: Button(
|
||||||
|
style: ButtonStyle(
|
||||||
|
padding: ButtonState.all(EdgeInsets.zero)
|
||||||
|
),
|
||||||
|
onPressed: onReset,
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: 30,
|
||||||
|
child: Icon(
|
||||||
|
FluentIcons.arrow_reset_24_regular
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
))
|
||||||
|
],
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String? _checkDll(String? text) {
|
String? _checkDll(String? text) {
|
||||||
if (text == null || text.isEmpty) {
|
if (text == null || text.isEmpty) {
|
||||||
|
|||||||
@@ -41,10 +41,12 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
final HostingController _hostingController = Get.find<HostingController>();
|
final HostingController _hostingController = Get.find<HostingController>();
|
||||||
final BackendController _backendController = Get.find<BackendController>();
|
final BackendController _backendController = Get.find<BackendController>();
|
||||||
final DllController _dllController = Get.find<DllController>();
|
final DllController _dllController = Get.find<DllController>();
|
||||||
|
final SettingsController _settingsController = Get.find<SettingsController>();
|
||||||
|
|
||||||
InfoBarEntry? _gameClientInfoBar;
|
InfoBarEntry? _gameClientInfoBar;
|
||||||
InfoBarEntry? _gameServerInfoBar;
|
InfoBarEntry? _gameServerInfoBar;
|
||||||
CancelableOperation? _operation;
|
CancelableOperation? _operation;
|
||||||
|
CancelableOperation? _pingOperation;
|
||||||
IVirtualDesktop? _virtualDesktop;
|
IVirtualDesktop? _virtualDesktop;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -94,10 +96,6 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
log("[${host ? 'HOST' : 'GAME'}] Checking dlls: ${InjectableDll.values}");
|
log("[${host ? 'HOST' : 'GAME'}] Checking dlls: ${InjectableDll.values}");
|
||||||
for (final injectable in InjectableDll.values) {
|
for (final injectable in InjectableDll.values) {
|
||||||
if(await _getDllFileOrStop(injectable, host) == null) {
|
if(await _getDllFileOrStop(injectable, host) == null) {
|
||||||
_onStop(
|
|
||||||
reason: _StopReason.missingCustomDllError,
|
|
||||||
error: injectable.name,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +121,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Backend works");
|
log("[${host ? 'HOST' : 'GAME'}] Backend works");
|
||||||
final serverType = _hostingController.type.value;
|
final serverType = _settingsController.debug.value ? GameServerType.window : _hostingController.type.value;
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Implicit game server metadata: headless($serverType)");
|
log("[${host ? 'HOST' : 'GAME'}] Implicit game server metadata: headless($serverType)");
|
||||||
final linkedHostingInstance = await _startMatchMakingServer(version, host, serverType, false);
|
final linkedHostingInstance = await _startMatchMakingServer(version, host, serverType, false);
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Implicit game server result: $linkedHostingInstance");
|
log("[${host ? 'HOST' : 'GAME'}] Implicit game server result: $linkedHostingInstance");
|
||||||
@@ -139,6 +137,12 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
}else {
|
}else {
|
||||||
_showLaunchingGameServerWidget();
|
_showLaunchingGameServerWidget();
|
||||||
}
|
}
|
||||||
|
} on ProcessException catch (exception, stackTrace) {
|
||||||
|
_onStop(
|
||||||
|
reason: _StopReason.corruptedVersionError,
|
||||||
|
error: exception.toString(),
|
||||||
|
stackTrace: stackTrace
|
||||||
|
);
|
||||||
} catch (exception, stackTrace) {
|
} catch (exception, stackTrace) {
|
||||||
_onStop(
|
_onStop(
|
||||||
reason: _StopReason.unknownError,
|
reason: _StopReason.unknownError,
|
||||||
@@ -155,6 +159,11 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_settingsController.debug.value) {
|
||||||
|
log("[${host ? 'HOST' : 'GAME'}] The user is on debug mode, not asking for auto server");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if(!forceLinkedHosting && _backendController.type.value == ServerType.embedded && !isLocalHost(_backendController.gameServerAddress.text)) {
|
if(!forceLinkedHosting && _backendController.type.value == ServerType.embedded && !isLocalHost(_backendController.gameServerAddress.text)) {
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Backend is not set to embedded and/or not pointing to the local game server");
|
log("[${host ? 'HOST' : 'GAME'}] Backend is not set to embedded and/or not pointing to the local game server");
|
||||||
return null;
|
return null;
|
||||||
@@ -271,9 +280,17 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
line: line,
|
line: line,
|
||||||
host: host,
|
host: host,
|
||||||
onShutdown: () => _onStop(reason: _StopReason.normal),
|
onShutdown: () => _onStop(reason: _StopReason.normal),
|
||||||
onTokenError: () => _onStop(reason: _StopReason.tokenError),
|
onTokenError: () {
|
||||||
|
if(_settingsController.debug.value) {
|
||||||
|
log("[PROCESS] Ignoring token error because debug mode is on");
|
||||||
|
}else {
|
||||||
|
_onStop(reason: _StopReason.tokenError);
|
||||||
|
}
|
||||||
|
},
|
||||||
onBuildCorrupted: () {
|
onBuildCorrupted: () {
|
||||||
if(instance?.launched == false) {
|
if(instance == null) {
|
||||||
|
return;
|
||||||
|
}else if(!instance.launched) {
|
||||||
_onStop(reason: _StopReason.corruptedVersionError);
|
_onStop(reason: _StopReason.corruptedVersionError);
|
||||||
}else {
|
}else {
|
||||||
_onStop(reason: _StopReason.crash);
|
_onStop(reason: _StopReason.crash);
|
||||||
@@ -432,10 +449,11 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
duration: null
|
duration: null
|
||||||
);
|
);
|
||||||
final gameServerPort = _dllController.gameServerPort.text;
|
final gameServerPort = _dllController.gameServerPort.text;
|
||||||
final localPingResult = await pingGameServer(
|
this._pingOperation = await CancelableOperation.fromFuture(pingGameServer(
|
||||||
"127.0.0.1:$gameServerPort",
|
"127.0.0.1:$gameServerPort",
|
||||||
timeout: const Duration(minutes: 2)
|
timeout: const Duration(minutes: 2)
|
||||||
);
|
));
|
||||||
|
final localPingResult = (await _pingOperation?.value) ?? false;
|
||||||
_gameServerInfoBar?.close();
|
_gameServerInfoBar?.close();
|
||||||
if (!localPingResult) {
|
if (!localPingResult) {
|
||||||
showRebootInfoBar(
|
showRebootInfoBar(
|
||||||
@@ -478,16 +496,18 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
duration: null
|
duration: null
|
||||||
);
|
);
|
||||||
final publicIp = await Ipify.ipv4();
|
final publicIp = await Ipify.ipv4();
|
||||||
final externalResult = await pingGameServer("$publicIp:$gameServerPort");
|
this._pingOperation = CancelableOperation.fromFuture(pingGameServer("$publicIp:$gameServerPort"));
|
||||||
|
final externalResult = (await _pingOperation?.value) ?? false;
|
||||||
if (externalResult) {
|
if (externalResult) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gameServerInfoBar?.close();
|
_gameServerInfoBar?.close();
|
||||||
final future = pingGameServer(
|
this._pingOperation = CancelableOperation.fromFuture(pingGameServer(
|
||||||
"$publicIp:$gameServerPort",
|
"$publicIp:$gameServerPort",
|
||||||
timeout: const Duration(days: 365)
|
timeout: const Duration(days: 365)
|
||||||
);
|
));
|
||||||
|
final future = await _pingOperation?.value ?? false;
|
||||||
_gameServerInfoBar = showRebootInfoBar(
|
_gameServerInfoBar = showRebootInfoBar(
|
||||||
translations.checkGameServerFixMessage(gameServerPort),
|
translations.checkGameServerFixMessage(gameServerPort),
|
||||||
action: Button(
|
action: Button(
|
||||||
@@ -506,6 +526,8 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
|
|
||||||
Future<void> _onStop({required _StopReason reason, bool? host, String? error, StackTrace? stackTrace}) async {
|
Future<void> _onStop({required _StopReason reason, bool? host, String? error, StackTrace? stackTrace}) async {
|
||||||
if(host == null) {
|
if(host == null) {
|
||||||
|
await _pingOperation?.cancel();
|
||||||
|
_pingOperation = null;
|
||||||
await _operation?.cancel();
|
await _operation?.cancel();
|
||||||
_operation = null;
|
_operation = null;
|
||||||
_backendController.cancelInteractive();
|
_backendController.cancelInteractive();
|
||||||
@@ -513,6 +535,10 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
|
|
||||||
host = host ?? widget.host;
|
host = host ?? widget.host;
|
||||||
final instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
final instance = host ? _hostingController.instance.value : _gameController.instance.value;
|
||||||
|
if(instance == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(host){
|
if(host){
|
||||||
_hostingController.instance.value = null;
|
_hostingController.instance.value = null;
|
||||||
}else {
|
}else {
|
||||||
@@ -534,19 +560,17 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
_hostingController.discardServer();
|
_hostingController.discardServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(instance != null) {
|
if(reason == _StopReason.normal) {
|
||||||
if(reason == _StopReason.normal) {
|
instance.launched = true;
|
||||||
instance.launched = true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
instance.kill();
|
instance.kill();
|
||||||
final child = instance.child;
|
final child = instance.child;
|
||||||
if(child != null) {
|
if(child != null) {
|
||||||
await _onStop(
|
await _onStop(
|
||||||
reason: reason,
|
reason: reason,
|
||||||
host: child.serverType != null
|
host: child.serverType != null
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_setStarted(host, false);
|
_setStarted(host, false);
|
||||||
@@ -578,7 +602,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case _StopReason.exitCode:
|
case _StopReason.exitCode:
|
||||||
if(instance != null && !instance.launched) {
|
if(!instance.launched) {
|
||||||
showRebootInfoBar(
|
showRebootInfoBar(
|
||||||
translations.corruptedVersionError,
|
translations.corruptedVersionError,
|
||||||
severity: InfoBarSeverity.error,
|
severity: InfoBarSeverity.error,
|
||||||
@@ -614,7 +638,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
case _StopReason.tokenError:
|
case _StopReason.tokenError:
|
||||||
_backendController.stop();
|
_backendController.stop();
|
||||||
showRebootInfoBar(
|
showRebootInfoBar(
|
||||||
translations.tokenError(instance?.injectedDlls.map((element) => element.name).join(", ") ?? translations.none),
|
translations.tokenError(instance.injectedDlls.map((element) => element.name).join(", ")),
|
||||||
severity: InfoBarSeverity.error,
|
severity: InfoBarSeverity.error,
|
||||||
duration: infoBarLongDuration,
|
duration: infoBarLongDuration,
|
||||||
action: Button(
|
action: Button(
|
||||||
@@ -663,6 +687,10 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log("[${hosting ? 'HOST' : 'GAME'}] Trying to inject ${injectable.name}...");
|
log("[${hosting ? 'HOST' : 'GAME'}] Trying to inject ${injectable.name}...");
|
||||||
|
if(_settingsController.debug.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await injectDll(gameProcess, dllPath);
|
await injectDll(gameProcess, dllPath);
|
||||||
instance.injectedDlls.add(injectable);
|
instance.injectedDlls.add(injectable);
|
||||||
log("[${hosting ? 'HOST' : 'GAME'}] Injected ${injectable.name}");
|
log("[${hosting ? 'HOST' : 'GAME'}] Injected ${injectable.name}");
|
||||||
@@ -687,13 +715,17 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Path doesn't exist");
|
log("[${host ? 'HOST' : 'GAME'}] Path doesn't exist");
|
||||||
if(customDll || isRetry) {
|
if(customDll) {
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Custom dll -> no recovery");
|
log("[${host ? 'HOST' : 'GAME'}] Custom dll -> no recovery");
|
||||||
|
_onStop(
|
||||||
|
reason: _StopReason.missingCustomDllError,
|
||||||
|
error: injectable.name,
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Path does not exist, downloading critical dll again...");
|
log("[${host ? 'HOST' : 'GAME'}] Path does not exist, downloading critical dll again...");
|
||||||
await _dllController.downloadCriticalDllInteractive(file.path);
|
await _dllController.downloadCriticalDllInteractive(file.path, force: true);
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Downloaded dll again, retrying check...");
|
log("[${host ? 'HOST' : 'GAME'}] Downloaded dll again, retrying check...");
|
||||||
return _getDllFileOrStop(injectable, host, true);
|
return _getDllFileOrStop(injectable, host, true);
|
||||||
}
|
}
|
||||||
@@ -710,7 +742,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
loading: true,
|
loading: true,
|
||||||
duration: null,
|
duration: null,
|
||||||
action: Obx(() {
|
action: Obx(() {
|
||||||
if(_hostingController.started.value || linkedHosting) {
|
if(_settingsController.debug.value || _hostingController.started.value || linkedHosting) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: reboot_launcher
|
name: reboot_launcher
|
||||||
description: Graphical User Interface for Project Reboot
|
description: Graphical User Interface for Project Reboot
|
||||||
version: "9.2.5"
|
version: "9.2.6"
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user