Switched to sinum

This commit is contained in:
Alessandro Autiero
2024-10-21 20:32:23 +02:00
parent bfe15e43d9
commit dfebe74518
45 changed files with 2185 additions and 193 deletions

View File

@@ -4,15 +4,11 @@ import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/main.dart';
import 'package:reboot_launcher/src/messenger/abstract/info_bar.dart';
import 'package:reboot_launcher/src/util/translations.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:version/version.dart';
import 'package:yaml/yaml.dart';
class DllController extends GetxController {
static const String storageName = "dll_storage";
@@ -25,7 +21,8 @@ class DllController extends GetxController {
late final TextEditingController memoryLeakDll;
late final TextEditingController gameServerPort;
late final Rx<UpdateTimer> timer;
late final TextEditingController url;
late final TextEditingController beforeS20Mirror;
late final TextEditingController aboveS20Mirror;
late final RxBool customGameServer;
late final RxnInt timestamp;
late final Rx<UpdateStatus> status;
@@ -43,8 +40,10 @@ class DllController extends GetxController {
final timerIndex = _storage?.read("timer");
timer = Rx(timerIndex == null ? UpdateTimer.hour : UpdateTimer.values.elementAt(timerIndex));
timer.listen((value) => _storage?.write("timer", value.index));
url = TextEditingController(text: _storage?.read("update_url") ?? kRebootDownloadUrl);
url.addListener(() => _storage?.write("update_url", url.text));
beforeS20Mirror = TextEditingController(text: _storage?.read("update_url") ?? kRebootBelowS20DownloadUrl);
beforeS20Mirror.addListener(() => _storage?.write("update_url", beforeS20Mirror.text));
aboveS20Mirror = TextEditingController(text: _storage?.read("old_update_url") ?? kRebootAboveS20DownloadUrl);
aboveS20Mirror.addListener(() => _storage?.write("new_update_url", aboveS20Mirror.text));
status = Rx(UpdateStatus.waiting);
customGameServer = RxBool(_storage?.read("custom_game_server") ?? false);
customGameServer.listen((value) => _storage?.write("custom_game_server", value));
@@ -68,7 +67,8 @@ class DllController extends GetxController {
void resetServer() {
gameServerPort.text = kDefaultGameServerPort;
timer.value = UpdateTimer.hour;
url.text = kRebootDownloadUrl;
beforeS20Mirror.text = kRebootBelowS20DownloadUrl;
aboveS20Mirror.text = kRebootAboveS20DownloadUrl;
status.value = UpdateStatus.waiting;
customGameServer.value = false;
timestamp.value = null;
@@ -109,9 +109,15 @@ class DllController extends GetxController {
duration: null
);
}
final result = downloadRebootDll(url.text);
timestamp.value = await Future.wait([result, Future.delayed(const Duration(seconds: 1))], eagerError: false)
.then((_) => result);
await Future.wait(
[
downloadRebootDll(rebootBeforeS20DllFile, beforeS20Mirror.text),
downloadRebootDll(rebootAboveS20DllFile, aboveS20Mirror.text),
Future.delayed(const Duration(seconds: 1))
],
eagerError: false
);
timestamp.value = DateTime.now().millisecondsSinceEpoch;
status.value = UpdateStatus.success;
infoBarEntry?.close();
if(!silent) {
@@ -160,7 +166,7 @@ class DllController extends GetxController {
}
}
return (rebootDllFile, false);
return (rebootBeforeS20DllFile, false);
case InjectableDll.console:
final ue4ConsoleFile = File(unrealEngineConsoleDll.text);
return (ue4ConsoleFile, canonicalize(ue4ConsoleFile.path) != defaultPath);

View File

@@ -56,20 +56,36 @@ class HostingController extends GetxController {
published = RxBool(false);
showPassword = RxBool(false);
instance = Rxn();
final supabase = Supabase.instance.client;
servers = Rxn();
supabase.from("hosting_v2")
.stream(primaryKey: ['id'])
.map((event) => event.map((element) => FortniteServer.fromJson(element)).where((element) => element.ip.isNotEmpty).toSet())
.listen((event) {
servers.value = event;
published.value = event.any((element) => element.id == uuid);
});
_listenServers();
customLaunchArgs = TextEditingController(text: _storage?.read("custom_launch_args") ?? "");
customLaunchArgs.addListener(() => _storage?.write("custom_launch_args", customLaunchArgs.text));
_semaphore = Semaphore();
}
void _listenServers([int attempt = 0]) {
log("[SUPABASE] Listening...");
final supabase = Supabase.instance.client;
supabase.from("hosting_v2")
.stream(primaryKey: ['id'])
.map((event) => event.map((element) => FortniteServer.fromJson(element)).where((element) => element.ip.isNotEmpty).toSet())
.listen(
_onNewServer,
onError: (error) async {
log("[SUPABASE] Error: ${error}");
await Future.delayed(Duration(seconds: attempt * 5));
_listenServers(attempt + 1);
},
cancelOnError: true
);
}
void _onNewServer(Set<FortniteServer> event) {
log("[SUPABASE] New event: ${event}");
servers.value = event;
published.value = event.any((element) => element.id == uuid);
}
Future<void> publishServer(String author, String version) async {
try {
_semaphore.acquire();

View File

@@ -1,11 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/main.dart';
import 'package:reboot_launcher/src/messenger/abstract/info_bar.dart';
@@ -21,7 +19,6 @@ class SettingsController extends GetxController {
late final RxString language;
late final Rx<ThemeMode> themeMode;
late final RxBool firstRun;
late final RxBool debug;
late double width;
late double height;
late double? offsetX;
@@ -39,7 +36,6 @@ class SettingsController extends GetxController {
language.listen((value) => _storage?.write("language", value));
firstRun = RxBool(_storage?.read("first_run_tutorial") ?? true);
firstRun.listen((value) => _storage?.write("first_run_tutorial", value));
debug = RxBool(false);
}
void saveWindowSize(Size size) {

View File

@@ -300,7 +300,7 @@ class _DialogButtonState extends State<DialogButton> {
Widget get _primaryButton => Button(
style: ButtonStyle(
backgroundColor: ButtonState.all(FluentTheme.of(context).accentColor)
backgroundColor: WidgetStateProperty.all(FluentTheme.of(context).accentColor)
),
onPressed: widget.onTap!,
child: Text(widget.text!),
@@ -308,7 +308,7 @@ class _DialogButtonState extends State<DialogButton> {
Widget get _secondaryButton => Button(
style: widget.color != null ? ButtonStyle(
backgroundColor: ButtonState.all(widget.color!)
backgroundColor: WidgetStateProperty.all(widget.color!)
) : null,
onPressed: widget.onTap ?? _onDefaultSecondaryActionTap,
child: Text(widget.text ?? translations.defaultDialogSecondaryAction),

View File

@@ -62,7 +62,7 @@ void _promptPlayVersion() {
onTap: () async {
onClose();
if(!hasBuilds) {
await VersionSelector.openDownloadDialog(closable: false);
await VersionSelector.openDownloadDialog();
}
_promptServerBrowserPage();
}
@@ -339,7 +339,7 @@ Widget _buildActionButton({
required void Function() onTap,
}) => Button(
style: themed ? ButtonStyle(
backgroundColor: ButtonState.all(FluentTheme.of(context).accentColor)
backgroundColor: WidgetStateProperty.all(FluentTheme.of(context).accentColor)
) : null,
child: Text(label),
onPressed: onTap

View File

@@ -56,8 +56,8 @@ Future<bool> showProfileForm(BuildContext context) async{
suffix: Button(
onPressed: () => showPassword.value = !showPassword.value,
style: ButtonStyle(
shape: ButtonState.all(const CircleBorder()),
backgroundColor: ButtonState.all(Colors.transparent)
shape: WidgetStateProperty.all(const CircleBorder()),
backgroundColor: WidgetStateProperty.all(Colors.transparent)
),
child: Icon(
showPassword.value ? Icons.visibility_off : Icons.visibility,

View File

@@ -257,8 +257,8 @@ extension ServerControllerDialog on BackendController {
suffix: !showPasswordTrailing.value ? null : Button(
onPressed: () => showPassword.value = !showPassword.value,
style: ButtonStyle(
shape: ButtonState.all(const CircleBorder()),
backgroundColor: ButtonState.all(Colors.transparent)
shape: WidgetStateProperty.all(const CircleBorder()),
backgroundColor: WidgetStateProperty.all(Colors.transparent)
),
child: Icon(
showPassword.value ? FluentIcons.eye_off_24_regular : FluentIcons.eye_24_regular

View File

@@ -5,11 +5,9 @@ import 'dart:isolate';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/messenger/abstract/dialog.dart';
import 'package:reboot_launcher/src/util/os.dart';
import 'package:reboot_launcher/src/util/translations.dart';
import 'package:reboot_launcher/src/util/types.dart';
import 'package:reboot_launcher/src/widget/file_selector.dart';

View File

@@ -1,6 +1,5 @@
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';
@@ -35,7 +34,6 @@ abstract class RebootPageState<T extends RebootPage> extends State<T> with Autom
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildFirstLaunchInfo(),
_buildDebugInfo(),
Expanded(
child: _listView
)
@@ -47,7 +45,6 @@ abstract class RebootPageState<T extends RebootPage> extends State<T> with Autom
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildFirstLaunchInfo(),
_buildDebugInfo(),
Expanded(
child: Column(
children: [
@@ -99,35 +96,6 @@ abstract class RebootPageState<T extends RebootPage> extends State<T> with Autom
);
});
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(
itemCount: settings.length,
itemBuilder: (context, index) => settings[index],

View File

@@ -5,7 +5,6 @@ import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/backend_controller.dart';
import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/messenger/abstract/info_bar.dart';
import 'package:reboot_launcher/src/messenger/abstract/overlay.dart';
import 'package:reboot_launcher/src/messenger/implementation/data.dart';

View File

@@ -276,8 +276,8 @@ class _BrowsePageState extends RebootPageState<BrowsePage> {
_filterControllerStream.add("");
},
style: ButtonStyle(
backgroundColor: ButtonState.all(Colors.transparent),
shape: ButtonState.all(Border())
backgroundColor: WidgetStateProperty.all(Colors.transparent),
shape: WidgetStateProperty.all(Border())
),
child: _searchBarIconData
);

View File

@@ -498,7 +498,7 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
decoration: BoxDecoration(
color: ButtonThemeData.uncheckedInputColor(
FluentTheme.of(context),
pageIndex.value == index ? {ButtonStates.hovering} : states,
pageIndex.value == index ? {WidgetState.hovered} : states,
transparentWhenNone: true,
),
borderRadius: BorderRadius.all(Radius.circular(6.0))
@@ -527,12 +527,12 @@ class _HomePageState extends State<HomePage> with WindowListener, AutomaticKeepA
stream: pagesController.stream,
builder: (context, _) => Button(
style: ButtonStyle(
padding: ButtonState.all(const EdgeInsets.symmetric(
padding: WidgetStateProperty.all(const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 16.0
)),
backgroundColor: ButtonState.all(Colors.transparent),
shape: ButtonState.all(Border())
backgroundColor: WidgetStateProperty.all(Colors.transparent),
shape: WidgetStateProperty.all(Border())
),
onPressed: appStack.isEmpty && !inDialog ? null : () {
if(inDialog) {

View File

@@ -155,8 +155,8 @@ class _HostingPageState extends RebootPageState<HostPage> {
suffix: Button(
onPressed: () => _hostingController.showPassword.value = !_hostingController.showPassword.value,
style: ButtonStyle(
shape: ButtonState.all(const CircleBorder()),
backgroundColor: ButtonState.all(Colors.transparent)
shape: WidgetStateProperty.all(const CircleBorder()),
backgroundColor: WidgetStateProperty.all(Colors.transparent)
),
child: Icon(
_hostingController.showPassword.value ? FluentIcons.eye_off_24_filled : FluentIcons.eye_24_filled,
@@ -221,12 +221,11 @@ class _HostingPageState extends RebootPageState<HostPage> {
content: Obx(() => DropDownButton(
onOpen: () => inDialog = true,
onClose: () => inDialog = false,
leading: Text(_settingsController.debug.value ? GameServerType.window.translatedName : _hostingController.type.value.translatedName),
leading: Text(_hostingController.type.value.translatedName),
items: GameServerType.values.map((entry) => MenuFlyoutItem(
text: Text(entry.translatedName),
onPressed: () => _hostingController.type.value = entry
)).toList(),
disabled: _settingsController.debug.value
)).toList()
)),
),
SettingTile(
@@ -280,7 +279,8 @@ class _HostingPageState extends RebootPageState<HostPage> {
children: [
_internalFilesServerType,
_internalFilesUpdateTimer,
_internalFilesServerSource
_internalFilesOldServerSource,
_internalFilesNewServerSource,
],
);
@@ -318,13 +318,13 @@ class _HostingPageState extends RebootPageState<HostPage> {
))
);
Widget get _internalFilesServerSource => Obx(() {
Widget get _internalFilesOldServerSource => Obx(() {
if(!_dllController.customGameServer.value) {
return SettingTile(
icon: Icon(
FluentIcons.globe_24_regular
),
title: Text(translations.settingsServerMirrorName),
title: Text(translations.settingsServerOldMirrorName),
subtitle: Text(translations.settingsServerMirrorDescription),
contentWidth: SettingTile.kDefaultContentWidth + 30,
content: Row(
@@ -332,7 +332,7 @@ class _HostingPageState extends RebootPageState<HostPage> {
Expanded(
child: TextFormBox(
placeholder: translations.settingsServerMirrorPlaceholder,
controller: _dllController.url,
controller: _dllController.beforeS20Mirror,
onChanged: (value) {
if(Uri.tryParse(value) != null) {
_dllController.updateGameServerDll(force: true);
@@ -343,7 +343,7 @@ class _HostingPageState extends RebootPageState<HostPage> {
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: () => _dllController.updateGameServerDll(force: true),
child: SizedBox.square(
@@ -356,10 +356,10 @@ class _HostingPageState extends RebootPageState<HostPage> {
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: () {
_dllController.url.text = kRebootDownloadUrl;
_dllController.beforeS20Mirror.text = kRebootBelowS20DownloadUrl;
_dllController.updateGameServerDll(force: true);
},
child: SizedBox.square(
@@ -374,7 +374,75 @@ class _HostingPageState extends RebootPageState<HostPage> {
);
}else {
return createFileSetting(
title: translations.settingsServerFileName,
title: translations.settingsOldServerFileName,
description: translations.settingsServerFileDescription,
controller: _dllController.gameServerDll,
onReset: () {
final path = _dllController.getDefaultDllPath(InjectableDll.reboot);
_dllController.gameServerDll.text = path;
_dllController.downloadCriticalDllInteractive(path);
}
);
}
});
Widget get _internalFilesNewServerSource => Obx(() {
if(!_dllController.customGameServer.value) {
return SettingTile(
icon: Icon(
FluentIcons.globe_24_regular
),
title: Text(translations.settingsServerNewMirrorName),
subtitle: Text(translations.settingsServerMirrorDescription),
contentWidth: SettingTile.kDefaultContentWidth + 30,
content: Row(
children: [
Expanded(
child: TextFormBox(
placeholder: translations.settingsServerMirrorPlaceholder,
controller: _dllController.aboveS20Mirror,
onChanged: (value) {
if(Uri.tryParse(value) != null) {
_dllController.updateGameServerDll(force: true);
}
},
),
),
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: () => _dllController.updateGameServerDll(force: true),
child: SizedBox.square(
dimension: 30,
child: Icon(
FluentIcons.arrow_download_24_regular
),
)
),
const SizedBox(width: 8.0),
Button(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: () {
_dllController.aboveS20Mirror.text = kRebootBelowS20DownloadUrl;
_dllController.updateGameServerDll(force: true);
},
child: SizedBox.square(
dimension: 30,
child: Icon(
FluentIcons.arrow_reset_24_regular
),
)
)
],
)
);
}else {
return createFileSetting(
title: translations.settingsNewServerFileName,
description: translations.settingsServerFileDescription,
controller: _dllController.gameServerDll,
onReset: () {

View File

@@ -7,7 +7,6 @@ import 'package:reboot_launcher/src/controller/game_controller.dart';
import 'package:reboot_launcher/src/controller/settings_controller.dart';
import 'package:reboot_launcher/src/messenger/abstract/overlay.dart';
import 'package:reboot_launcher/src/messenger/implementation/data.dart';
import 'package:reboot_launcher/src/messenger/implementation/onboard.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/util/translations.dart';
@@ -38,7 +37,6 @@ class PlayPage extends RebootPage {
}
class _PlayPageState extends RebootPageState<PlayPage> {
final SettingsController _settingsController = Get.find<SettingsController>();
final GameController _gameController = Get.find<GameController>();
final DllController _dllController = Get.find<DllController>();

View File

@@ -6,7 +6,6 @@ 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/messenger/abstract/dialog.dart';
import 'package:reboot_launcher/src/messenger/implementation/data.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/util/translations.dart';
@@ -42,7 +41,6 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
List<Widget> get settings => [
_language,
_theme,
_debugMode,
_installationDirectory,
];
@@ -100,29 +98,6 @@ class _SettingsPageState extends RebootPageState<SettingsPage> {
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: [
Obx(() => 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 {

View File

@@ -24,10 +24,13 @@ bool get isWin11 {
return intBuild != null && intBuild > 22000;
}
Future<String?> openFolderPicker(String title) async =>
await FilePicker.platform.getDirectoryPath(dialogTitle: title);
Future<String?> openFolderPicker(String title) async {
FilePicker.platform = FilePickerWindows();
return await FilePicker.platform.getDirectoryPath(dialogTitle: title);
}
Future<String?> openFilePicker(String extension) async {
FilePicker.platform = FilePickerWindows();
var result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: false,
@@ -93,7 +96,7 @@ class IVirtualDesktop extends IUnknown {
throw WindowsException(code);
}
return convertFromHString(result.value);
return _convertFromHString(result.value);
}
}
@@ -280,7 +283,7 @@ class _IVirtualDesktopManagerInternal extends IUnknown {
HRESULT Function(Pointer, COMObject, Int8)>>>()
.value
.asFunction<int Function(Pointer, COMObject, int)>()(
ptr.ref.lpVtbl, desktop.ptr.ref, convertToHString(newName));
ptr.ref.lpVtbl, desktop.ptr.ref, _convertToHString(newName));
if (code != 0) {
throw WindowsException(code);
}
@@ -369,7 +372,7 @@ List<int> _getHWnds(int pid, String? excludedWindowName) {
result.ref.excluded = excludedWindowName.toNativeUtf16();
}
EnumWindows(Pointer.fromFunction<EnumWindowsProc>(_filter, TRUE), result.address);
EnumWindows(Pointer.fromFunction<WNDENUMPROC>(_filter, TRUE), result.address);
final length = result.ref.HWndLength;
final HWndsPointer = result.ref.HWnd;
if(HWndsPointer == nullptr) {
@@ -397,7 +400,7 @@ class VirtualDesktopManager {
}
final hr = CoInitializeEx(
nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
nullptr, COINIT.COINIT_APARTMENTTHREADED | COINIT.COINIT_DISABLE_OLE1DDE);
if (FAILED(hr)) {
throw WindowsException(hr);
}
@@ -468,3 +471,19 @@ class VirtualDesktopManager {
void setDesktopName(IVirtualDesktop desktop, String newName) =>
windowManager.setDesktopName(desktop, newName);
}
String _convertFromHString(int hstring) =>
WindowsGetStringRawBuffer(hstring, nullptr).toDartString();
int _convertToHString(String string) {
final hString = calloc<HSTRING>();
final stringPtr = string.toNativeUtf16();
try {
final hr = WindowsCreateString(stringPtr, string.length, hString);
if (FAILED(hr)) throw WindowsException(hr);
return hString.value;
} finally {
free(stringPtr);
free(hString);
}
}

View File

@@ -0,0 +1,63 @@
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';
final _hive = HKEY_CURRENT_USER;
void registerUrlProtocol(String scheme, {String? executable, List<String>? arguments}) {
final prefix = _regPrefix(scheme);
final capitalized = scheme[0].toUpperCase() + scheme.substring(1);
final args = _getArguments(arguments).map((a) => _sanitize(a));
final cmd =
'${executable ?? Platform.resolvedExecutable} ${args.join(' ')}';
_regCreateStringKey(_hive, prefix, '', 'URL:$capitalized');
_regCreateStringKey(_hive, prefix, 'URL Protocol', '');
_regCreateStringKey(_hive, prefix + '\\shell\\open\\command', '', cmd);
}
void unregisterUrlProtocol(String scheme) {
final txtKey = TEXT(_regPrefix(scheme));
try {
RegDeleteTree(HKEY_CURRENT_USER, txtKey);
} finally {
free(txtKey);
}
}
String _regPrefix(String scheme) => 'SOFTWARE\\Classes\\$scheme';
int _regCreateStringKey(int hKey, String key, String valueName, String data) {
final txtKey = TEXT(key);
final txtValue = TEXT(valueName);
final txtData = TEXT(data);
try {
return RegSetKeyValue(
hKey,
txtKey,
txtValue,
REG_VALUE_TYPE.REG_SZ,
txtData,
txtData.length * 2 + 2,
);
} finally {
free(txtKey);
free(txtValue);
free(txtData);
}
}
String _sanitize(String value) {
value = value.replaceAll(r'%s', '%1').replaceAll(r'"', '\\"');
return '"$value"';
}
List<String> _getArguments(List<String>? arguments) {
if (arguments == null) return ['%s'];
if (arguments.isEmpty && !arguments.any((e) => e.contains('%s'))) {
throw ArgumentError('arguments must contain at least 1 instance of "%s"');
}
return arguments;
}

View File

@@ -1,7 +1,7 @@
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
import 'package:fluent_ui/fluent_ui.dart' as fluentIcons show FluentIcons;
import 'package:fluent_ui/fluent_ui.dart' hide FluentIcons;
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
@@ -23,7 +23,7 @@ SettingTile createFileSetting({required String title, required String descriptio
),
title: Text(title),
subtitle: Text(description),
contentWidth: SettingTile.kDefaultContentWidth + _kButtonDimensions * 2 + _kButtonSpacing * 2,
contentWidth: SettingTile.kDefaultContentWidth + _kButtonDimensions,
content: Row(
children: [
Expanded(
@@ -47,7 +47,7 @@ SettingTile createFileSetting({required String title, required String descriptio
message: translations.selectFile,
child: Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: () => _onPressed(selecting, controller),
child: SizedBox.square(
@@ -68,7 +68,7 @@ SettingTile createFileSetting({required String title, required String descriptio
message: translations.reset,
child: Button(
style: ButtonStyle(
padding: ButtonState.all(EdgeInsets.zero)
padding: WidgetStateProperty.all(EdgeInsets.zero)
),
onPressed: onReset,
child: SizedBox.square(

View File

@@ -121,7 +121,7 @@ class _LaunchButtonState extends State<LaunchButton> {
return;
}
log("[${host ? 'HOST' : 'GAME'}] Backend works");
final serverType = _settingsController.debug.value ? GameServerType.window : _hostingController.type.value;
final serverType = _hostingController.type.value;
log("[${host ? 'HOST' : 'GAME'}] Implicit game server metadata: headless($serverType)");
final linkedHostingInstance = await _startMatchMakingServer(version, host, serverType, false);
log("[${host ? 'HOST' : 'GAME'}] Implicit game server result: $linkedHostingInstance");
@@ -159,11 +159,6 @@ class _LaunchButtonState extends State<LaunchButton> {
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)) {
log("[${host ? 'HOST' : 'GAME'}] Backend is not set to embedded and/or not pointing to the local game server");
return null;
@@ -248,7 +243,7 @@ class _LaunchButtonState extends State<LaunchButton> {
}else{
_gameController.instance.value = instance;
}
await _injectOrShowError(InjectableDll.cobalt, host);
await _injectOrShowError(InjectableDll.sinum, host);
log("[${host ? 'HOST' : 'GAME'}] Finished creating game instance");
return instance;
}
@@ -280,13 +275,7 @@ class _LaunchButtonState extends State<LaunchButton> {
line: line,
host: host,
onShutdown: () => _onStop(reason: _StopReason.normal),
onTokenError: () {
if(_settingsController.debug.value) {
log("[PROCESS] Ignoring token error because debug mode is on");
}else {
_onStop(reason: _StopReason.tokenError);
}
},
onTokenError: () => _onStop(reason: _StopReason.tokenError),
onBuildCorrupted: () {
if(instance == null) {
return;
@@ -687,10 +676,6 @@ class _LaunchButtonState extends State<LaunchButton> {
}
log("[${hosting ? 'HOST' : 'GAME'}] Trying to inject ${injectable.name}...");
if(_settingsController.debug.value) {
return;
}
await injectDll(gameProcess, dllPath);
instance.injectedDlls.add(injectable);
log("[${hosting ? 'HOST' : 'GAME'}] Injected ${injectable.name}");
@@ -742,7 +727,7 @@ class _LaunchButtonState extends State<LaunchButton> {
loading: true,
duration: null,
action: Obx(() {
if(_settingsController.debug.value || _hostingController.started.value || linkedHosting) {
if(_hostingController.started.value || linkedHosting) {
return const SizedBox.shrink();
}

View File

@@ -15,11 +15,11 @@ import 'package:url_launcher/url_launcher.dart';
class VersionSelector extends StatefulWidget {
const VersionSelector({Key? key}) : super(key: key);
static Future<void> openDownloadDialog({bool closable = true}) => showRebootDialog<bool>(
static Future<void> openDownloadDialog() => showRebootDialog<bool>(
builder: (context) => AddVersionDialog(
closable: closable,
closable: true,
),
dismissWithEsc: closable
dismissWithEsc: true
);
@override