diff --git a/cli/lib/src/game.dart b/cli/lib/src/game.dart index d0acf40..9703991 100644 --- a/cli/lib/src/game.dart +++ b/cli/lib/src/game.dart @@ -70,7 +70,7 @@ void _onGameOutput(String line, String dll, bool hosting, bool verbose) { _injectOrShowError("console.dll"); } - _injectOrShowError("memoryleak.dll"); + _injectOrShowError("memoryFix.dll"); } } @@ -87,12 +87,12 @@ Future _injectOrShowError(String binary, [bool locate = true]) async { try { stdout.writeln("Injecting $binary..."); - var dll = locate ? File("${assetsDirectory.path}\\dlls\\$binary") : File(binary); + var dll = locate ? File("${dllsDirectory.path}\\$binary") : File(binary); if(!dll.existsSync()){ throw Exception("Cannot inject $dll: missing file"); } - await injectDll(_gameProcess!.pid, dll.path); + await injectDll(_gameProcess!.pid, dll); } catch (exception) { throw Exception("Cannot inject binary: $binary"); } diff --git a/cli/lib/src/reboot.dart b/cli/lib/src/reboot.dart index 89a9999..c7538e3 100644 --- a/cli/lib/src/reboot.dart +++ b/cli/lib/src/reboot.dart @@ -7,12 +7,12 @@ import 'package:reboot_common/common.dart'; // TODO: Use github const String _baseDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968021373169674/cobalt.dll"; const String _consoleDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968095033524234/console.dll"; -const String _memoryFixDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968141556756581/memoryleak.dll"; +const String _memoryFixDownload = "https://cdn.discordapp.com/attachments/1095351875961901057/1110968141556756581/memoryFix.dll"; const String _embeddedConfigDownload = "https://cdn.discordapp.com/attachments/1026121175878881290/1040679319351066644/embedded.zip"; Future downloadRequiredDLLs() async { stdout.writeln("Downloading necessary components..."); - var consoleDll = File("${assetsDirectory.path}\\dlls\\console.dll"); + var consoleDll = File("${dllsDirectory.path}\\console.dll"); if(!consoleDll.existsSync()){ var response = await http.get(Uri.parse(_consoleDownload)); if(response.statusCode != 200){ @@ -22,7 +22,7 @@ Future downloadRequiredDLLs() async { await consoleDll.writeAsBytes(response.bodyBytes); } - var craniumDll = File("${assetsDirectory.path}\\dlls\\cobalt.dll"); + var craniumDll = File("${dllsDirectory.path}\\cobalt.dll"); if(!craniumDll.existsSync()){ var response = await http.get(Uri.parse(_baseDownload)); if(response.statusCode != 200){ @@ -32,11 +32,11 @@ Future downloadRequiredDLLs() async { await craniumDll.writeAsBytes(response.bodyBytes); } - var memoryFixDll = File("${assetsDirectory.path}\\dlls\\memoryleak.dll"); + var memoryFixDll = File("${dllsDirectory.path}\\memoryFix.dll"); if(!memoryFixDll.existsSync()){ var response = await http.get(Uri.parse(_memoryFixDownload)); if(response.statusCode != 200){ - throw Exception("Cannot download memoryleak.dll"); + throw Exception("Cannot download memoryFix.dll"); } await memoryFixDll.writeAsBytes(response.bodyBytes); diff --git a/common/lib/common.dart b/common/lib/common.dart index 72415e4..4ca9b0d 100644 --- a/common/lib/common.dart +++ b/common/lib/common.dart @@ -10,6 +10,7 @@ export 'package:reboot_common/src/model/server_result.dart'; export 'package:reboot_common/src/model/server_type.dart'; export 'package:reboot_common/src/model/update_status.dart'; export 'package:reboot_common/src/model/update_timer.dart'; +export 'package:reboot_common/src/model/dll.dart'; export 'package:reboot_common/src/util/backend.dart'; export 'package:reboot_common/src/util/build.dart'; export 'package:reboot_common/src/util/dll.dart'; diff --git a/common/lib/src/constant/game.dart b/common/lib/src/constant/game.dart index a2606ed..7e7655a 100644 --- a/common/lib/src/constant/game.dart +++ b/common/lib/src/constant/game.dart @@ -21,3 +21,4 @@ const List kCannotConnectErrors = [ "UOnlineAccountCommon::ForceLogout" ]; const String kGameFinishedLine = "PlayersLeft: 1"; +const String kDisplayInitializedLine = "Display"; diff --git a/common/lib/src/model/dll.dart b/common/lib/src/model/dll.dart new file mode 100644 index 0000000..e02bea6 --- /dev/null +++ b/common/lib/src/model/dll.dart @@ -0,0 +1,6 @@ +enum InjectableDll { + console, + cobalt, + reboot, + memoryFix +} diff --git a/common/lib/src/util/dll.dart b/common/lib/src/util/dll.dart index 7aac733..f0e20d7 100644 --- a/common/lib/src/util/dll.dart +++ b/common/lib/src/util/dll.dart @@ -6,7 +6,7 @@ import 'package:path/path.dart' as path; import 'package:reboot_common/common.dart'; bool _watcher = false; -final File rebootDllFile = File("${assetsDirectory.path}\\dlls\\reboot.dll"); +final File rebootDllFile = File("${dllsDirectory.path}\\reboot.dll"); const String kRebootDownloadUrl = "http://nightly.link/Milxnor/Project-Reboot-3.0/workflows/msbuild/master/Release.zip"; @@ -18,7 +18,7 @@ Future hasRebootDllUpdate(int? lastUpdateMs, {int hours = 24, bool force = } Future downloadCriticalDll(String name, String outputPath) async { - final response = await http.get(Uri.parse("https://github.com/Auties00/reboot_launcher/raw/master/gui/assets/dlls/$name")); + final response = await http.get(Uri.parse("https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/$name")); if(response.statusCode != 200) { throw Exception("Cannot download $name: status code ${response.statusCode}"); } diff --git a/common/lib/src/util/network.dart b/common/lib/src/util/network.dart index c2fa8c3..64fb74a 100644 --- a/common/lib/src/util/network.dart +++ b/common/lib/src/util/network.dart @@ -34,10 +34,11 @@ final class _MIB_TCPTABLE_OWNER_PID extends Struct { @Uint32() external int dwNumEntries; - @Array(1) + @Array(512) external Array<_MIB_TCPROW_OWNER_PID> table; } + bool isLocalHost(String host) => host.trim() == "127.0.0.1" || host.trim().toLowerCase() == "localhost" || host.trim() == "0.0.0.0"; @@ -46,7 +47,6 @@ bool killProcessByPort(int port) { var pTcpTable = calloc<_MIB_TCPTABLE_OWNER_PID>(); final dwSize = calloc(); dwSize.value = 0; - int result = _getExtendedTcpTable( nullptr, dwSize, @@ -56,6 +56,7 @@ bool killProcessByPort(int port) { 0 ); if (result == ERROR_INSUFFICIENT_BUFFER) { + free(pTcpTable); pTcpTable = calloc<_MIB_TCPTABLE_OWNER_PID>(dwSize.value); result = _getExtendedTcpTable( pTcpTable, diff --git a/common/lib/src/util/path.dart b/common/lib/src/util/path.dart index 25feede..4551fdc 100644 --- a/common/lib/src/util/path.dart +++ b/common/lib/src/util/path.dart @@ -3,6 +3,8 @@ import 'dart:io'; Directory get installationDirectory => File(Platform.resolvedExecutable).parent; +Directory get dllsDirectory => Directory("${installationDirectory.path}\\dlls"); + Directory get assetsDirectory { var directory = Directory("${installationDirectory.path}\\data\\flutter_assets\\assets"); if(directory.existsSync()) { diff --git a/common/lib/src/util/process.dart b/common/lib/src/util/process.dart index f116d04..e9ca711 100644 --- a/common/lib/src/util/process.dart +++ b/common/lib/src/util/process.dart @@ -33,7 +33,10 @@ final _CreateRemoteThread = _kernel32.lookupFunction< Pointer lpThreadId)>('CreateRemoteThread'); const chunkSize = 1024; -Future injectDll(int pid, String dll) async { +Future injectDll(int pid, File dll) async { + // Get the path to the file + final dllPath = dll.path; + final process = OpenProcess( 0x43A, 0, @@ -52,7 +55,7 @@ Future injectDll(int pid, String dll) async { final dllAddress = VirtualAllocEx( process, nullptr, - dll.length + 1, + dllPath.length + 1, 0x3000, 0x4 ); @@ -60,8 +63,8 @@ Future injectDll(int pid, String dll) async { final writeMemoryResult = WriteProcessMemory( process, dllAddress, - dll.toNativeUtf8(), - dll.length, + dllPath.toNativeUtf8(), + dllPath.length, nullptr ); @@ -89,6 +92,18 @@ Future injectDll(int pid, String dll) async { } } +Future startElevatedProcess({required String executable, required String args, bool window = false}) async { + var shellInput = calloc(); + shellInput.ref.lpFile = executable.toNativeUtf16(); + shellInput.ref.lpParameters = args.toNativeUtf16(); + shellInput.ref.nShow = window ? SW_SHOWNORMAL : SW_HIDE; + shellInput.ref.fMask = ES_AWAYMODE_REQUIRED; + shellInput.ref.lpVerb = "runas".toNativeUtf16(); + shellInput.ref.cbSize = sizeOf(); + var shellResult = ShellExecuteEx(shellInput); + return shellResult == 1; +} + Future startProcess({required File executable, List? args, bool wrapProcess = true, bool window = false, String? name}) async { final argsOrEmpty = args ?? []; if(wrapProcess) { diff --git a/gui/assets/info/en/1. What is Project Reboot b/gui/assets/info/en/1. What is Project Reboot index 616f773..ab32a68 100644 --- a/gui/assets/info/en/1. What is Project Reboot +++ b/gui/assets/info/en/1. What is Project Reboot @@ -1,4 +1,3 @@ -Some Fortnite versions support running this game server in the background without rendering the game: this type of server is called "headless" as the game is running, but you can't see it on your screen. -If headless is not supported by the Fortnite version you want to play, or if you disabled it manually from the "Configuration" section in the "Host" tab of the launcher, you will see an instance of Fortnite open on your screen. -For convenience, this window will be opened on a new Virtual Desktop, if your Windows version supports it. This feature can be disabled as well from from the "Configuration" section in the "Host" tab of the launcher. -Just like in Minecraft, you need a game client to play the game and one to host the server." \ No newline at end of file +Project Reboot is a game server for Fortnite that aims to support as many seasons as possible. +The project was started on Discord by Milxnor, while the launcher is developed by Auties00. +Both are open source on GitHub, anyone can easily contribute or audit the code!" \ No newline at end of file diff --git a/gui/assets/info/en/5. What is a backend b/gui/assets/info/en/5. What is a backend index 2108286..6d1df79 100644 --- a/gui/assets/info/en/5. What is a backend +++ b/gui/assets/info/en/5. What is a backend @@ -1,6 +1,6 @@ A backend is a piece of software that emulates the Epic Games server responsible for authentication and related features. By default, the Reboot Launcher ships with a slightly customized version of LawinV1, an open source implementation available on Github. -If you are having any problems with the built in backend, enable the "Detached" option in the "Backend" tab of the Reboot Laucher to troubleshoot the issue." +If you are having any problems with the built in backend, enable the "Detached" option in the "Backend" tab of the Reboot Laucher to troubleshoot the issue. LawinV1 was chosen to allow users to log into Fortnite and join games easily, but keep in mind that if you want to use features such as parties, voice chat or skins, you will need to use a custom backend. Other popular options are LawinV2 and Momentum, both available on Github, but it's not recommended to use them if you are not an advanced user. -You can run these alternatives either either on your PC or on a server by selecting respectively "Local" or "Remote" from the "Type" section in the "Backend" tab of the Reboot Launcher. \ No newline at end of file +You can run these alternatives either on your PC or on a server by selecting respectively "Local" or "Remote" from the "Type" section in the "Backend" tab of the Reboot Launcher. \ No newline at end of file diff --git a/gui/assets/dlls/cobalt.dll b/gui/dependencies/dlls/cobalt.dll similarity index 100% rename from gui/assets/dlls/cobalt.dll rename to gui/dependencies/dlls/cobalt.dll diff --git a/gui/assets/dlls/console.dll b/gui/dependencies/dlls/console.dll similarity index 100% rename from gui/assets/dlls/console.dll rename to gui/dependencies/dlls/console.dll diff --git a/gui/assets/dlls/memoryleak.dll b/gui/dependencies/dlls/memoryFix.dll similarity index 100% rename from gui/assets/dlls/memoryleak.dll rename to gui/dependencies/dlls/memoryFix.dll diff --git a/gui/lib/main.dart b/gui/lib/main.dart index b3aadc2..31a6fe9 100644 --- a/gui/lib/main.dart +++ b/gui/lib/main.dart @@ -24,7 +24,7 @@ import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart'; import 'package:reboot_launcher/src/dialog/implementation/error.dart'; import 'package:reboot_launcher/src/dialog/implementation/server.dart'; import 'package:reboot_launcher/src/page/implementation/home_page.dart'; -import 'package:reboot_launcher/src/util/info.dart'; +import 'package:reboot_launcher/src/page/implementation/info_page.dart'; import 'package:reboot_launcher/src/util/matchmaker.dart'; import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/translations.dart'; @@ -35,65 +35,102 @@ import 'package:version/version.dart'; import 'package:window_manager/window_manager.dart'; const double kDefaultWindowWidth = 1536; -const double kDefaultWindowHeight = 1024; +const double kDefaultWindowHeight = 1224; const String kCustomUrlSchema = "Reboot"; Version? appVersion; -class _MyHttpOverrides extends HttpOverrides { - @override - HttpClient createHttpClient(SecurityContext? context){ - return super.createHttpClient(context) - ..badCertificateCallback = ((X509Certificate cert, String host, int port) => true); +void main() => runZonedGuarded( + () => _startApp(), + (error, stack) => onError(error, stack, false), + zoneSpecification: ZoneSpecification( + handleUncaughtError: (self, parent, zone, error, stacktrace) => onError(error, stacktrace, false) + ) +); + +Future _startApp() async { + final errors = []; + try { + final pathError = await _initPath(); + if(pathError != null) { + errors.add(pathError); + } + + final databaseError = await _initDatabase(); + if(databaseError != null) { + errors.add(databaseError); + } + + final notificationsError = await _initNotifications(); + if(notificationsError != null) { + errors.add(notificationsError); + } + + WidgetsFlutterBinding.ensureInitialized(); + + _initWindow(); + + final tilesError = InfoPage.initInfoTiles(); + if(tilesError != null) { + errors.add(tilesError); + } + + final versionError = await _initVersion(); + if(versionError != null) { + errors.add(versionError); + } + + final storageError = await _initStorage(); + if(storageError != null) { + errors.add(storageError); + } + + final urlError = await _initUrlHandler(); + if(urlError != null) { + errors.add(urlError); + } + + _checkGameServer(); + }catch(uncaughtError) { + errors.add(uncaughtError); + } finally{ + runApp(const RebootApplication()); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) => _handleErrors(errors)); } } -void main() => runZonedGuarded( - () async { - HttpOverrides.global = _MyHttpOverrides(); - final errors = []; - try { - await installationDirectory.create(recursive: true); - await Supabase.initialize( - url: supabaseUrl, - anonKey: supabaseAnonKey - ); - await localNotifier.setup( - appName: 'Reboot Launcher', - shortcutPolicy: ShortcutPolicy.ignore - ); - WidgetsFlutterBinding.ensureInitialized(); - await SystemTheme.accentColor.load(); - _initWindow(); - initInfoTiles(); - final versionError = await _initVersion(); - if(versionError != null) { - errors.add(versionError); - } +Future _initNotifications() async { + try { + await localNotifier.setup( + appName: 'Reboot Launcher', + shortcutPolicy: ShortcutPolicy.ignore + ); + return null; + }catch(error) { + return error; + } +} - final storageError = await _initStorage(); - if(storageError != null) { - errors.add(storageError); - } +Future _initDatabase() async { + try { + await Supabase.initialize( + url: supabaseUrl, + anonKey: supabaseAnonKey + ); + return null; + }catch(error) { + return error; + } +} - final urlError = await _initUrlHandler(); - if(urlError != null) { - errors.add(urlError); - } - - _checkGameServer(); - }catch(uncaughtError) { - errors.add(uncaughtError); - } finally{ - runApp(const RebootApplication()); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) => _handleErrors(errors)); - } - }, - (error, stack) => onError(error, stack, false), - zoneSpecification: ZoneSpecification( - handleUncaughtError: (self, parent, zone, error, stacktrace) => onError(error, stacktrace, false) - ) -); +Future _initPath() async { + try { + await installationDirectory.create(recursive: true); + return null; + }catch(error) { + return error; + } +} void _handleErrors(List errors) { errors.where((element) => element != null).forEach((element) => onError(element!, null, false)); @@ -170,6 +207,7 @@ void _joinServer(Uri uri) { String _parseCustomUrl(Uri uri) => uri.host; void _initWindow() => doWhenWindowReady(() async { + await SystemTheme.accentColor.load(); await windowManager.ensureInitialized(); await Window.initialize(); var settingsController = Get.find(); diff --git a/gui/lib/src/controller/settings_controller.dart b/gui/lib/src/controller/settings_controller.dart index dd01a3e..610cf8c 100644 --- a/gui/lib/src/controller/settings_controller.dart +++ b/gui/lib/src/controller/settings_controller.dart @@ -26,7 +26,7 @@ class SettingsController extends GetxController { gameServerDll = _createController("game_server", "reboot.dll"); unrealEngineConsoleDll = _createController("unreal_engine_console", "console.dll"); backendDll = _createController("backend", "cobalt.dll"); - memoryLeakDll = _createController("memory_leak", "memoryleak.dll"); + memoryLeakDll = _createController("memory_leak", "memoryFix.dll"); gameServerPort = TextEditingController(text: _storage.read("game_server_port") ?? kDefaultGameServerPort); gameServerPort.addListener(() => _storage.write("game_server_port", gameServerPort.text)); width = _storage.read("width") ?? kDefaultWindowWidth; @@ -67,5 +67,5 @@ class SettingsController extends GetxController { firstRun.value = true; } - String _controllerDefaultPath(String name) => "${assetsDirectory.path}\\dlls\\$name"; + String _controllerDefaultPath(String name) => "${dllsDirectory.path}\\$name"; } diff --git a/gui/lib/src/dialog/implementation/server.dart b/gui/lib/src/dialog/implementation/server.dart index 3b2bf7d..f7df30f 100644 --- a/gui/lib/src/dialog/implementation/server.dart +++ b/gui/lib/src/dialog/implementation/server.dart @@ -53,6 +53,7 @@ extension ServerControllerDialog on BackendController { severity: InfoBarSeverity.success ); case ServerResultType.startError: + print(event.stackTrace); return showInfoBar( type.value == ServerType.local ? translations.localServerError(event.error ?? translations.unknownError) : translations.startServerError(event.error ?? translations.unknownError), severity: InfoBarSeverity.error, diff --git a/gui/lib/src/page/implementation/home_page.dart b/gui/lib/src/page/implementation/home_page.dart index f052faa..345f57d 100644 --- a/gui/lib/src/page/implementation/home_page.dart +++ b/gui/lib/src/page/implementation/home_page.dart @@ -46,16 +46,26 @@ class _HomePageState extends State with WindowListener, AutomaticKeepA @override void initState() { windowManager.addListener(this); - WidgetsBinding.instance.addPostFrameCallback((_) { - _updateController.notifyLauncherUpdate(); - _updateController.updateReboot(); - watchDlls().listen((filePath) => showDllDeletedDialog(() { - downloadCriticalDllInteractive(filePath); - })); - }); + WidgetsBinding.instance.addPostFrameCallback((_) => _checkUpdates()); super.initState(); } + void _checkUpdates() { + _updateController.notifyLauncherUpdate(); + + if(!dllsDirectory.existsSync()) { + dllsDirectory.createSync(recursive: true); + } + + for(final injectable in InjectableDll.values) { + downloadCriticalDllInteractive("${injectable.name}.dll"); + } + + watchDlls().listen((filePath) => showDllDeletedDialog(() { + downloadCriticalDllInteractive(filePath); + })); + } + @override void onWindowClose() { exit(0); // Force closing diff --git a/gui/lib/src/page/implementation/info_page.dart b/gui/lib/src/page/implementation/info_page.dart index b1f846d..ba4ff3d 100644 --- a/gui/lib/src/page/implementation/info_page.dart +++ b/gui/lib/src/page/implementation/info_page.dart @@ -1,15 +1,53 @@ import 'dart:async'; +import 'dart:collection'; +import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons; +import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; +import 'package:reboot_common/common.dart'; import 'package:reboot_launcher/src/controller/settings_controller.dart'; import 'package:reboot_launcher/src/page/abstract/page.dart'; import 'package:reboot_launcher/src/page/abstract/page_type.dart'; import 'package:reboot_launcher/src/page/pages.dart'; -import 'package:reboot_launcher/src/util/info.dart'; import 'package:reboot_launcher/src/util/translations.dart'; +import 'package:path/path.dart' as path; +import 'package:reboot_launcher/src/widget/info_tile.dart'; class InfoPage extends RebootPage { + static late final List _infoTiles; + static Object? initInfoTiles() { + try { + final directory = Directory("${assetsDirectory.path}\\info\\$currentLocale"); + final map = SplayTreeMap(); + for(final entry in directory.listSync()) { + if(entry is File) { + final name = Uri.decodeQueryComponent(path.basename(entry.path)); + final splitter = name.indexOf("."); + if(splitter == -1) { + continue; + } + + final index = int.tryParse(name.substring(0, splitter)); + if(index == null) { + continue; + } + + final questionName = Uri.decodeQueryComponent(name.substring(splitter + 2)); + map[index] = InfoTile( + title: Text(questionName), + content: Text(entry.readAsStringSync()) + ); + } + } + _infoTiles = map.values.toList(growable: false); + return null; + }catch(error) { + _infoTiles = []; + return error; + } + } + const InfoPage({Key? key}) : super(key: key); @override @@ -30,7 +68,7 @@ class InfoPage extends RebootPage { class _InfoPageState extends RebootPageState { final SettingsController _settingsController = Get.find(); - RxInt _counter = RxInt(180); + RxInt _counter = RxInt(kDebugMode ? 0 : 180); @override void initState() { @@ -48,7 +86,7 @@ class _InfoPageState extends RebootPageState { } @override - List get settings => infoTiles; + List get settings => InfoPage._infoTiles; @override Widget? get button => Obx(() { diff --git a/gui/lib/src/util/dll.dart b/gui/lib/src/util/dll.dart index a4add1f..1346f52 100644 --- a/gui/lib/src/util/dll.dart +++ b/gui/lib/src/util/dll.dart @@ -1,9 +1,11 @@ import 'dart:async'; +import 'dart:io'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:get/get.dart'; import 'package:path/path.dart' as path; import 'package:reboot_common/common.dart'; +import 'package:reboot_launcher/src/controller/settings_controller.dart'; import 'package:reboot_launcher/src/controller/update_controller.dart'; import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart'; import 'package:reboot_launcher/src/util/translations.dart'; @@ -68,3 +70,26 @@ Future _downloadCriticalDllInteractive(String filePath) async { _operations.remove(fileName); } } + +extension InjectableDllExtension on InjectableDll { + String get path { + final SettingsController settingsController = Get.find(); + switch(this){ + case InjectableDll.reboot: + if(_updateController.customGameServer.value) { + final file = File(settingsController.gameServerDll.text); + if(file.existsSync()) { + return file.path; + } + } + + return rebootDllFile.path; + case InjectableDll.console: + return settingsController.unrealEngineConsoleDll.text; + case InjectableDll.cobalt: + return settingsController.backendDll.text; + case InjectableDll.memoryFix: + return settingsController.memoryLeakDll.text; + } + } +} diff --git a/gui/lib/src/util/info.dart b/gui/lib/src/util/info.dart deleted file mode 100644 index bbf13ac..0000000 --- a/gui/lib/src/util/info.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'dart:collection'; -import 'dart:io'; - -import 'package:fluent_ui/fluent_ui.dart'; -import 'package:path/path.dart' as path; -import 'package:reboot_common/common.dart'; -import 'package:reboot_launcher/src/util/log.dart'; -import 'package:reboot_launcher/src/util/translations.dart'; -import 'package:reboot_launcher/src/widget/info_tile.dart'; - -final _entries = SplayTreeMap(); - -void initInfoTiles() { - try { - final directory = Directory("${assetsDirectory.path}\\info\\$currentLocale"); - for(final entry in directory.listSync()) { - if(entry is File) { - final name = Uri.decodeQueryComponent(path.basename(entry.path)); - final splitter = name.indexOf("."); - if(splitter == -1) { - continue; - } - - final index = int.tryParse(name.substring(0, splitter)); - if(index == null) { - continue; - } - - final questionName = Uri.decodeQueryComponent(name.substring(splitter + 2)); - _entries[index] = InfoTile( - title: Text(questionName), - content: Text(entry.readAsStringSync()) - ); - } - } - }catch(error) { - log("[INFO] Error occurred while initializing info tiles: $error"); - } -} - -List get infoTiles => _entries.values.toList(growable: false); \ No newline at end of file diff --git a/gui/lib/src/widget/game_start_button.dart b/gui/lib/src/widget/game_start_button.dart index f89cef0..bb6db49 100644 --- a/gui/lib/src/widget/game_start_button.dart +++ b/gui/lib/src/widget/game_start_button.dart @@ -103,8 +103,8 @@ class _LaunchButtonState extends State { log("[${widget.host ? 'HOST' : 'GAME'}] Setting started..."); _setStarted(widget.host, true); log("[${widget.host ? 'HOST' : 'GAME'}] Set started"); - log("[${widget.host ? 'HOST' : 'GAME'}] Checking dlls: ${_Injectable.values}"); - for (final injectable in _Injectable.values) { + log("[${widget.host ? 'HOST' : 'GAME'}] Checking dlls: ${InjectableDll.values}"); + for (final injectable in InjectableDll.values) { if(await _getDllFileOrStop(injectable, widget.host) == null) { return; } @@ -239,7 +239,7 @@ class _LaunchButtonState extends State { }else{ _gameController.instance.value = instance; } - await _injectOrShowError(_Injectable.sslBypassV2, host); + await _injectOrShowError(InjectableDll.cobalt, host); log("[${host ? 'HOST' : 'GAME'}] Finished creating game instance"); return instance; } @@ -319,46 +319,33 @@ class _LaunchButtonState extends State { _onStop( reason: _StopReason.normal ); - return; - } - - if(kCorruptedBuildErrors.any((element) => line.contains(element))){ + }else if(kCorruptedBuildErrors.any((element) => line.contains(element))){ _onStop( reason: _StopReason.corruptedVersionError ); - return; - } - - if(kCannotConnectErrors.any((element) => line.contains(element))){ + }else if(kCannotConnectErrors.any((element) => line.contains(element))){ _onStop( reason: _StopReason.tokenError ); - return; - } - - if(kLoggedInLines.every((entry) => line.contains(entry))) { + }else if(kLoggedInLines.every((entry) => line.contains(entry))) { final instance = host ? _hostingController.instance.value : _gameController.instance.value; if(instance != null && !instance.launched) { instance.launched = true; instance.tokenError = false; - await _injectOrShowError(_Injectable.memoryFix, host); + await _injectOrShowError(InjectableDll.memoryFix, host); if(!host){ - await _injectOrShowError(_Injectable.console, host); + await _injectOrShowError(InjectableDll.console, host); _onGameClientInjected(); }else { final gameServerPort = int.tryParse(_settingsController.gameServerPort.text); if(gameServerPort != null) { await killProcessByPort(gameServerPort); } - await _injectOrShowError(_Injectable.reboot, host); + await _injectOrShowError(InjectableDll.reboot, host); _onGameServerInjected(); } } - - return; - } - - if(line.contains(kGameFinishedLine) && host) { + }else if(line.contains(kGameFinishedLine) && host) { if(_hostingController.autoRestart.value) { final notification = LocalNotification( title: translations.gameServerEnd, @@ -378,10 +365,7 @@ class _LaunchButtonState extends State { _onStop(reason: _StopReason.normal, host: true); }); } - return; - } - - if(line.contains("Display") && host && virtualDesktop) { + }else if(line.contains(kDisplayInitializedLine) && host && virtualDesktop) { final hostingInstance = _hostingController.instance.value; if(hostingInstance != null && !hostingInstance.movedToVirtualDesktop) { hostingInstance.movedToVirtualDesktop = true; @@ -615,7 +599,7 @@ class _LaunchButtonState extends State { } } - Future _injectOrShowError(_Injectable injectable, bool hosting) async { + Future _injectOrShowError(InjectableDll injectable, bool hosting) async { final instance = hosting ? _hostingController.instance.value : _gameController.instance.value; if (instance == null) { log("[${hosting ? 'HOST' : 'GAME'}] No instance found to inject ${injectable.name}"); @@ -637,7 +621,7 @@ class _LaunchButtonState extends State { } log("[${hosting ? 'HOST' : 'GAME'}] Trying to inject ${injectable.name}..."); - await injectDll(gameProcess, dllPath.path); + await injectDll(gameProcess, dllPath); log("[${hosting ? 'HOST' : 'GAME'}] Injected ${injectable.name}"); } catch (error, stackTrace) { log("[${hosting ? 'HOST' : 'GAME'}] Cannot inject ${injectable.name}: $error $stackTrace"); @@ -650,29 +634,9 @@ class _LaunchButtonState extends State { } } - String _getDllPath(_Injectable injectable) { - switch(injectable){ - case _Injectable.reboot: - if(_updateController.customGameServer.value) { - final file = File(_settingsController.gameServerDll.text); - if(file.existsSync()) { - return file.path; - } - } - - return rebootDllFile.path; - case _Injectable.console: - return _settingsController.unrealEngineConsoleDll.text; - case _Injectable.sslBypassV2: - return _settingsController.backendDll.text; - case _Injectable.memoryFix: - return _settingsController.memoryLeakDll.text; - } - } - - Future _getDllFileOrStop(_Injectable injectable, bool host) async { + Future _getDllFileOrStop(InjectableDll injectable, bool host) async { log("[${host ? 'HOST' : 'GAME'}] Checking dll ${injectable}..."); - final path = _getDllPath(injectable); + final path = injectable.path; log("[${host ? 'HOST' : 'GAME'}] Path: $path"); final file = File(path); if(await file.exists()) { @@ -712,11 +676,4 @@ enum _StopReason { exitCode; bool get isError => name.contains("Error"); -} - -enum _Injectable { - console, - sslBypassV2, - reboot, - memoryFix, -} +} \ No newline at end of file diff --git a/gui/pubspec.yaml b/gui/pubspec.yaml index a7a8c82..3fda0f1 100644 --- a/gui/pubspec.yaml +++ b/gui/pubspec.yaml @@ -90,7 +90,6 @@ flutter: uses-material-design: true generate: true assets: - - assets/dlls/ - assets/icons/ - assets/images/ - assets/backend/ diff --git a/gui/windows/packaging/exe/custom-inno-setup-script.iss b/gui/windows/packaging/exe/custom-inno-setup-script.iss index 8909ae8..c06ad28 100644 --- a/gui/windows/packaging/exe/custom-inno-setup-script.iss +++ b/gui/windows/packaging/exe/custom-inno-setup-script.iss @@ -10,10 +10,10 @@ AppPublisher={{PUBLISHER_NAME}} AppPublisherURL={{PUBLISHER_URL}} AppSupportURL={{PUBLISHER_URL}} AppUpdatesURL={{PUBLISHER_URL}} -DefaultDirName={{INSTALL_DIR_NAME}} +DefaultDirName={autopf}\{{DISPLAY_NAME}}; DisableProgramGroupPage=yes OutputBaseFilename={{OUTPUT_BASE_FILENAME}} -Compression=lzma +Compression=zip SolidCompression=yes SetupIconFile={{SETUP_ICON_FILE}} WizardStyle=modern @@ -32,7 +32,8 @@ Name: "launchAtStartup"; Description: "{cm:AutoStartProgram,{{DISPLAY_NAME}}}"; Source: "{{SOURCE_DIR}}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs [Run] -Filename: "{app}\\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: runascurrentuser nowait postinstall skipifsilent +Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -Command ""Add-MpPreference -ExclusionPath '{app}'"""; Flags: runhidden +Filename: "{app}\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: runascurrentuser nowait postinstall skipifsilent [Icons] Name: "{autoprograms}\{{DISPLAY_NAME}}"; Filename: "{app}\{{EXECUTABLE_NAME}}"