mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 11:12:23 +01:00
Release 9.2.3
This commit is contained in:
@@ -15,10 +15,16 @@ final Semaphore _semaphore = Semaphore();
|
|||||||
String? _lastIp;
|
String? _lastIp;
|
||||||
String? _lastPort;
|
String? _lastPort;
|
||||||
|
|
||||||
Future<Process> startEmbeddedBackend(bool detached) async => startProcess(
|
Future<Process> startEmbeddedBackend(bool detached) async {
|
||||||
|
final process = await startProcess(
|
||||||
executable: backendStartExecutable,
|
executable: backendStartExecutable,
|
||||||
window: detached,
|
window: detached,
|
||||||
);
|
);
|
||||||
|
process.stdOutput.listen((message) => log("[BACKEND] Message: $message"));
|
||||||
|
process.stdError.listen((error) => log("[BACKEND] Error: $error"));
|
||||||
|
process.exitCode.then((exitCode) => log("[BACKEND] Exit code: $exitCode"));
|
||||||
|
return process;
|
||||||
|
}
|
||||||
|
|
||||||
Future<HttpServer> startRemoteBackendProxy(Uri uri) async => await serve(proxyHandler(uri), kDefaultBackendHost, kDefaultBackendPort);
|
Future<HttpServer> startRemoteBackendProxy(Uri uri) async => await serve(proxyHandler(uri), kDefaultBackendHost, kDefaultBackendPort);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ final File launcherLogFile = _createLoggingFile();
|
|||||||
final Semaphore _semaphore = Semaphore(1);
|
final Semaphore _semaphore = Semaphore(1);
|
||||||
|
|
||||||
File _createLoggingFile() {
|
File _createLoggingFile() {
|
||||||
final file = File("${logsDirectory.path}\\launcher.log");
|
final file = File("${installationDirectory.path}\\launcher.log");
|
||||||
file.parent.createSync(recursive: true);
|
file.parent.createSync(recursive: true);
|
||||||
if(file.existsSync()) {
|
if(file.existsSync()) {
|
||||||
file.deleteSync();
|
file.deleteSync();
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ Directory get assetsDirectory {
|
|||||||
return installationDirectory;
|
return installationDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory get logsDirectory =>
|
|
||||||
Directory("${installationDirectory.path}\\logs");
|
|
||||||
|
|
||||||
Directory get settingsDirectory =>
|
Directory get settingsDirectory =>
|
||||||
Directory("${installationDirectory.path}\\settings");
|
Directory("${installationDirectory.path}\\settings");
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// ignore_for_file: non_constant_identifier_names
|
// ignore_for_file: non_constant_identifier_names
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:collection';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
@@ -9,6 +10,7 @@ import 'dart:math';
|
|||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:reboot_common/common.dart';
|
import 'package:reboot_common/common.dart';
|
||||||
|
import 'package:reboot_common/src/util/log.dart';
|
||||||
import 'package:sync/semaphore.dart';
|
import 'package:sync/semaphore.dart';
|
||||||
import 'package:win32/win32.dart';
|
import 'package:win32/win32.dart';
|
||||||
|
|
||||||
@@ -105,53 +107,45 @@ Future<bool> startElevatedProcess({required String executable, required String a
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Process> startProcess({required File executable, List<String>? args, bool useTempBatch = true, bool window = false, String? name, Map<String, String>? environment}) async {
|
Future<Process> startProcess({required File executable, List<String>? args, bool useTempBatch = true, bool window = false, String? name, Map<String, String>? environment}) async {
|
||||||
|
log("[PROCESS] Starting process on ${executable.path} with $args (useTempBatch: $useTempBatch, window: $window, name: $name, environment: $environment)");
|
||||||
final argsOrEmpty = args ?? [];
|
final argsOrEmpty = args ?? [];
|
||||||
|
final workingDirectory = _getWorkingDirectory(executable);
|
||||||
if(useTempBatch) {
|
if(useTempBatch) {
|
||||||
final tempScriptDirectory = await tempDirectory.createTemp("reboot_launcher_process");
|
final tempScriptDirectory = await tempDirectory.createTemp("reboot_launcher_process");
|
||||||
final tempScriptFile = File("${tempScriptDirectory.path}/process.bat");
|
final tempScriptFile = File("${tempScriptDirectory.path}\\process.bat");
|
||||||
final command = window ? 'cmd.exe /k ""${executable.path}" ${argsOrEmpty.join(" ")}"' : '"${executable.path}" ${argsOrEmpty.join(" ")}';
|
final command = window ? 'cmd.exe /k ""${executable.path}" ${argsOrEmpty.join(" ")}"' : '"${executable.path}" ${argsOrEmpty.join(" ")}';
|
||||||
await tempScriptFile.writeAsString(command, flush: true);
|
await tempScriptFile.writeAsString(command, flush: true);
|
||||||
final process = await Process.start(
|
final process = await Process.start(
|
||||||
tempScriptFile.path,
|
tempScriptFile.path,
|
||||||
[],
|
[],
|
||||||
workingDirectory: executable.parent.path,
|
workingDirectory: workingDirectory,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
mode: window ? ProcessStartMode.detachedWithStdio : ProcessStartMode.normal,
|
mode: window ? ProcessStartMode.detachedWithStdio : ProcessStartMode.normal,
|
||||||
runInShell: window
|
runInShell: window
|
||||||
);
|
);
|
||||||
return _withLogger(name, executable, process, window);
|
return _ExtendedProcess(process, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
final process = await Process.start(
|
final process = await Process.start(
|
||||||
executable.path,
|
executable.path,
|
||||||
args ?? [],
|
args ?? [],
|
||||||
workingDirectory: executable.parent.path,
|
workingDirectory: workingDirectory,
|
||||||
mode: window ? ProcessStartMode.detachedWithStdio : ProcessStartMode.normal,
|
mode: window ? ProcessStartMode.detachedWithStdio : ProcessStartMode.normal,
|
||||||
runInShell: window
|
runInShell: window
|
||||||
);
|
);
|
||||||
return _withLogger(name, executable, process, window);
|
return _ExtendedProcess(process, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ExtendedProcess _withLogger(String? name, File executable, Process process, bool window) {
|
String? _getWorkingDirectory(File executable) {
|
||||||
final extendedProcess = _ExtendedProcess(process, true);
|
try {
|
||||||
final loggingFile = File("${logsDirectory.path}\\${name ?? path.basenameWithoutExtension(executable.path)}-${DateTime.now().millisecondsSinceEpoch}.log");
|
log("[PROCESS] Calculating working directory for $executable");
|
||||||
loggingFile.parent.createSync(recursive: true);
|
final workingDirectory = executable.parent.resolveSymbolicLinksSync();
|
||||||
if(loggingFile.existsSync()) {
|
log("[PROCESS] Using working directory: $workingDirectory");
|
||||||
loggingFile.deleteSync();
|
return workingDirectory;
|
||||||
|
}catch(error) {
|
||||||
|
log("[PROCESS] Cannot infer working directory: $error");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final semaphore = Semaphore(1);
|
|
||||||
void logEvent(String event) async {
|
|
||||||
await semaphore.acquire();
|
|
||||||
await loggingFile.writeAsString("$event\n", mode: FileMode.append, flush: true);
|
|
||||||
semaphore.release();
|
|
||||||
}
|
|
||||||
extendedProcess.stdOutput.listen(logEvent);
|
|
||||||
extendedProcess.stdError.listen(logEvent);
|
|
||||||
if(!window) {
|
|
||||||
extendedProcess.exitCode.then((value) => logEvent("Process terminated with exit code: $value\n"));
|
|
||||||
}
|
|
||||||
return extendedProcess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final _NtResumeProcess = _ntdll.lookupFunction<Int32 Function(IntPtr hWnd),
|
final _NtResumeProcess = _ntdll.lookupFunction<Int32 Function(IntPtr hWnd),
|
||||||
@@ -203,47 +197,61 @@ Future<bool> watchProcess(int pid) async {
|
|||||||
return await completer.future;
|
return await completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Template
|
List<String> createRebootArgs(String username, String password, bool host, GameServerType hostType, bool logging, String additionalArgs) {
|
||||||
List<String> createRebootArgs(String username, String password, bool host, GameServerType hostType, bool log, String additionalArgs) {
|
log("[PROCESS] Generating reboot args");
|
||||||
if(password.isEmpty) {
|
if(password.isEmpty) {
|
||||||
username = '${_parseUsername(username, host)}@projectreboot.dev';
|
username = '${_parseUsername(username, host)}@projectreboot.dev';
|
||||||
}
|
}
|
||||||
|
|
||||||
password = password.isNotEmpty ? password : "Rebooted";
|
password = password.isNotEmpty ? password : "Rebooted";
|
||||||
final args = [
|
final args = LinkedHashMap<String, String>(
|
||||||
"-epicapp=Fortnite",
|
equals: (a, b) => a.toUpperCase() == b.toUpperCase(),
|
||||||
"-epicenv=Prod",
|
hashCode: (a) => a.toUpperCase().hashCode
|
||||||
"-epiclocale=en-us",
|
);
|
||||||
"-epicportal",
|
args.addAll({
|
||||||
"-skippatchcheck",
|
"-epicapp": "Fortnite",
|
||||||
"-nobe",
|
"-epicenv": "Prod",
|
||||||
"-fromfl=eac",
|
"-epiclocale": "en-us",
|
||||||
"-fltoken=3db3ba5dcbd2e16703f3978d",
|
"-epicportal": "",
|
||||||
"-caldera=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50X2lkIjoiYmU5ZGE1YzJmYmVhNDQwN2IyZjQwZWJhYWQ4NTlhZDQiLCJnZW5lcmF0ZWQiOjE2Mzg3MTcyNzgsImNhbGRlcmFHdWlkIjoiMzgxMGI4NjMtMmE2NS00NDU3LTliNTgtNGRhYjNiNDgyYTg2IiwiYWNQcm92aWRlciI6IkVhc3lBbnRpQ2hlYXQiLCJub3RlcyI6IiIsImZhbGxiYWNrIjpmYWxzZX0.VAWQB67RTxhiWOxx7DBjnzDnXyyEnX7OljJm-j2d88G_WgwQ9wrE6lwMEHZHjBd1ISJdUO1UVUqkfLdU5nofBQ",
|
"-skippatchcheck": "",
|
||||||
"-AUTH_LOGIN=$username",
|
"-nobe": "",
|
||||||
"-AUTH_PASSWORD=${password.isNotEmpty ? password : "Rebooted"}",
|
"-fromfl": "eac",
|
||||||
"-AUTH_TYPE=epic"
|
"-fltoken": "3db3ba5dcbd2e16703f3978d",
|
||||||
];
|
"-caldera": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50X2lkIjoiYmU5ZGE1YzJmYmVhNDQwN2IyZjQwZWJhYWQ4NTlhZDQiLCJnZW5lcmF0ZWQiOjE2Mzg3MTcyNzgsImNhbGRlcmFHdWlkIjoiMzgxMGI4NjMtMmE2NS00NDU3LTliNTgtNGRhYjNiNDgyYTg2IiwiYWNQcm92aWRlciI6IkVhc3lBbnRpQ2hlYXQiLCJub3RlcyI6IiIsImZhbGxiYWNrIjpmYWxzZX0.VAWQB67RTxhiWOxx7DBjnzDnXyyEnX7OljJm-j2d88G_WgwQ9wrE6lwMEHZHjBd1ISJdUO1UVUqkfLdU5nofBQ",
|
||||||
|
"-AUTH_LOGIN": username,
|
||||||
|
"-AUTH_PASSWORD": password.isNotEmpty ? password : "Rebooted",
|
||||||
|
"-AUTH_TYPE": "epic"
|
||||||
|
});
|
||||||
|
|
||||||
if(log) {
|
if(logging) {
|
||||||
args.add("-log");
|
args["-log"] = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(host) {
|
if(host) {
|
||||||
args.addAll([
|
args["-nosplash"] = "";
|
||||||
"-nosplash",
|
args["-nosound"] = "";
|
||||||
"-nosound"
|
|
||||||
]);
|
|
||||||
if(hostType == GameServerType.headless){
|
if(hostType == GameServerType.headless){
|
||||||
args.add("-nullrhi");
|
args["-nullrhi"] = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(additionalArgs.isNotEmpty){
|
log("[PROCESS] Default args: $args");
|
||||||
args.addAll(additionalArgs.split(" "));
|
log("[PROCESS] Adding custom args: $additionalArgs");
|
||||||
|
for(final additionalArg in additionalArgs.split(" ")) {
|
||||||
|
log("[PROCESS] Processing custom arg: $additionalArg");
|
||||||
|
final separatorIndex = additionalArg.indexOf("=");
|
||||||
|
final argName = separatorIndex == -1 ? additionalArg : additionalArg.substring(0, separatorIndex);
|
||||||
|
log("[PROCESS] Custom arg key: $argName");
|
||||||
|
final argValue = separatorIndex == -1 || separatorIndex + 1 >= additionalArg.length ? "" : additionalArg.substring(separatorIndex + 1);
|
||||||
|
log("[PROCESS] Custom arg value: $argValue");
|
||||||
|
args[argName] = argValue;
|
||||||
|
log("[PROCESS] Updated args: $args");
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
log("[PROCESS] Final args result: $args");
|
||||||
|
return args.entries
|
||||||
|
.map((entry) => entry.value.isEmpty ? entry.key : "${entry.key}=${entry.value}")
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleGameOutput({
|
void handleGameOutput({
|
||||||
@@ -257,16 +265,22 @@ void handleGameOutput({
|
|||||||
required void Function() onBuildCorrupted,
|
required void Function() onBuildCorrupted,
|
||||||
}) {
|
}) {
|
||||||
if (line.contains(kShutdownLine)) {
|
if (line.contains(kShutdownLine)) {
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected shutdown: $line");
|
||||||
onShutdown();
|
onShutdown();
|
||||||
}else if(kCorruptedBuildErrors.any((element) => line.contains(element))){
|
}else if(kCorruptedBuildErrors.any((element) => line.contains(element))){
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected corrupt build: $line");
|
||||||
onBuildCorrupted();
|
onBuildCorrupted();
|
||||||
}else if(kCannotConnectErrors.any((element) => line.contains(element))){
|
}else if(kCannotConnectErrors.any((element) => line.contains(element))){
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected cannot connect error: $line");
|
||||||
onTokenError();
|
onTokenError();
|
||||||
}else if(kLoggedInLines.every((entry) => line.contains(entry))) {
|
}else if(kLoggedInLines.every((entry) => line.contains(entry))) {
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected logged in: $line");
|
||||||
onLoggedIn();
|
onLoggedIn();
|
||||||
}else if(line.contains(kGameFinishedLine) && host) {
|
}else if(line.contains(kGameFinishedLine) && host) {
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected match end: $line");
|
||||||
onMatchEnd();
|
onMatchEnd();
|
||||||
}else if(line.contains(kDisplayInitializedLine) && host) {
|
}else if(line.contains(kDisplayInitializedLine) && host) {
|
||||||
|
log("[FORTNITE_OUTPUT_HANDLER] Detected display attach: $line");
|
||||||
onDisplayAttached();
|
onDisplayAttached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
"settingsClientDescription": "Configure the internal files used by the launcher for Fortnite",
|
"settingsClientDescription": "Configure the internal files used by the launcher for Fortnite",
|
||||||
"settingsClientOptionsName": "Options",
|
"settingsClientOptionsName": "Options",
|
||||||
"settingsClientOptionsDescription": "Configure additional options for Fortnite",
|
"settingsClientOptionsDescription": "Configure additional options for Fortnite",
|
||||||
"settingsClientConsoleName": "Unreal engine console",
|
"settingsClientConsoleName": "Unreal engine patcher",
|
||||||
"settingsClientConsoleDescription": "Unlocks the Unreal Engine Console",
|
"settingsClientConsoleDescription": "Unlocks the Unreal Engine Console",
|
||||||
"settingsClientConsoleKeyName": "Unreal engine console key",
|
"settingsClientConsoleKeyName": "Unreal engine console key",
|
||||||
"settingsClientConsoleKeyDescription": "The keyboard key used to open the Unreal Engine console",
|
"settingsClientConsoleKeyDescription": "The keyboard key used to open the Unreal Engine console",
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
"settingsClientMemoryName": "Memory patcher",
|
"settingsClientMemoryName": "Memory patcher",
|
||||||
"settingsClientMemoryDescription": "Prevents the client from crashing because of a memory leak",
|
"settingsClientMemoryDescription": "Prevents the client from crashing because of a memory leak",
|
||||||
"settingsClientArgsName": "Custom launch arguments",
|
"settingsClientArgsName": "Custom launch arguments",
|
||||||
"settingsClientArgsDescription": "Additional arguments to use when launching the game",
|
"settingsClientArgsDescription": "Additional arguments to use when launching Fortnite",
|
||||||
"settingsClientArgsPlaceholder": "Arguments...",
|
"settingsClientArgsPlaceholder": "Arguments...",
|
||||||
"settingsServerName": "Internal files",
|
"settingsServerName": "Internal files",
|
||||||
"settingsServerSubtitle": "Configure the internal files used by the launcher for the game server",
|
"settingsServerSubtitle": "Configure the internal files used by the launcher for the game server",
|
||||||
@@ -156,6 +156,7 @@
|
|||||||
"launchingGameClientAndServer": "Launching the game client and server...",
|
"launchingGameClientAndServer": "Launching the game client and server...",
|
||||||
"startGameServer": "Start a game server",
|
"startGameServer": "Start a game server",
|
||||||
"usernameOrEmail": "Username/Email",
|
"usernameOrEmail": "Username/Email",
|
||||||
|
"invalidEmail": "Invalid email",
|
||||||
"usernameOrEmailPlaceholder": "Type your username or email",
|
"usernameOrEmailPlaceholder": "Type your username or email",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"passwordPlaceholder": "Type your password, if you want to use one",
|
"passwordPlaceholder": "Type your password, if you want to use one",
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ class GameController extends GetxController {
|
|||||||
password = TextEditingController(text: _storage?.read("password") ?? "");
|
password = TextEditingController(text: _storage?.read("password") ?? "");
|
||||||
password.addListener(() => _storage?.write("password", password.text));
|
password.addListener(() => _storage?.write("password", password.text));
|
||||||
customLaunchArgs = TextEditingController(text: _storage?.read("custom_launch_args") ?? "");
|
customLaunchArgs = TextEditingController(text: _storage?.read("custom_launch_args") ?? "");
|
||||||
customLaunchArgs.addListener(() =>
|
customLaunchArgs.addListener(() => _storage?.write("custom_launch_args", customLaunchArgs.text));
|
||||||
_storage?.write("custom_launch_args", customLaunchArgs.text));
|
|
||||||
started = RxBool(false);
|
started = RxBool(false);
|
||||||
instance = Rxn();
|
instance = Rxn();
|
||||||
consoleKey = Rx(_readConsoleKey());
|
consoleKey = Rx(_readConsoleKey());
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class HostingController extends GetxController {
|
|||||||
late final RxBool published;
|
late final RxBool published;
|
||||||
late final Rxn<GameInstance> instance;
|
late final Rxn<GameInstance> instance;
|
||||||
late final Rxn<Set<FortniteServer>> servers;
|
late final Rxn<Set<FortniteServer>> servers;
|
||||||
|
late final TextEditingController customLaunchArgs;
|
||||||
late final Semaphore _semaphore;
|
late final Semaphore _semaphore;
|
||||||
|
|
||||||
HostingController() {
|
HostingController() {
|
||||||
@@ -62,6 +63,8 @@ class HostingController extends GetxController {
|
|||||||
servers.value = event;
|
servers.value = event;
|
||||||
published.value = event.any((element) => element.id == uuid);
|
published.value = event.any((element) => element.id == uuid);
|
||||||
});
|
});
|
||||||
|
customLaunchArgs = TextEditingController(text: _storage?.read("custom_launch_args") ?? "");
|
||||||
|
customLaunchArgs.addListener(() => _storage?.write("custom_launch_args", customLaunchArgs.text));
|
||||||
_semaphore = Semaphore();
|
_semaphore = Semaphore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:email_validator/email_validator.dart';
|
||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
import 'package:flutter/material.dart' show Icons;
|
import 'package:flutter/material.dart' show Icons;
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -23,6 +24,17 @@ Future<bool> showProfileForm(BuildContext context) async{
|
|||||||
label: translations.usernameOrEmail,
|
label: translations.usernameOrEmail,
|
||||||
child: TextFormBox(
|
child: TextFormBox(
|
||||||
placeholder: translations.usernameOrEmailPlaceholder,
|
placeholder: translations.usernameOrEmailPlaceholder,
|
||||||
|
validator: (text) {
|
||||||
|
if(_gameController.password.text.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(EmailValidator.validate(_gameController.username.text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return translations.invalidEmail;
|
||||||
|
},
|
||||||
controller: _gameController.username,
|
controller: _gameController.username,
|
||||||
autovalidateMode: AutovalidateMode.always,
|
autovalidateMode: AutovalidateMode.always,
|
||||||
enableSuggestions: true,
|
enableSuggestions: true,
|
||||||
|
|||||||
@@ -199,6 +199,17 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
title: Text(translations.settingsServerOptionsName),
|
title: Text(translations.settingsServerOptionsName),
|
||||||
subtitle: Text(translations.settingsServerOptionsSubtitle),
|
subtitle: Text(translations.settingsServerOptionsSubtitle),
|
||||||
children: [
|
children: [
|
||||||
|
SettingTile(
|
||||||
|
icon: Icon(
|
||||||
|
FluentIcons.options_24_regular
|
||||||
|
),
|
||||||
|
title: Text(translations.settingsClientArgsName),
|
||||||
|
subtitle: Text(translations.settingsClientArgsDescription),
|
||||||
|
content: TextFormBox(
|
||||||
|
placeholder: translations.settingsClientArgsPlaceholder,
|
||||||
|
controller: _hostingController.customLaunchArgs,
|
||||||
|
)
|
||||||
|
),
|
||||||
SettingTile(
|
SettingTile(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
FluentIcons.window_console_20_regular
|
FluentIcons.window_console_20_regular
|
||||||
@@ -253,7 +264,7 @@ class _HostingPageState extends RebootPageState<HostPage> {
|
|||||||
FilteringTextInputFormatter.digitsOnly
|
FilteringTextInputFormatter.digitsOnly
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ class _LaunchButtonState extends State<LaunchButton> {
|
|||||||
host,
|
host,
|
||||||
hostType,
|
hostType,
|
||||||
false,
|
false,
|
||||||
""
|
host ? _hostingController.customLaunchArgs.text : _gameController.customLaunchArgs.text
|
||||||
);
|
);
|
||||||
log("[${host ? 'HOST' : 'GAME'}] Generated game args: ${gameArgs.join(" ")}");
|
log("[${host ? 'HOST' : 'GAME'}] Generated game args: ${gameArgs.join(" ")}");
|
||||||
final gameProcess = await startProcess(
|
final gameProcess = await startProcess(
|
||||||
|
|||||||
@@ -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.2"
|
version: "9.2.3"
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
@@ -74,6 +74,9 @@ dependencies:
|
|||||||
package_info_plus: ^8.0.0
|
package_info_plus: ^8.0.0
|
||||||
version: ^3.0.2
|
version: ^3.0.2
|
||||||
|
|
||||||
|
# Validate profile
|
||||||
|
email_validator: ^3.0.0
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
xml: ^6.3.0
|
xml: ^6.3.0
|
||||||
http: ^0.13.5
|
http: ^0.13.5
|
||||||
@@ -98,4 +101,9 @@ flutter:
|
|||||||
- assets/backend/profiles/
|
- assets/backend/profiles/
|
||||||
- assets/backend/public/
|
- assets/backend/public/
|
||||||
- assets/backend/responses/
|
- assets/backend/responses/
|
||||||
|
- assets/backend/responses/Athena/
|
||||||
|
- assets/backend/responses/Athena/BattlePass/
|
||||||
|
- assets/backend/responses/Athena/Discovery/
|
||||||
|
- assets/backend/responses/Campaign/
|
||||||
|
- assets/backend/responses/CloudDir/
|
||||||
- assets/build/
|
- assets/build/
|
||||||
Reference in New Issue
Block a user