Added remote lawin server

This commit is contained in:
Alessandro Autiero
2022-10-02 18:58:17 +02:00
parent 5332926981
commit 9a759ac9e3
27 changed files with 277 additions and 150 deletions

View File

@@ -9,10 +9,10 @@ import 'package:get_storage/get_storage.dart';
import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/build_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/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/page/home_page.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';
import 'package:system_theme/system_theme.dart'; import 'package:system_theme/system_theme.dart';
import 'package:reboot_launcher/src/page/home_page.dart';
void main() async { void main() async {
await Directory(safeBinariesDirectory) await Directory(safeBinariesDirectory)

View File

@@ -1,5 +1,4 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/model/fortnite_build.dart'; import 'package:reboot_launcher/src/model/fortnite_build.dart';
class BuildController extends GetxController { class BuildController extends GetxController {

View File

@@ -4,7 +4,6 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/model/fortnite_version.dart';
class GameController extends GetxController { class GameController extends GetxController {

View File

@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart'; import 'package:get_storage/get_storage.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:reboot_launcher/src/util/server.dart'; import 'package:reboot_launcher/src/util/server.dart';
@@ -13,6 +12,7 @@ class ServerController extends GetxController {
late final RxBool embedded; late final RxBool embedded;
late final RxBool warning; late final RxBool warning;
late RxBool started; late RxBool started;
HttpServer? reverseProxy;
ServerController() { ServerController() {
var storage = GetStorage("server"); var storage = GetStorage("server");
@@ -23,18 +23,30 @@ class ServerController extends GetxController {
port.addListener(() => storage.write("port", port.text)); port.addListener(() => storage.write("port", port.text));
embedded = RxBool(storage.read("embedded") ?? true); embedded = RxBool(storage.read("embedded") ?? true);
embedded.listen((value) => storage.write("embedded", value)); embedded.listen((value) {
storage.write("embedded", value);
if(!started.value) {
return;
}
if(value){
reverseProxy?.close(force: true);
reverseProxy = null;
started(false);
return;
}
loadBinary("release.bat", false)
.then((value) => Process.run(value.path, []))
.then((value) => started(false));
});
warning = RxBool(storage.read("lawin_value") ?? true); warning = RxBool(storage.read("lawin_value") ?? true);
warning.listen((value) => storage.write("lawin_value", value)); warning.listen((value) => storage.write("lawin_value", value));
started = RxBool(false); started = RxBool(false);
isLawinPortFree() isLawinPortFree()
.then((value) => started = RxBool(!value)); .then((value) => !embedded.value ? {} : started = RxBool(!value));
}
Future kill() async {
var release = await loadBinary("release.bat", false);
return Process.run(release.path, []);
} }
} }

View File

@@ -1,4 +1,5 @@
import 'dart:io'; import 'dart:io';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;

View File

@@ -5,11 +5,10 @@ import 'package:get_storage/get_storage.dart';
import 'package:reboot_launcher/src/page/info_page.dart'; import 'package:reboot_launcher/src/page/info_page.dart';
import 'package:reboot_launcher/src/page/launcher_page.dart'; import 'package:reboot_launcher/src/page/launcher_page.dart';
import 'package:reboot_launcher/src/page/server_page.dart'; import 'package:reboot_launcher/src/page/server_page.dart';
import 'package:reboot_launcher/src/widget/window_buttons.dart';
import 'package:reboot_launcher/src/widget/window_border.dart';
import 'package:window_manager/window_manager.dart';
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/widget/window_border.dart';
import 'package:reboot_launcher/src/widget/window_buttons.dart';
import 'package:window_manager/window_manager.dart';
import '../util/reboot.dart'; import '../util/reboot.dart';

View File

@@ -1,13 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart';
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/widget/deployment_selector.dart'; import 'package:reboot_launcher/src/widget/deployment_selector.dart';
import 'package:reboot_launcher/src/widget/launch_button.dart'; import 'package:reboot_launcher/src/widget/launch_button.dart';
import 'package:reboot_launcher/src/widget/username_box.dart'; import 'package:reboot_launcher/src/widget/username_box.dart';
import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/version_selector.dart'; import 'package:reboot_launcher/src/widget/version_selector.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';

View File

@@ -1,12 +1,11 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/widget/warning_info.dart'; import 'package:reboot_launcher/src/widget/host_input.dart';
import 'package:reboot_launcher/src/widget/local_server_switch.dart'; import 'package:reboot_launcher/src/widget/local_server_switch.dart';
import 'package:reboot_launcher/src/widget/port_input.dart'; import 'package:reboot_launcher/src/widget/port_input.dart';
import 'package:reboot_launcher/src/widget/host_input.dart';
import 'package:reboot_launcher/src/widget/server_button.dart'; import 'package:reboot_launcher/src/widget/server_button.dart';
import 'package:reboot_launcher/src/widget/warning_info.dart';
class ServerPage extends StatelessWidget { class ServerPage extends StatelessWidget {
final ServerController _serverController = Get.find<ServerController>(); final ServerController _serverController = Get.find<ServerController>();

View File

@@ -1,14 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;
import 'package:reboot_launcher/src/util/version.dart' as parser;
import 'package:html/parser.dart' show parse; import 'package:html/parser.dart' show parse;
import 'package:http/http.dart' as http;
import 'package:reboot_launcher/src/model/fortnite_build.dart';
import 'package:process_run/shell.dart'; import 'package:process_run/shell.dart';
import 'package:reboot_launcher/src/model/fortnite_build.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:reboot_launcher/src/util/version.dart' as parser;
const _userAgent = const _userAgent =
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"; "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36";

View File

@@ -1,11 +1,11 @@
import 'dart:io'; import 'dart:io';
import 'package:archive/archive_io.dart'; import 'package:archive/archive_io.dart';
import 'package:get/get.dart';
import 'package:reboot_launcher/src/util/binary.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:reboot_launcher/src/util/binary.dart';
const _rebootUrl = const _rebootUrl =
"https://nightly.link/Milxnor/Universal-Walking-Simulator/workflows/msbuild/master/Release.zip"; "https://nightly.link/Milxnor/Universal-Walking-Simulator/workflows/msbuild/master/Release.zip";

View File

@@ -1,14 +1,14 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io'; import 'dart:io';
import 'package:archive/archive_io.dart'; import 'package:archive/archive_io.dart';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:process_run/shell.dart'; import 'package:process_run/shell.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_proxy/shelf_proxy.dart';
final serverLocation = Directory("${Platform.environment["UserProfile"]}/.reboot_launcher/lawin"); final serverLocation = Directory("${Platform.environment["UserProfile"]}/.reboot_launcher/lawin");
const String _serverUrl = const String _serverUrl =
@@ -47,27 +47,76 @@ Future<bool> isLawinPortFree() async {
return !process.outText.contains(" LISTENING "); // Goofy way, best we got return !process.outText.contains(" LISTENING "); // Goofy way, best we got
} }
Future<bool> showRemoteServerCheck(BuildContext context, String host, String port, [bool autoClose = false]) async { Future<HttpServer?> changeReverseProxyState(BuildContext context, String host, String port, HttpServer? server) async {
var future = _pingServer(host, port).then((value) { if(server != null){
if(value && autoClose){ try{
Navigator.of(context).pop(); server.close(force: true);
return null;
}catch(error){
_showStopProxyError(context, error);
return server;
}
} }
return value; host = host.trim();
}); if(host.isEmpty){
await showDialog( showSnackbar(
context, const Snackbar(content: Text("Missing host name")));
return null;
}
port = port.trim();
if(port.isEmpty){
showSnackbar(
context, const Snackbar(content: Text("Missing port", textAlign: TextAlign.center)));
return null;
}
if(int.tryParse(port) == null){
showSnackbar(
context, const Snackbar(content: Text("Invalid port, use only numbers", textAlign: TextAlign.center)));
return null;
}
try{
var uri = await _showReverseProxyCheck(context, host, port);
if(uri == null){
return null;
}
return await shelf_io.serve(proxyHandler(uri), 'localhost', 3551);
}catch(error){
_showStartProxyError(context, error);
return null;
}
}
Future<Uri?> _showReverseProxyCheck(BuildContext context, String host, String port) async {
var future = _pingServer(host, port);
return await showDialog(
context: context, context: context,
builder: (context) => ContentDialog( builder: (context) => ContentDialog(
content: FutureBuilder<bool>( content: FutureBuilder<Uri?>(
future: future, future: future,
builder: (context, snapshot) { builder: (context, snapshot) {
if(snapshot.hasData){ if(snapshot.hasError){
return SizedBox( return SizedBox(
width: double.infinity, width: double.infinity,
child: Text(snapshot.data! ? "The server answered correctly" : "The remote server doesn't work correctly or the IP and/or the port are incorrect" , textAlign: TextAlign.center) child: Text("Cannot ping remote server: ${snapshot.error}" , textAlign: TextAlign.center)
); );
} }
if(snapshot.connectionState == ConnectionState.done && !snapshot.hasData){
return const SizedBox(
width: double.infinity,
child: Text("The remote server doesn't work correctly or the IP and/or the port are incorrect" , textAlign: TextAlign.center)
);
}
if(snapshot.hasData){
Navigator.of(context).pop(snapshot.data);
}
return const InfoLabel( return const InfoLabel(
label: "Pinging remote lawin server...", label: "Pinging remote lawin server...",
child: SizedBox( child: SizedBox(
@@ -86,30 +135,81 @@ Future<bool> showRemoteServerCheck(BuildContext context, String host, String por
backgroundColor: ButtonState.all(Colors.red)), backgroundColor: ButtonState.all(Colors.red)),
child: const Text('Close'), child: const Text('Close'),
)) ))
], ]
) )
); );
return await future;
} }
Future<bool> _pingServer(String host, String port, [bool https=false]) async { Future<Uri?> _pingServer(String host, String port, [bool https=false]) async {
var hostName = _getHostName(host);
var declaredScheme = _getScheme(host);
try{ try{
var uri = Uri( var uri = Uri(
scheme: https ? "https" : "http", scheme: declaredScheme ?? (https ? "https" : "http"),
host: host, host: hostName,
port: int.parse(port) port: int.parse(port)
); );
var client = HttpClient() var client = HttpClient()
..connectionTimeout = const Duration(seconds: 5); ..connectionTimeout = const Duration(seconds: 5);
var request = await client.getUrl(uri); var request = await client.getUrl(uri);
var response = await request.close(); var response = await request.close();
return response.statusCode == 200; return response.statusCode == 200 ? uri : null;
}catch(_){ }catch(_){
return https ? false : await _pingServer(host, port, true); return https || declaredScheme != null ? null : await _pingServer(host, port, true);
} }
} }
String? _getHostName(String host) => host.replaceFirst("http://", "").replaceFirst("https://", "");
String? _getScheme(String host) => host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null;
void _showStartProxyError(BuildContext context, Object error) {
showDialog(
context: context,
builder: (context) => ContentDialog(
content: SizedBox(
width: double.infinity,
child: Text("Cannot create the reverse proxy: $error", textAlign: TextAlign.center)
),
actions: [
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () => Navigator.of(context).pop(),
style: ButtonStyle(
backgroundColor: ButtonState.all(Colors.red)),
child: const Text('Close'),
)
)
],
)
);
}
void _showStopProxyError(BuildContext context, Object error) {
showDialog(
context: context,
builder: (context) => ContentDialog(
content: SizedBox(
width: double.infinity,
child: Text("Cannot kill the reverse proxy: $error", textAlign: TextAlign.center)
),
actions: [
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () => Navigator.of(context).pop(),
style: ButtonStyle(
backgroundColor: ButtonState.all(Colors.red)),
child: const Text('Close'),
)
)
],
)
);
}
Future<bool> changeEmbeddedServerState(BuildContext context, bool running) async { Future<bool> changeEmbeddedServerState(BuildContext context, bool running) async {
if (running) { if (running) {
var releaseBat = await loadBinary("release.bat", false); var releaseBat = await loadBinary("release.bat", false);

View File

@@ -3,9 +3,8 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/widget/select_file.dart';
import 'package:reboot_launcher/src/model/fortnite_version.dart'; import 'package:reboot_launcher/src/model/fortnite_version.dart';
import 'package:reboot_launcher/src/widget/select_file.dart';
class AddLocalVersion extends StatelessWidget { class AddLocalVersion extends StatelessWidget {
final GameController _gameController = Get.find<GameController>(); final GameController _gameController = Get.find<GameController>();

View File

@@ -1,19 +1,18 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:async/async.dart'; import 'package:async/async.dart';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:process_run/shell.dart';
import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/build_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/util/build.dart'; import 'package:reboot_launcher/src/model/fortnite_version.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:reboot_launcher/src/util/build.dart';
import 'package:reboot_launcher/src/widget/select_file.dart'; import 'package:reboot_launcher/src/widget/select_file.dart';
import 'package:reboot_launcher/src/widget/version_name_input.dart'; import 'package:reboot_launcher/src/widget/version_name_input.dart';
import 'package:reboot_launcher/src/model/fortnite_version.dart';
import 'package:reboot_launcher/src/model/fortnite_build.dart';
import 'build_selector.dart'; import 'build_selector.dart';
class AddServerVersion extends StatefulWidget { class AddServerVersion extends StatefulWidget {

View File

@@ -1,7 +1,6 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/build_controller.dart'; import 'package:reboot_launcher/src/controller/build_controller.dart';
import 'package:reboot_launcher/src/model/fortnite_build.dart'; import 'package:reboot_launcher/src/model/fortnite_build.dart';
class BuildSelector extends StatefulWidget { class BuildSelector extends StatefulWidget {

View File

@@ -1,8 +1,7 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/smart_switch.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/widget/smart_switch.dart';
class DeploymentSelector extends StatelessWidget { class DeploymentSelector extends StatelessWidget {
final GameController _gameController = Get.find<GameController>(); final GameController _gameController = Get.find<GameController>();

View File

@@ -1,8 +1,7 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
class HostInput extends StatelessWidget { class HostInput extends StatelessWidget {
final ServerController _serverController = Get.find<ServerController>(); final ServerController _serverController = Get.find<ServerController>();

View File

@@ -6,14 +6,13 @@ import 'package:get/get.dart';
import 'package:process_run/shell.dart'; import 'package:process_run/shell.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/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/util/injector.dart';
import 'package:reboot_launcher/src/util/binary.dart'; import 'package:reboot_launcher/src/util/binary.dart';
import 'package:reboot_launcher/src/util/injector.dart';
import 'package:reboot_launcher/src/util/patcher.dart'; import 'package:reboot_launcher/src/util/patcher.dart';
import 'package:reboot_launcher/src/util/server.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:win32_suspend_process/win32_suspend_process.dart'; import 'package:win32_suspend_process/win32_suspend_process.dart';
import 'package:reboot_launcher/src/util/server.dart';
class LaunchButton extends StatefulWidget { class LaunchButton extends StatefulWidget {
const LaunchButton( const LaunchButton(
{Key? key}) {Key? key})
@@ -65,28 +64,6 @@ class _LaunchButtonState extends State<LaunchButton> {
return; return;
} }
if (_serverController.embedded.value && !_serverController.started.value && await isLawinPortFree()) {
if(!mounted){
return;
}
var result = await changeEmbeddedServerState(context, false);
_serverController.started(result);
}
_updateServerState(true);
_onStart();
}
Future<void> _updateServerState(bool value) async {
if (_gameController.started.value == value) {
return;
}
_gameController.started(value);
}
Future<void> _onStart() async {
try { try {
_updateServerState(true); _updateServerState(true);
var version = _gameController.selectedVersionObs.value!; var version = _gameController.selectedVersionObs.value!;
@@ -101,17 +78,16 @@ class _LaunchButtonState extends State<LaunchButton> {
Win32Process(_gameController.eacProcess!.pid).suspend(); Win32Process(_gameController.eacProcess!.pid).suspend();
} }
if(!_serverController.embedded.value){
var available = await _showPingWarning();
if(!available) {
return;
}
}
if(hosting){ if(hosting){
await patchExe(version.executable!); await patchExe(version.executable!);
} }
await _startServerIfNecessary();
if(!_serverController.started.value){
_onStop();
return;
}
_gameController.gameProcess = await Process.start(version.executable!.path, _createProcessArguments()) _gameController.gameProcess = await Process.start(version.executable!.path, _createProcessArguments())
..exitCode.then((_) => _onEnd()) ..exitCode.then((_) => _onEnd())
..outLines.forEach(_onGameOutput); ..outLines.forEach(_onGameOutput);
@@ -126,6 +102,43 @@ class _LaunchButtonState extends State<LaunchButton> {
} }
} }
Future<void> _startServerIfNecessary() async {
if (!mounted) {
return;
}
if(_serverController.started.value){
return;
}
if(!(await isLawinPortFree())){
_serverController.started(true);
return;
}
if (_serverController.embedded.value) {
var result = await changeEmbeddedServerState(context, false);
_serverController.started(result);
return;
}
_serverController.reverseProxy = await changeReverseProxyState(
context,
_serverController.host.text,
_serverController.port.text,
_serverController.reverseProxy
);
_serverController.started(_serverController.reverseProxy != null);
}
Future<void> _updateServerState(bool value) async {
if (_gameController.started.value == value) {
return;
}
_gameController.started(value);
}
void _onEnd() { void _onEnd() {
if(_lawinFail){ if(_lawinFail){
return; return;
@@ -148,19 +161,6 @@ class _LaunchButtonState extends State<LaunchButton> {
Navigator.of(context).pop(false); Navigator.of(context).pop(false);
} }
Future<bool> _showPingWarning() async {
if(!mounted){
return false;
}
return await showRemoteServerCheck(
context,
_serverController.host.text,
_serverController.port.text,
true
);
}
Future<void> _showBrokenServerWarning() async { Future<void> _showBrokenServerWarning() async {
if(!mounted){ if(!mounted){
return; return;

View File

@@ -1,8 +1,7 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/smart_switch.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/widget/smart_switch.dart';
class LocalServerSwitch extends StatelessWidget { class LocalServerSwitch extends StatelessWidget {
final ServerController _serverController = Get.find<ServerController>(); final ServerController _serverController = Get.find<ServerController>();
@@ -15,7 +14,7 @@ class LocalServerSwitch extends StatelessWidget {
message: "Determines whether an embedded or remote lawin server should be used", message: "Determines whether an embedded or remote lawin server should be used",
child: SmartSwitch( child: SmartSwitch(
value: _serverController.embedded, value: _serverController.embedded,
label: "Embedded" label: "Embedded",
), ),
); );
} }

View File

@@ -1,8 +1,7 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
class PortInput extends StatelessWidget { class PortInput extends StatelessWidget {
final ServerController _serverController = Get.find<ServerController>(); final ServerController _serverController = Get.find<ServerController>();

View File

@@ -2,9 +2,9 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path;
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/widget/select_file.dart'; import 'package:reboot_launcher/src/widget/select_file.dart';
import 'package:path/path.dart' as path;
class ScanLocalVersion extends StatefulWidget { class ScanLocalVersion extends StatefulWidget {

View File

@@ -1,7 +1,6 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart'; import 'package:reboot_launcher/src/controller/server_controller.dart';
import 'package:reboot_launcher/src/util/server.dart'; import 'package:reboot_launcher/src/util/server.dart';
class ServerButton extends StatelessWidget { class ServerButton extends StatelessWidget {
@@ -16,35 +15,56 @@ class ServerButton extends StatelessWidget {
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
child: Obx(() => Tooltip( child: Obx(() => Tooltip(
message: !_serverController.embedded.value message: _helpMessage,
? "Check the address of the remote Lawin server"
: _serverController.started.value
? "Stop the running Lawin server instance"
: "Start a new Lawin server instance",
child: Button( child: Button(
onPressed: () => _onPressed(context), onPressed: () => _onPressed(context),
child: Text(_serverController.embedded.value child: Text(!_serverController.started.value
? !_serverController.started.value
? "Start" ? "Start"
: "Stop" : "Stop")),
: "Ping Server")),
)), )),
), ),
); );
} }
String get _helpMessage {
if (_serverController.embedded.value) {
if (_serverController.started.value) {
return "Stop the Lawin server currently running";
}
return "Start a new local Lawin server";
}
if (_serverController.started.value) {
return "Stop the reverse proxy currently running";
}
return "Start a reverse proxy targeting the remote Lawin server";
}
void _onPressed(BuildContext context) async { void _onPressed(BuildContext context) async {
var running = _serverController.started.value;
_serverController.started.value = !running;
if (!_serverController.embedded.value) { if (!_serverController.embedded.value) {
showRemoteServerCheck( _serverController.reverseProxy = await changeReverseProxyState(
context, _serverController.host.text, _serverController.port.text); context,
_serverController.host.text,
_serverController.port.text,
_serverController.reverseProxy
);
_updateStarted(_serverController.reverseProxy != null);
return; return;
} }
var running = _serverController.started.value;
_serverController.started.value = !running;
var updatedRunning = await changeEmbeddedServerState(context, running); var updatedRunning = await changeEmbeddedServerState(context, running);
if (updatedRunning != _serverController.started.value) { _updateStarted(updatedRunning);
}
void _updateStarted(bool updatedRunning) {
if (updatedRunning == _serverController.started.value) {
return;
}
_serverController.started.value = updatedRunning; _serverController.started.value = updatedRunning;
} }
}
} }

View File

@@ -1,8 +1,7 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/widget/smart_input.dart';
class UsernameBox extends StatelessWidget { class UsernameBox extends StatelessWidget {
final GameController _gameController = Get.find<GameController>(); final GameController _gameController = Get.find<GameController>();

View File

@@ -1,6 +1,5 @@
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart'; import 'package:reboot_launcher/src/controller/game_controller.dart';
class VersionNameInput extends StatelessWidget { class VersionNameInput extends StatelessWidget {

View File

@@ -1,29 +1,28 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart' import 'package:flutter/material.dart'
show showMenu, PopupMenuEntry, PopupMenuItem; show showMenu, PopupMenuEntry, PopupMenuItem;
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/model/fortnite_version.dart';
import 'package:reboot_launcher/src/widget/add_local_version.dart'; import 'package:reboot_launcher/src/widget/add_local_version.dart';
import 'package:reboot_launcher/src/widget/add_server_version.dart'; import 'package:reboot_launcher/src/widget/add_server_version.dart';
import 'package:reboot_launcher/src/model/fortnite_version.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/widget/scan_local_version.dart'; import 'package:reboot_launcher/src/widget/scan_local_version.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../controller/build_controller.dart'; class VersionSelector extends StatefulWidget {
class VersionSelector extends StatelessWidget {
final GameController _gameController = Get.find<GameController>();
final bool enableScanner; final bool enableScanner;
VersionSelector({Key? key, this.enableScanner = false}) : super(key: key); const VersionSelector({Key? key, this.enableScanner = false}) : super(key: key);
@override
State<VersionSelector> createState() => _VersionSelectorState();
}
class _VersionSelectorState extends State<VersionSelector> {
final GameController _gameController = Get.find<GameController>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -46,14 +45,14 @@ class VersionSelector extends StatelessWidget {
const SizedBox( const SizedBox(
width: 16, width: 16,
), ),
if(enableScanner) if(widget.enableScanner)
Tooltip( Tooltip(
message: "Scan all fortnite builds in a directory", message: "Scan all fortnite builds in a directory",
child: Button( child: Button(
child: const Icon(FluentIcons.site_scan), child: const Icon(FluentIcons.site_scan),
onPressed: () => _openScanLocalVersionDialog(context)), onPressed: () => _openScanLocalVersionDialog(context)),
), ),
if(enableScanner) if(widget.enableScanner)
const SizedBox( const SizedBox(
width: 16, width: 16,
), ),
@@ -125,7 +124,7 @@ class VersionSelector extends StatelessWidget {
void _openScanLocalVersionDialog(BuildContext context) async { void _openScanLocalVersionDialog(BuildContext context) async {
await showDialog<bool>( await showDialog<bool>(
context: context, context: context,
builder: (context) => ScanLocalVersion()); builder: (context) => const ScanLocalVersion());
} }
Future<void> _openMenu( Future<void> _openMenu(
@@ -142,13 +141,26 @@ class VersionSelector extends StatelessWidget {
switch (result) { switch (result) {
case 0: case 0:
if(!mounted){
return;
}
Navigator.of(context).pop(); Navigator.of(context).pop();
launchUrl(version.location.uri); launchUrl(version.location.uri);
break; break;
case 1: case 1:
_gameController.removeVersion(version); _gameController.removeVersion(version);
if(!mounted){
return;
}
await _openDeleteDialog(context, version); await _openDeleteDialog(context, version);
if(!mounted){
return;
}
Navigator.of(context).pop(); Navigator.of(context).pop();
if (_gameController.selectedVersionObs.value?.name == version.name || _gameController.hasNoVersions) { if (_gameController.selectedVersionObs.value?.name == version.name || _gameController.hasNoVersions) {
_gameController.selectedVersionObs.value = null; _gameController.selectedVersionObs.value = null;

View File

@@ -1,8 +1,7 @@
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:system_theme/system_theme.dart';
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';
import 'package:system_theme/system_theme.dart';
class WindowBorder extends StatelessWidget { class WindowBorder extends StatelessWidget {
const WindowBorder({Key? key}) : super(key: key); const WindowBorder({Key? key}) : super(key: key);

View File

@@ -1,5 +1,3 @@
import 'dart:io';
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:reboot_launcher/src/util/os.dart'; import 'package:reboot_launcher/src/util/os.dart';

View File

@@ -30,6 +30,7 @@ dependencies:
get: ^4.6.5 get: ^4.6.5
get_storage: ^2.0.3 get_storage: ^2.0.3
window_manager: ^0.2.7 window_manager: ^0.2.7
shelf_proxy: ^1.0.2
dependency_overrides: dependency_overrides:
win32: ^3.0.0 win32: ^3.0.0