<feat: New project structure>

<feat: New release>
This commit is contained in:
Alessandro Autiero
2023-09-02 15:34:15 +02:00
parent 64b33102f4
commit b41e22adeb
953 changed files with 1373072 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart';
class AuthenticatorController extends ServerController {
AuthenticatorController() : super();
@override
String get controllerName => "authenticator";
@override
String get storageName => "reboot_authenticator";
@override
String get defaultHost => kDefaultAuthenticatorHost;
@override
String get defaultPort => kDefaultAuthenticatorPort;
@override
Future<bool> get isPortFree => isAuthenticatorPortFree();
@override
Future<bool> freePort() => freeAuthenticatorPort();
}

View File

@@ -0,0 +1,24 @@
import 'package:get/get.dart';
import 'package:reboot_common/common.dart';
class BuildController extends GetxController {
List<FortniteBuild>? _builds;
Rxn<FortniteBuild> selectedBuild;
BuildController() : selectedBuild = Rxn();
List<FortniteBuild>? get builds => _builds;
set builds(List<FortniteBuild>? builds) {
_builds = builds;
if(builds == null || builds.isEmpty){
return;
}
selectedBuild.value = builds[0];
}
void reset(){
_builds = null;
selectedBuild.value = null;
}
}

View File

@@ -0,0 +1,125 @@
import 'dart:async';
import 'dart:convert';
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:uuid/uuid.dart';
class GameController extends GetxController {
late final String uuid;
late final GetStorage _storage;
late final TextEditingController username;
late final TextEditingController password;
late final TextEditingController customLaunchArgs;
late final Rx<List<FortniteVersion>> versions;
late final Rxn<FortniteVersion> _selectedVersion;
late final RxBool started;
late final RxBool autoStartGameServer;
late final Rxn<Set<Map<String, dynamic>>> servers;
late final Rxn<GameInstance> instance;
GameController() {
_storage = GetStorage("reboot_game");
Iterable decodedVersionsJson = jsonDecode(_storage.read("versions") ?? "[]");
var decodedVersions = decodedVersionsJson
.map((entry) => FortniteVersion.fromJson(entry))
.toList();
versions = Rx(decodedVersions);
versions.listen((data) => _saveVersions());
var decodedSelectedVersionName = _storage.read("version");
var decodedSelectedVersion = decodedVersions.firstWhereOrNull((element) => element.name == decodedSelectedVersionName);
uuid = _storage.read("uuid") ?? const Uuid().v4();
_storage.write("uuid", uuid);
_selectedVersion = Rxn(decodedSelectedVersion);
username = TextEditingController(text: _storage.read("username") ?? kDefaultPlayerName);
username.addListener(() => _storage.write("username", username.text));
password = TextEditingController(text: _storage.read("password") ?? "");
password.addListener(() => _storage.write("password", password.text));
customLaunchArgs = TextEditingController(text: _storage.read("custom_launch_args") ?? "");
customLaunchArgs.addListener(() => _storage.write("custom_launch_args", customLaunchArgs.text));
started = RxBool(false);
autoStartGameServer = RxBool(_storage.read("auto_game_server") ?? true);
autoStartGameServer.listen((value) => _storage.write("auto_game_server", value));
var supabase = Supabase.instance.client;
servers = Rxn();
supabase.from('hosts')
.stream(primaryKey: ['id'])
.map((event) => event.where((element) => element["ip"] != null).toSet())
.listen((event) {
if(servers.value == null) {
servers.value = event;
}else {
servers.value?.addAll(event);
}
});
var serializedInstance = _storage.read("instance");
instance = Rxn(serializedInstance != null ? GameInstance.fromJson(jsonDecode(serializedInstance)) : null);
instance.listen((value) => _storage.write("instance", jsonEncode(value?.toJson())));
}
void reset() {
username.text = kDefaultPlayerName;
password.text = "";
customLaunchArgs.text = "";
versions.value = [];
autoStartGameServer.value = true;
instance.value = null;
}
FortniteVersion? getVersionByName(String name) {
return versions.value.firstWhereOrNull((element) => element.name == name);
}
void addVersion(FortniteVersion version) {
var empty = versions.value.isEmpty;
versions.update((val) => val?.add(version));
if(empty){
selectedVersion = version;
}
}
FortniteVersion removeVersionByName(String versionName) {
var version = versions.value.firstWhere((element) => element.name == versionName);
removeVersion(version);
return version;
}
void removeVersion(FortniteVersion version) {
versions.update((val) => val?.remove(version));
if (selectedVersion?.name == version.name || hasNoVersions) {
selectedVersion = null;
}
}
Future<void> _saveVersions() async {
var serialized = jsonEncode(versions.value.map((entry) => entry.toJson()).toList());
await _storage.write("versions", serialized);
}
bool get hasVersions => versions.value.isNotEmpty;
bool get hasNoVersions => versions.value.isEmpty;
FortniteVersion? get selectedVersion => _selectedVersion();
set selectedVersion(FortniteVersion? version) {
_selectedVersion.value = version;
_storage.write("version", version?.name);
}
void updateVersion(FortniteVersion version, Function(FortniteVersion) function) {
versions.update((val) => function(version));
}
Map<String, dynamic>? findServerById(String uuid) {
try {
print(uuid);
return servers.value?.firstWhere((element) => element["id"] == uuid);
} on StateError catch(_) {
return null;
}
}
}

View File

@@ -0,0 +1,46 @@
import 'dart:convert';
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
const String kDefaultServerName = "Reboot Game Server";
const String kDefaultDescription = "Just another server";
class HostingController extends GetxController {
late final GetStorage _storage;
late final TextEditingController name;
late final TextEditingController description;
late final TextEditingController password;
late final RxBool showPassword;
late final RxBool discoverable;
late final RxBool started;
late final Rxn<GameInstance> instance;
HostingController() {
_storage = GetStorage("reboot_hosting");
name = TextEditingController(text: _storage.read("name") ?? kDefaultServerName);
name.addListener(() => _storage.write("name", name.text));
description = TextEditingController(text: _storage.read("description") ?? kDefaultDescription);
description.addListener(() => _storage.write("description", description.text));
password = TextEditingController(text: _storage.read("password") ?? "");
password.addListener(() => _storage.write("password", password.text));
discoverable = RxBool(_storage.read("discoverable") ?? true);
discoverable.listen((value) => _storage.write("discoverable", value));
started = RxBool(false);
showPassword = RxBool(false);
var serializedInstance = _storage.read("instance");
instance = Rxn(serializedInstance != null ? GameInstance.fromJson(jsonDecode(serializedInstance)) : null);
instance.listen((value) => _storage.write("instance", jsonEncode(value?.toJson())));
}
void reset() {
name.text = kDefaultServerName;
description.text = kDefaultDescription;
showPassword.value = false;
discoverable.value = false;
started.value = false;
instance.value = null;
}
}

View File

@@ -0,0 +1,30 @@
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:reboot_common/common.dart';
import 'package:reboot_launcher/src/controller/server_controller.dart';
class MatchmakerController extends ServerController {
late final TextEditingController gameServerAddress;
MatchmakerController() : super() {
gameServerAddress = TextEditingController(text: storage.read("game_server_address") ?? kDefaultMatchmakerHost);
gameServerAddress.addListener(() => storage.write("game_server_address", gameServerAddress.text));
}
@override
String get controllerName => "matchmaker";
@override
String get storageName => "reboot_matchmaker";
@override
String get defaultHost => kDefaultMatchmakerHost;
@override
String get defaultPort => kDefaultMatchmakerPort;
@override
Future<bool> get isPortFree => isMatchmakerPortFree();
@override
Future<bool> freePort() => freeMatchmakerPort();
}

View File

@@ -0,0 +1,189 @@
import 'dart:async';
import 'dart:io';
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
import 'package:sync/semaphore.dart';
abstract class ServerController extends GetxController {
late final GetStorage storage;
late final TextEditingController host;
late final TextEditingController port;
late final Rx<ServerType> type;
late final Semaphore semaphore;
late RxBool started;
late RxBool detached;
Process? embeddedServer;
HttpServer? localServer;
HttpServer? remoteServer;
ServerController() {
storage = GetStorage(storageName);
started = RxBool(false);
type = Rx(ServerType.values.elementAt(storage.read("type") ?? 0));
type.listen((value) {
host.text = _readHost();
port.text = _readPort();
storage.write("type", value.index);
if (!started.value) {
return;
}
stop();
});
host = TextEditingController(text: _readHost());
host.addListener(() =>
storage.write("${type.value.name}_host", host.text));
port = TextEditingController(text: _readPort());
port.addListener(() =>
storage.write("${type.value.name}_port", port.text));
detached = RxBool(storage.read("detached") ?? false);
detached.listen((value) => storage.write("detached", value));
semaphore = Semaphore();
}
String get controllerName;
String get storageName;
String get defaultHost;
String get defaultPort;
Future<bool> get isPortFree;
Future<bool> get isPortTaken async => !(await isPortFree);
Future<bool> freePort();
void reset() async {
type.value = ServerType.values.elementAt(0);
for (var type in ServerType.values) {
storage.write("${type.name}_host", null);
storage.write("${type.name}_port", null);
}
host.text = type.value != ServerType.remote ? defaultHost : "";
port.text = defaultPort;
detached.value = false;
}
String _readHost() {
String? value = storage.read("${type.value.name}_host");
return value != null && value.isNotEmpty ? value
: type.value != ServerType.remote ? defaultHost : "";
}
String _readPort() =>
storage.read("${type.value.name}_port") ?? defaultPort;
Stream<ServerResult> start() async* {
try {
var host = this.host.text.trim();
if (host.isEmpty) {
yield ServerResult(ServerResultType.missingHostError);
return;
}
var port = this.port.text.trim();
if (port.isEmpty) {
yield ServerResult(ServerResultType.missingPortError);
return;
}
var portNumber = int.tryParse(port);
if (portNumber == null) {
yield ServerResult(ServerResultType.illegalPortError);
return;
}
if (type() != ServerType.local && await isPortTaken) {
yield ServerResult(ServerResultType.freeingPort);
var result = await freePort();
yield ServerResult(result ? ServerResultType.freePortSuccess : ServerResultType.freePortError);
if(!result) {
return;
}
}
switch(type()){
case ServerType.embedded:
embeddedServer = await startEmbeddedAuthenticator(detached());
break;
case ServerType.remote:
yield ServerResult(ServerResultType.pingingRemote);
var uriResult = await ping(host, port);
if(uriResult == null) {
yield ServerResult(ServerResultType.pingError);
return;
}
remoteServer = await startRemoteAuthenticatorProxy(uriResult);
break;
case ServerType.local:
if(port != defaultPort) {
localServer = await startRemoteAuthenticatorProxy(Uri.parse("http://$defaultHost:$defaultPort"));
}
break;
}
yield ServerResult(ServerResultType.pingingLocal);
var uriResult = await pingSelf(defaultPort);
if(uriResult == null) {
yield ServerResult(ServerResultType.pingError);
return;
}
yield ServerResult(ServerResultType.startSuccess);
started.value = true;
}catch(error, stackTrace) {
yield ServerResult(
ServerResultType.startError,
error: error,
stackTrace: stackTrace
);
}
}
Future<bool> stop() async {
started.value = false;
try{
switch(type()){
case ServerType.embedded:
freePort();
break;
case ServerType.remote:
await remoteServer?.close(force: true);
remoteServer = null;
break;
case ServerType.local:
await localServer?.close(force: true);
localServer = null;
break;
}
return true;
}catch(_){
started.value = true;
return false;
}
}
Stream<ServerResult> restart() async* {
await resetWinNat();
if(started()) {
await stop();
}
yield* start();
}
Stream<ServerResult> toggle() async* {
if(started()) {
await stop();
}else {
yield* start();
}
}
}

View File

@@ -0,0 +1,63 @@
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_launcher/main.dart';
import 'package:reboot_common/common.dart';
import 'package:window_manager/window_manager.dart';
class SettingsController extends GetxController {
static const String _kDefaultIp = "127.0.0.1";
late final GetStorage _storage;
late final String originalDll;
late final TextEditingController rebootDll;
late final TextEditingController consoleDll;
late final TextEditingController authDll;
late final RxBool firstRun;
late double width;
late double height;
late double? offsetX;
late double? offsetY;
late double scrollingDistance;
SettingsController() {
_storage = GetStorage("reboot_settings");
rebootDll = _createController("reboot", "reboot.dll");
consoleDll = _createController("console", "console.dll");
authDll = _createController("cobalt", "cobalt.dll");
width = _storage.read("width") ?? kDefaultWindowWidth;
height = _storage.read("height") ?? kDefaultWindowHeight;
offsetX = _storage.read("offset_x");
offsetY = _storage.read("offset_y");
scrollingDistance = 0.0;
firstRun = RxBool(_storage.read("first_run") ?? true);
firstRun.listen((value) => _storage.write("first_run", value));
}
TextEditingController _createController(String key, String name) {
var controller = TextEditingController(text: _storage.read(key) ?? _controllerDefaultPath(name));
controller.addListener(() => _storage.write(key, controller.text));
return controller;
}
void saveWindowSize() async {
var size = await windowManager.getSize();
_storage.write("width", size.width);
_storage.write("height", size.height);
}
void saveWindowOffset(Offset position) {
_storage.write("offset_x", position.dx);
_storage.write("offset_y", position.dy);
}
void reset(){
rebootDll.text = _controllerDefaultPath("reboot.dll");
consoleDll.text = _controllerDefaultPath("console.dll");
authDll.text = _controllerDefaultPath("cobalt.dll");
firstRun.value = true;
writeMatchmakingIp(_kDefaultIp);
}
String _controllerDefaultPath(String name) => "${assetsDirectory.path}\\dlls\\$name";
}

View File

@@ -0,0 +1,47 @@
import 'package:fluent_ui/fluent_ui.dart' hide showDialog;
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:reboot_common/common.dart';
class UpdateController {
late final GetStorage _storage;
late final RxnInt timestamp;
late final Rx<UpdateStatus> status;
late final Rx<UpdateTimer> timer;
late final TextEditingController url;
UpdateController() {
_storage = GetStorage("reboot_update");
timestamp = RxnInt(_storage.read("ts"));
timestamp.listen((value) => _storage.write("ts", value));
var timerIndex = _storage.read("timer");
timer = Rx(timerIndex == null ? UpdateTimer.never : UpdateTimer.values.elementAt(timerIndex));
timer.listen((value) => _storage.write("timer", value.index));
url = TextEditingController(text: _storage.read("update_url") ?? rebootDownloadUrl);
url.addListener(() => _storage.write("update_url", url.text));
status = Rx(UpdateStatus.waiting);
}
Future<void> update() async {
if(timer.value == UpdateTimer.never) {
status.value = UpdateStatus.success;
return;
}
try {
timestamp.value = await downloadRebootDll(url.text, timestamp.value);
status.value = UpdateStatus.success;
}catch(_) {
status.value = UpdateStatus.error;
rethrow;
}
}
void reset() {
timestamp.value = null;
timer.value = UpdateTimer.never;
url.text = rebootDownloadUrl;
status.value = UpdateStatus.waiting;
update();
}
}