mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 19:22:22 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d83dc1c5 | ||
|
|
d53a577f0b | ||
|
|
c9ed6a5af3 | ||
|
|
4ea73d17c7 | ||
|
|
52abf5eb95 |
@@ -1,18 +1,21 @@
|
|||||||
export 'package:reboot_common/src/constant/backend.dart';
|
export 'package:reboot_common/src/backend/auth_backend_constants.dart';
|
||||||
export 'package:reboot_common/src/constant/game.dart';
|
export 'package:reboot_common/src/backend/auth_backend_helper.dart';
|
||||||
export 'package:reboot_common/src/constant/supabase.dart';
|
export 'package:reboot_common/src/backend/auth_backend_result.dart';
|
||||||
export 'package:reboot_common/src/model/fortnite_build.dart';
|
export 'package:reboot_common/src/backend/auth_backend_type.dart';
|
||||||
export 'package:reboot_common/src/model/fortnite_version.dart';
|
|
||||||
export 'package:reboot_common/src/model/game_instance.dart';
|
export 'package:reboot_common/src/browser/server_browser_client.dart';
|
||||||
export 'package:reboot_common/src/model/server_result.dart';
|
export 'package:reboot_common/src/browser/server_browser_entry.dart';
|
||||||
export 'package:reboot_common/src/model/server_type.dart';
|
export 'package:reboot_common/src/browser/server_browser_event.dart';
|
||||||
export 'package:reboot_common/src/model/update_status.dart';
|
export 'package:reboot_common/src/browser/server_browser_state.dart';
|
||||||
export 'package:reboot_common/src/model/update_timer.dart';
|
|
||||||
export 'package:reboot_common/src/model/fortnite_server.dart';
|
export 'package:reboot_common/src/game/game_build.dart';
|
||||||
export 'package:reboot_common/src/model/dll.dart';
|
export 'package:reboot_common/src/game/game_constants.dart';
|
||||||
export 'package:reboot_common/src/util/backend.dart';
|
export 'package:reboot_common/src/game/game_dll.dart';
|
||||||
export 'package:reboot_common/src/util/downloader.dart';
|
export 'package:reboot_common/src/game/game_downloader.dart';
|
||||||
|
export 'package:reboot_common/src/game/game_instance.dart';
|
||||||
|
export 'package:reboot_common/src/game/game_metadata.dart';
|
||||||
|
export 'package:reboot_common/src/game/game_version.dart';
|
||||||
|
|
||||||
|
export 'package:reboot_common/src/util/extensions.dart';
|
||||||
|
export 'package:reboot_common/src/util/logger.dart';
|
||||||
export 'package:reboot_common/src/util/os.dart';
|
export 'package:reboot_common/src/util/os.dart';
|
||||||
export 'package:reboot_common/src/util/log.dart';
|
|
||||||
export 'package:reboot_common/src/util/game.dart';
|
|
||||||
export 'package:reboot_common/src/util/extensions.dart';
|
|
||||||
@@ -15,93 +15,95 @@ final Semaphore _semaphore = Semaphore();
|
|||||||
String? _lastIp;
|
String? _lastIp;
|
||||||
String? _lastPort;
|
String? _lastPort;
|
||||||
|
|
||||||
Stream<ServerResult> startBackend({
|
typedef BackendErrorHandler = void Function(String);
|
||||||
required ServerType type,
|
|
||||||
|
Stream<AuthBackendEvent> startAuthBackend({
|
||||||
|
required AuthBackendType type,
|
||||||
required String host,
|
required String host,
|
||||||
required String port,
|
required String port,
|
||||||
required bool detached,
|
required bool detached,
|
||||||
required void Function(String) onError
|
required BackendErrorHandler? onError
|
||||||
}) async* {
|
}) async* {
|
||||||
Process? process;
|
Process? process;
|
||||||
HttpServer? server;
|
HttpServer? server;
|
||||||
try {
|
try {
|
||||||
host = host.trim();
|
host = host.trim();
|
||||||
port = port.trim();
|
port = port.trim();
|
||||||
if(type != ServerType.local || port != kDefaultBackendPort.toString()) {
|
if(type != AuthBackendType.local || port != kDefaultBackendPort.toString()) {
|
||||||
yield ServerResult(ServerResultType.starting);
|
yield AuthBackendEvent(AuthBackendEventType.starting);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (host.isEmpty) {
|
if (host.isEmpty) {
|
||||||
yield ServerResult(ServerResultType.startMissingHostError);
|
yield AuthBackendEvent(AuthBackendEventType.startMissingHostError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port.isEmpty) {
|
if (port.isEmpty) {
|
||||||
yield ServerResult(ServerResultType.startMissingPortError);
|
yield AuthBackendEvent(AuthBackendEventType.startMissingPortError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final portNumber = int.tryParse(port);
|
final portNumber = int.tryParse(port);
|
||||||
if (portNumber == null) {
|
if (portNumber == null) {
|
||||||
yield ServerResult(ServerResultType.startIllegalPortError);
|
yield AuthBackendEvent(AuthBackendEventType.startIllegalPortError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type != ServerType.local || port != kDefaultBackendPort.toString()) && !(await isBackendPortFree())) {
|
if ((type != AuthBackendType.local || port != kDefaultBackendPort.toString()) && !(await isAuthBackendPortFree())) {
|
||||||
yield ServerResult(ServerResultType.startFreeingPort);
|
yield AuthBackendEvent(AuthBackendEventType.startFreeingPort);
|
||||||
final result = await freeBackendPort();
|
final result = await freeAuthBackendPort();
|
||||||
if(!result) {
|
if(!result) {
|
||||||
yield ServerResult(ServerResultType.startFreePortError);
|
yield AuthBackendEvent(AuthBackendEventType.startFreePortError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ServerResult(ServerResultType.startFreePortSuccess);
|
yield AuthBackendEvent(AuthBackendEventType.startFreePortSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(type){
|
switch(type){
|
||||||
case ServerType.embedded:
|
case AuthBackendType.embedded:
|
||||||
process = await startEmbeddedBackend(detached, onError: onError);
|
process = await _startEmbedded(detached, onError: onError);
|
||||||
yield ServerResult(ServerResultType.startedImplementation, implementation: ServerImplementation(process: process));
|
yield AuthBackendEvent(AuthBackendEventType.startedImplementation, implementation: AuthBackendImplementation(process: process));
|
||||||
break;
|
break;
|
||||||
case ServerType.remote:
|
case AuthBackendType.remote:
|
||||||
yield ServerResult(ServerResultType.startPingingRemote);
|
yield AuthBackendEvent(AuthBackendEventType.startPingingRemote);
|
||||||
final uriResult = await pingBackend(host, portNumber);
|
final uriResult = await _ping(host, portNumber);
|
||||||
if(uriResult == null) {
|
if(uriResult == null) {
|
||||||
yield ServerResult(ServerResultType.startPingError);
|
yield AuthBackendEvent(AuthBackendEventType.startPingError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server = await startRemoteBackendProxy(uriResult);
|
server = await _startRemote(uriResult);
|
||||||
yield ServerResult(ServerResultType.startedImplementation, implementation: ServerImplementation(server: server));
|
yield AuthBackendEvent(AuthBackendEventType.startedImplementation, implementation: AuthBackendImplementation(server: server));
|
||||||
break;
|
break;
|
||||||
case ServerType.local:
|
case AuthBackendType.local:
|
||||||
if(portNumber != kDefaultBackendPort) {
|
if(portNumber != kDefaultBackendPort) {
|
||||||
yield ServerResult(ServerResultType.startPingingLocal);
|
yield AuthBackendEvent(AuthBackendEventType.startPingingLocal);
|
||||||
final uriResult = await pingBackend(kDefaultBackendHost, portNumber);
|
final uriResult = await _ping(kDefaultBackendHost, portNumber);
|
||||||
if(uriResult == null) {
|
if(uriResult == null) {
|
||||||
yield ServerResult(ServerResultType.startPingError);
|
yield AuthBackendEvent(AuthBackendEventType.startPingError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server = await startRemoteBackendProxy(Uri.parse("http://$kDefaultBackendHost:$port"));
|
server = await _startRemote(Uri.parse("http://$kDefaultBackendHost:$port"));
|
||||||
yield ServerResult(ServerResultType.startedImplementation, implementation: ServerImplementation(server: server));
|
yield AuthBackendEvent(AuthBackendEventType.startedImplementation, implementation: AuthBackendImplementation(server: server));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ServerResult(ServerResultType.startPingingLocal);
|
yield AuthBackendEvent(AuthBackendEventType.startPingingLocal);
|
||||||
final uriResult = await pingBackend(kDefaultBackendHost, kDefaultBackendPort);
|
final uriResult = await _ping(kDefaultBackendHost, kDefaultBackendPort);
|
||||||
if(uriResult == null) {
|
if(uriResult == null) {
|
||||||
yield ServerResult(ServerResultType.startPingError);
|
yield AuthBackendEvent(AuthBackendEventType.startPingError);
|
||||||
process?.kill(ProcessSignal.sigterm);
|
process?.kill(ProcessSignal.sigterm);
|
||||||
server?.close(force: true);
|
server?.close(force: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield ServerResult(ServerResultType.startSuccess);
|
yield AuthBackendEvent(AuthBackendEventType.startSuccess);
|
||||||
}catch(error, stackTrace) {
|
}catch(error, stackTrace) {
|
||||||
yield ServerResult(
|
yield AuthBackendEvent(
|
||||||
ServerResultType.startError,
|
AuthBackendEventType.startError,
|
||||||
error: error,
|
error: error,
|
||||||
stackTrace: stackTrace
|
stackTrace: stackTrace
|
||||||
);
|
);
|
||||||
@@ -110,34 +112,7 @@ Stream<ServerResult> startBackend({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<ServerResult> stopBackend({required ServerType type, required ServerImplementation? implementation}) async* {
|
Future<Process> _startEmbedded(bool detached, {BackendErrorHandler? onError}) async {
|
||||||
yield ServerResult(ServerResultType.stopping);
|
|
||||||
try{
|
|
||||||
switch(type){
|
|
||||||
case ServerType.embedded:
|
|
||||||
final process = implementation?.process;
|
|
||||||
if(process != null) {
|
|
||||||
Process.killPid(process.pid, ProcessSignal.sigterm);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ServerType.remote:
|
|
||||||
await implementation?.server?.close(force: true);
|
|
||||||
break;
|
|
||||||
case ServerType.local:
|
|
||||||
await implementation?.server?.close(force: true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
yield ServerResult(ServerResultType.stopSuccess);
|
|
||||||
}catch(error, stackTrace){
|
|
||||||
yield ServerResult(
|
|
||||||
ServerResultType.stopError,
|
|
||||||
error: error,
|
|
||||||
stackTrace: stackTrace
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Process> startEmbeddedBackend(bool detached, {void Function(String)? onError}) async {
|
|
||||||
final process = await startProcess(
|
final process = await startProcess(
|
||||||
executable: backendStartExecutable,
|
executable: backendStartExecutable,
|
||||||
window: detached,
|
window: detached,
|
||||||
@@ -164,22 +139,38 @@ Future<Process> startEmbeddedBackend(bool detached, {void Function(String)? onEr
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<HttpServer> startRemoteBackendProxy(Uri uri) async => await serve(proxyHandler(uri), kDefaultBackendHost, kDefaultBackendPort);
|
Future<HttpServer> _startRemote(Uri uri) async => await serve(proxyHandler(uri), kDefaultBackendHost, kDefaultBackendPort);
|
||||||
|
|
||||||
Future<bool> isBackendPortFree() async => await pingBackend(kDefaultBackendHost, kDefaultBackendPort) == null;
|
Stream<AuthBackendEvent> stopAuthBackend({required AuthBackendType type, required AuthBackendImplementation? implementation}) async* {
|
||||||
|
yield AuthBackendEvent(AuthBackendEventType.stopping);
|
||||||
Future<bool> freeBackendPort() async {
|
try{
|
||||||
await killProcessByPort(kDefaultBackendPort);
|
switch(type){
|
||||||
await killProcessByPort(kDefaultXmppPort);
|
case AuthBackendType.embedded:
|
||||||
final standardResult = await isBackendPortFree();
|
final process = implementation?.process;
|
||||||
if(standardResult) {
|
if(process != null) {
|
||||||
return true;
|
Process.killPid(process.pid, ProcessSignal.sigterm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AuthBackendType.remote:
|
||||||
|
await implementation?.server?.close(force: true);
|
||||||
|
break;
|
||||||
|
case AuthBackendType.local:
|
||||||
|
await implementation?.server?.close(force: true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield AuthBackendEvent(AuthBackendEventType.stopSuccess);
|
||||||
|
}catch(error, stackTrace){
|
||||||
|
yield AuthBackendEvent(
|
||||||
|
AuthBackendEventType.stopError,
|
||||||
|
error: error,
|
||||||
|
stackTrace: stackTrace
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Uri?> pingBackend(String host, int port, [bool https=false]) async {
|
Future<bool> isAuthBackendPortFree() async => await _ping(kDefaultBackendHost, kDefaultBackendPort) == null;
|
||||||
|
|
||||||
|
Future<Uri?> _ping(String host, int port, [bool https=false]) async {
|
||||||
final hostName = host.replaceFirst("http://", "").replaceFirst("https://", "");
|
final hostName = host.replaceFirst("http://", "").replaceFirst("https://", "");
|
||||||
final declaredScheme = host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null;
|
final declaredScheme = host.startsWith("http://") ? "http" : host.startsWith("https://") ? "https" : null;
|
||||||
try{
|
try{
|
||||||
@@ -198,7 +189,7 @@ Future<Uri?> pingBackend(String host, int port, [bool https=false]) async {
|
|||||||
return uri;
|
return uri;
|
||||||
}catch(error) {
|
}catch(error) {
|
||||||
log("[BACKEND] Cannot ping backend: $error");
|
log("[BACKEND] Cannot ping backend: $error");
|
||||||
return https || declaredScheme != null || isLocalHost(host) ? null : await pingBackend(host, port, true);
|
return https || declaredScheme != null || isLocalHost(host) ? null : await _ping(host, port, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +227,18 @@ Stream<String?> watchMatchmakingIp() async* {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> writeMatchmakingIp(String text) async {
|
Future<bool> freeAuthBackendPort() async {
|
||||||
|
await killProcessByPort(kDefaultBackendPort);
|
||||||
|
await killProcessByPort(kDefaultXmppPort);
|
||||||
|
final standardResult = await isAuthBackendPortFree();
|
||||||
|
if(standardResult) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> writeAuthBackendMatchmakingIp(String text) async {
|
||||||
final exists = await matchmakerConfigFile.exists();
|
final exists = await matchmakerConfigFile.exists();
|
||||||
if(!exists) {
|
if(!exists) {
|
||||||
return;
|
return;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
class ServerResult {
|
class AuthBackendEvent {
|
||||||
final ServerResultType type;
|
final AuthBackendEventType type;
|
||||||
final ServerImplementation? implementation;
|
final AuthBackendImplementation? implementation;
|
||||||
final Object? error;
|
final Object? error;
|
||||||
final StackTrace? stackTrace;
|
final StackTrace? stackTrace;
|
||||||
|
|
||||||
ServerResult(this.type, {this.implementation, this.error, this.stackTrace});
|
AuthBackendEvent(this.type, {this.implementation, this.error, this.stackTrace});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
@@ -14,14 +14,7 @@ class ServerResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServerImplementation {
|
enum AuthBackendEventType {
|
||||||
final Process? process;
|
|
||||||
final HttpServer? server;
|
|
||||||
|
|
||||||
ServerImplementation({this.process, this.server});
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ServerResultType {
|
|
||||||
starting,
|
starting,
|
||||||
startMissingHostError,
|
startMissingHostError,
|
||||||
startMissingPortError,
|
startMissingPortError,
|
||||||
@@ -39,9 +32,16 @@ enum ServerResultType {
|
|||||||
stopSuccess,
|
stopSuccess,
|
||||||
stopError;
|
stopError;
|
||||||
|
|
||||||
bool get isStart => name.contains("start");
|
bool get isStart => name.startsWith("start");
|
||||||
|
|
||||||
bool get isError => name.contains("Error");
|
bool get isError => name.endsWith("Error");
|
||||||
|
|
||||||
bool get isSuccess => this == ServerResultType.startSuccess || this == ServerResultType.stopSuccess;
|
bool get isSuccess => this == AuthBackendEventType.startSuccess || this == AuthBackendEventType.stopSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AuthBackendImplementation {
|
||||||
|
final Process? process;
|
||||||
|
final HttpServer? server;
|
||||||
|
|
||||||
|
AuthBackendImplementation({this.process, this.server});
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
enum ServerType {
|
enum AuthBackendType {
|
||||||
embedded,
|
embedded,
|
||||||
remote,
|
remote,
|
||||||
local
|
local
|
||||||
209
common/lib/src/browser/server_browser_client.dart
Normal file
209
common/lib/src/browser/server_browser_client.dart
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:reboot_common/common.dart';
|
||||||
|
|
||||||
|
class ServerBrowserClient {
|
||||||
|
static const String _pingEvent = 'ping';
|
||||||
|
static const String _addEvent = 'add';
|
||||||
|
static const String _removeEvent = 'remove';
|
||||||
|
static const Duration _pingInterval = const Duration(seconds: 30);
|
||||||
|
static const Duration _reconnectDelay = const Duration(seconds: 10);
|
||||||
|
static const Duration _timeout = const Duration(seconds: 10);
|
||||||
|
|
||||||
|
final String _serverUrl;
|
||||||
|
final StreamController<ServerBrowserEvent> _eventsController = StreamController.broadcast();
|
||||||
|
|
||||||
|
WebSocket? _socket;
|
||||||
|
Timer? _reconnectTimer;
|
||||||
|
Timer? _pingTimer;
|
||||||
|
Completer _pingCompleter = Completer();
|
||||||
|
ServerBrowserState _state = ServerBrowserState.disconnected;
|
||||||
|
|
||||||
|
ServerBrowserClient({required String serverUrl})
|
||||||
|
: _serverUrl = serverUrl;
|
||||||
|
|
||||||
|
Future<void> connect() async {
|
||||||
|
if (_state != ServerBrowserState.disconnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_setState(ServerBrowserState.connecting);
|
||||||
|
_reconnectTimer?.cancel();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final socket = await WebSocket.connect(_serverUrl)
|
||||||
|
.timeout(_timeout);
|
||||||
|
_socket = socket;
|
||||||
|
_setState(ServerBrowserState.connected);
|
||||||
|
socket.listen(
|
||||||
|
_handleMessage,
|
||||||
|
onDone: () => _handleDisconnection(_state == ServerBrowserState.connected),
|
||||||
|
onError: (error) {
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'An unhandled error was thrown: $error'
|
||||||
|
));
|
||||||
|
_handleDisconnection(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
_startHeartbeat();
|
||||||
|
} catch (e) {
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'Cannot connect: $e'
|
||||||
|
));
|
||||||
|
_handleDisconnection(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleMessage(dynamic data) {
|
||||||
|
try {
|
||||||
|
final message = jsonDecode(data);
|
||||||
|
final type = message['type'];
|
||||||
|
final payload = message['data'];
|
||||||
|
switch (type) {
|
||||||
|
case _pingEvent:
|
||||||
|
if(!_pingCompleter.isCompleted) {
|
||||||
|
_pingCompleter.complete(null);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _addEvent:
|
||||||
|
if (payload is List) {
|
||||||
|
final entries = payload
|
||||||
|
.map((entry) => ServerBrowserEntry.fromJson(entry))
|
||||||
|
.toList(growable: false);
|
||||||
|
_eventsController.add(new ServerBrowserAddEvent(
|
||||||
|
entries: entries,
|
||||||
|
));
|
||||||
|
}else {
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'Invalid add event payload: ${payload?.runtimeType}'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case _removeEvent:
|
||||||
|
if (payload is List) {
|
||||||
|
final entries = payload
|
||||||
|
.map((entry) => entry['id'] as String?)
|
||||||
|
.whereType<String>()
|
||||||
|
.toList(growable: false);
|
||||||
|
_eventsController.add(new ServerBrowserRemoveEvent(
|
||||||
|
entries: entries
|
||||||
|
));
|
||||||
|
}else {
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'Invalid remove event payload: ${payload?.runtimeType}'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'Invalid event type: $type'
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
_eventsController.add(new ServerBrowserErrorEvent(
|
||||||
|
error: 'An error occurred while processing an event: $error'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleDisconnection(bool reconnect) {
|
||||||
|
_setState(ServerBrowserState.disconnected);
|
||||||
|
_cleanup();
|
||||||
|
if (reconnect) {
|
||||||
|
_reconnectTimer = Timer(_reconnectDelay, () => connect());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startHeartbeat() {
|
||||||
|
_pingTimer?.cancel();
|
||||||
|
_pingTimer = Timer.periodic(_pingInterval, (timer) async {
|
||||||
|
final socket = _socket;
|
||||||
|
if(socket == null || _state != ServerBrowserState.connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
socket.add(jsonEncode({'type': _pingEvent}));
|
||||||
|
await _pingCompleter.future
|
||||||
|
.timeout(_timeout);
|
||||||
|
_pingCompleter = Completer();
|
||||||
|
} catch (error) {
|
||||||
|
_pingCompleter = Completer();
|
||||||
|
_handleDisconnection(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cleanup() {
|
||||||
|
_socket?.close();
|
||||||
|
_socket = null;
|
||||||
|
_pingTimer?.cancel();
|
||||||
|
_pingTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setState(ServerBrowserState newState) {
|
||||||
|
if (_state != newState) {
|
||||||
|
_state = newState;
|
||||||
|
_eventsController.add(ServerBrowserStateEvent(
|
||||||
|
state: newState
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> addEntry(ServerBrowserEntry entry) async {
|
||||||
|
if (_state != ServerBrowserState.connected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final socket = _socket;
|
||||||
|
if(socket == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final message = {
|
||||||
|
'type': _addEvent,
|
||||||
|
'data': entry.toJson()
|
||||||
|
};
|
||||||
|
socket.add(jsonEncode(message));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> removeEntry(String id) async {
|
||||||
|
if (_state != ServerBrowserState.connected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final socket = _socket;
|
||||||
|
if(socket == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final message = {
|
||||||
|
'type': _removeEvent,
|
||||||
|
'data': id
|
||||||
|
};
|
||||||
|
socket.add(jsonEncode(message));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamSubscription<ServerBrowserEvent> addListener(void Function(ServerBrowserEvent) onData) {
|
||||||
|
return _eventsController.stream.listen(onData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> disconnect() async {
|
||||||
|
_reconnectTimer?.cancel();
|
||||||
|
_cleanup();
|
||||||
|
_setState(ServerBrowserState.disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
disconnect();
|
||||||
|
_eventsController.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
class FortniteServer {
|
class ServerBrowserEntry {
|
||||||
final String id;
|
final String id;
|
||||||
final String name;
|
final String name;
|
||||||
final String description;
|
final String description;
|
||||||
final String author;
|
final String author;
|
||||||
final String ip;
|
final String ip;
|
||||||
final String version;
|
final String version;
|
||||||
final String? password;
|
final String password;
|
||||||
final DateTime timestamp;
|
final DateTime timestamp;
|
||||||
final bool discoverable;
|
|
||||||
|
|
||||||
FortniteServer({
|
ServerBrowserEntry({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.description,
|
required this.description,
|
||||||
@@ -18,10 +17,9 @@ class FortniteServer {
|
|||||||
required this.version,
|
required this.version,
|
||||||
required this.password,
|
required this.password,
|
||||||
required this.timestamp,
|
required this.timestamp,
|
||||||
required this.discoverable
|
|
||||||
});
|
});
|
||||||
|
|
||||||
factory FortniteServer.fromJson(json) => FortniteServer(
|
factory ServerBrowserEntry.fromJson(json) => ServerBrowserEntry(
|
||||||
id: json["id"],
|
id: json["id"],
|
||||||
name: json["name"],
|
name: json["name"],
|
||||||
description: json["description"],
|
description: json["description"],
|
||||||
@@ -29,8 +27,7 @@ class FortniteServer {
|
|||||||
ip: json["ip"],
|
ip: json["ip"],
|
||||||
version: json["version"],
|
version: json["version"],
|
||||||
password: json["password"],
|
password: json["password"],
|
||||||
timestamp: json.containsKey("json") ? DateTime.parse(json["timestamp"]) : DateTime.now(),
|
timestamp: json.containsKey("json") ? DateTime.parse(json["timestamp"]) : DateTime.now()
|
||||||
discoverable: json["discoverable"] ?? false
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
@@ -41,7 +38,6 @@ class FortniteServer {
|
|||||||
"ip": ip,
|
"ip": ip,
|
||||||
"version": version,
|
"version": version,
|
||||||
"password": password,
|
"password": password,
|
||||||
"timestamp": timestamp.toString(),
|
"timestamp": timestamp.toString()
|
||||||
"discoverable": discoverable
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
30
common/lib/src/browser/server_browser_event.dart
Normal file
30
common/lib/src/browser/server_browser_event.dart
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import 'package:reboot_common/common.dart';
|
||||||
|
import 'package:reboot_common/src/browser/server_browser_state.dart';
|
||||||
|
|
||||||
|
sealed class ServerBrowserEvent {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ServerBrowserStateEvent extends ServerBrowserEvent {
|
||||||
|
final ServerBrowserState state;
|
||||||
|
|
||||||
|
ServerBrowserStateEvent({required this.state});
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ServerBrowserAddEvent extends ServerBrowserEvent {
|
||||||
|
final List<ServerBrowserEntry> entries;
|
||||||
|
|
||||||
|
ServerBrowserAddEvent({required this.entries});
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ServerBrowserRemoveEvent extends ServerBrowserEvent {
|
||||||
|
final List<String> entries;
|
||||||
|
|
||||||
|
ServerBrowserRemoveEvent({required this.entries});
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ServerBrowserErrorEvent extends ServerBrowserEvent {
|
||||||
|
final String error;
|
||||||
|
|
||||||
|
ServerBrowserErrorEvent({required this.error});
|
||||||
|
}
|
||||||
5
common/lib/src/browser/server_browser_state.dart
Normal file
5
common/lib/src/browser/server_browser_state.dart
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
enum ServerBrowserState {
|
||||||
|
disconnected,
|
||||||
|
connecting,
|
||||||
|
connected
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
const String supabaseUrl = 'https://drxuhdtyigthmjfhjgfl.supabase.co';
|
|
||||||
const String supabaseAnonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImRyeHVoZHR5aWd0aG1qZmhqZ2ZsIiwicm9sZSI6ImFub24iLCJpYXQiOjE2ODUzMDU4NjYsImV4cCI6MjAwMDg4MTg2Nn0.unuO67xf9CZgHi-3aXmC5p3RAktUfW7WwqDY-ccFN1M';
|
|
||||||
64
common/lib/src/game/game_build.dart
Normal file
64
common/lib/src/game/game_build.dart
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
class GameBuild {
|
||||||
|
final String gameVersion;
|
||||||
|
final String link;
|
||||||
|
final bool available;
|
||||||
|
|
||||||
|
GameBuild({
|
||||||
|
required this.gameVersion,
|
||||||
|
required this.link,
|
||||||
|
required this.available
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameBuildDownloadProgress {
|
||||||
|
final double progress;
|
||||||
|
final int? timeLeft;
|
||||||
|
final bool extracting;
|
||||||
|
final int speed;
|
||||||
|
|
||||||
|
GameBuildDownloadProgress({
|
||||||
|
required this.progress,
|
||||||
|
required this.extracting,
|
||||||
|
required this.timeLeft,
|
||||||
|
required this.speed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameBuildDownloadOptions {
|
||||||
|
GameBuild build;
|
||||||
|
Directory destination;
|
||||||
|
SendPort port;
|
||||||
|
|
||||||
|
GameBuildDownloadOptions(this.build, this.destination, this.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameBuildManifestChunk {
|
||||||
|
List<int> chunksIds;
|
||||||
|
String file;
|
||||||
|
int fileSize;
|
||||||
|
|
||||||
|
GameBuildManifestChunk._internal(this.chunksIds, this.file, this.fileSize);
|
||||||
|
|
||||||
|
factory GameBuildManifestChunk.fromJson(json) => GameBuildManifestChunk._internal(
|
||||||
|
List<int>.from(json["ChunksIds"] as List),
|
||||||
|
json["File"],
|
||||||
|
json["FileSize"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameBuildManifestFile {
|
||||||
|
String name;
|
||||||
|
List<GameBuildManifestChunk> chunks;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
GameBuildManifestFile._internal(this.name, this.chunks, this.size);
|
||||||
|
|
||||||
|
factory GameBuildManifestFile.fromJson(json) => GameBuildManifestFile._internal(
|
||||||
|
json["Name"],
|
||||||
|
List<GameBuildManifestChunk>.from(json["Chunks"].map((chunk) => GameBuildManifestChunk.fromJson(chunk))),
|
||||||
|
json["Size"]
|
||||||
|
);
|
||||||
|
}
|
||||||
10
common/lib/src/game/game_dll.dart
Normal file
10
common/lib/src/game/game_dll.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
enum GameDll {
|
||||||
|
console,
|
||||||
|
auth,
|
||||||
|
gameServer,
|
||||||
|
memoryLeak
|
||||||
|
}
|
||||||
|
|
||||||
|
extension InjectableDllVersionAware on GameDll {
|
||||||
|
bool get isVersionDependent => this == GameDll.gameServer;
|
||||||
|
}
|
||||||
@@ -19,107 +19,103 @@ const String kRebootBelowS20DownloadUrl =
|
|||||||
const String kRebootAboveS20DownloadUrl =
|
const String kRebootAboveS20DownloadUrl =
|
||||||
"https://nightly.link/Milxnor/Project-Reboot-3.0/workflows/msbuild/master/RebootS20.zip";
|
"https://nightly.link/Milxnor/Project-Reboot-3.0/workflows/msbuild/master/RebootS20.zip";
|
||||||
|
|
||||||
const String _kRebootBelowS20FallbackDownloadUrl =
|
|
||||||
"https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/RebootFallback.zip";
|
|
||||||
const String _kRebootAboveS20FallbackDownloadUrl =
|
|
||||||
"https://github.com/Auties00/reboot_launcher/raw/master/gui/dependencies/dlls/RebootS20Fallback.zip";
|
|
||||||
|
|
||||||
const String kStopBuildDownloadSignal = "kill";
|
const String kStopBuildDownloadSignal = "kill";
|
||||||
|
|
||||||
final int _ariaPort = 6800;
|
final int _ariaPort = 6800;
|
||||||
final Uri _ariaEndpoint = Uri.parse('http://localhost:$_ariaPort/jsonrpc');
|
final Uri _ariaEndpoint = Uri.parse('http://localhost:$_ariaPort/jsonrpc');
|
||||||
final Duration _ariaMaxSpawnTime = const Duration(seconds: 10);
|
final Duration _ariaMaxSpawnTime = const Duration(seconds: 10);
|
||||||
final RegExp _rarProgressRegex = RegExp("^((100)|(\\d{1,2}(.\\d*)?))%\$");
|
final RegExp _rarProgressRegex = RegExp("^((100)|(\\d{1,2}(.\\d*)?))%\$");
|
||||||
final List<FortniteBuild> downloadableBuilds = [
|
final List<GameBuild> downloadableBuilds = [
|
||||||
FortniteBuild(gameVersion: "1.7.2", link: "https://public.simplyblk.xyz/1.7.2.zip", available: true),
|
GameBuild(gameVersion: "1.7.2", link: "https://builds.rebootfn.org/1.7.2.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "1.8", link: "https://public.simplyblk.xyz/1.8.rar", available: true),
|
GameBuild(gameVersion: "1.8", link: "https://builds.rebootfn.org/1.8.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.8.1", link: "https://public.simplyblk.xyz/1.8.1.rar", available: true),
|
GameBuild(gameVersion: "1.8.1", link: "https://builds.rebootfn.org/1.8.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.8.2", link: "https://public.simplyblk.xyz/1.8.2.rar", available: true),
|
GameBuild(gameVersion: "1.8.2", link: "https://builds.rebootfn.org/1.8.2.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.9", link: "https://public.simplyblk.xyz/1.9.rar", available: true),
|
GameBuild(gameVersion: "1.9", link: "https://builds.rebootfn.org/1.9.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.9.1", link: "https://public.simplyblk.xyz/1.9.1.rar", available: true),
|
GameBuild(gameVersion: "1.9.1", link: "https://builds.rebootfn.org/1.9.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.10", link: "https://public.simplyblk.xyz/1.10.rar", available: true),
|
GameBuild(gameVersion: "1.10", link: "https://builds.rebootfn.org/1.10.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "1.11", link: "https://public.simplyblk.xyz/1.11.zip", available: true),
|
GameBuild(gameVersion: "1.11", link: "https://builds.rebootfn.org/1.11.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "2.1.0", link: "https://public.simplyblk.xyz/2.1.0.zip", available: true),
|
GameBuild(gameVersion: "2.1.0", link: "https://builds.rebootfn.org/2.1.0.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "2.2.0", link: "https://public.simplyblk.xyz/2.2.0.rar", available: true),
|
GameBuild(gameVersion: "2.2.0", link: "https://builds.rebootfn.org/2.2.0.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "2.3", link: "https://public.simplyblk.xyz/2.3.rar", available: true),
|
GameBuild(gameVersion: "2.3", link: "https://builds.rebootfn.org/2.3.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "2.4.0", link: "https://public.simplyblk.xyz/2.4.0.zip", available: true),
|
GameBuild(gameVersion: "2.4.0", link: "https://builds.rebootfn.org/2.4.0.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "2.4.2", link: "https://public.simplyblk.xyz/2.4.2.zip", available: true),
|
GameBuild(gameVersion: "2.4.2", link: "https://builds.rebootfn.org/2.4.2.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "2.5.0", link: "https://public.simplyblk.xyz/2.5.0.rar", available: true),
|
GameBuild(gameVersion: "2.5.0", link: "https://builds.rebootfn.org/2.5.0.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "3.0", link: "https://public.simplyblk.xyz/3.0.zip", available: true),
|
GameBuild(gameVersion: "3.0", link: "https://builds.rebootfn.org/3.0.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "3.1", link: "https://public.simplyblk.xyz/3.1.rar", available: true),
|
GameBuild(gameVersion: "3.1", link: "https://builds.rebootfn.org/3.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "3.1.1", link: "https://public.simplyblk.xyz/3.1.1.zip", available: true),
|
GameBuild(gameVersion: "3.1.1", link: "https://builds.rebootfn.org/3.1.1.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "3.2", link: "https://public.simplyblk.xyz/3.2.zip", available: true),
|
GameBuild(gameVersion: "3.2", link: "https://builds.rebootfn.org/3.2.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "3.3", link: "https://public.simplyblk.xyz/3.3.rar", available: true),
|
GameBuild(gameVersion: "3.3", link: "https://builds.rebootfn.org/3.3.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "3.5", link: "https://public.simplyblk.xyz/3.5.rar", available: true),
|
GameBuild(gameVersion: "3.5", link: "https://builds.rebootfn.org/3.5.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "3.6", link: "https://public.simplyblk.xyz/3.6.zip", available: true),
|
GameBuild(gameVersion: "3.6", link: "https://builds.rebootfn.org/3.6.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "4.0", link: "https://public.simplyblk.xyz/4.0.zip", available: true),
|
GameBuild(gameVersion: "4.0", link: "https://builds.rebootfn.org/4.0.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "4.1", link: "https://public.simplyblk.xyz/4.1.zip", available: true),
|
GameBuild(gameVersion: "4.1", link: "https://builds.rebootfn.org/4.1.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "4.2", link: "https://public.simplyblk.xyz/4.2.zip", available: true),
|
GameBuild(gameVersion: "4.2", link: "https://builds.rebootfn.org/4.2.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "4.4", link: "https://public.simplyblk.xyz/4.4.rar", available: true),
|
GameBuild(gameVersion: "4.4", link: "https://builds.rebootfn.org/4.4.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "4.5", link: "https://public.simplyblk.xyz/4.5.rar", available: true),
|
GameBuild(gameVersion: "4.5", link: "https://builds.rebootfn.org/4.5.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.00", link: "https://public.simplyblk.xyz/5.00.rar", available: true),
|
GameBuild(gameVersion: "5.00", link: "https://builds.rebootfn.org/5.00.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.0.1", link: "https://public.simplyblk.xyz/5.0.1.rar", available: true),
|
GameBuild(gameVersion: "5.0.1", link: "https://builds.rebootfn.org/5.0.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.10", link: "https://public.simplyblk.xyz/5.10.rar", available: true),
|
GameBuild(gameVersion: "5.10", link: "https://builds.rebootfn.org/5.10.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.21", link: "https://public.simplyblk.xyz/5.21.rar", available: true),
|
GameBuild(gameVersion: "5.21", link: "https://builds.rebootfn.org/5.21.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.30", link: "https://public.simplyblk.xyz/5.30.rar", available: true),
|
GameBuild(gameVersion: "5.30", link: "https://builds.rebootfn.org/5.30.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "5.40", link: "https://public.simplyblk.xyz/5.40.rar", available: true),
|
GameBuild(gameVersion: "5.40", link: "https://builds.rebootfn.org/5.40.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.00", link: "https://public.simplyblk.xyz/6.00.rar", available: true),
|
GameBuild(gameVersion: "6.00", link: "https://builds.rebootfn.org/6.00.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.01", link: "https://public.simplyblk.xyz/6.01.rar", available: true),
|
GameBuild(gameVersion: "6.01", link: "https://builds.rebootfn.org/6.01.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.1.1", link: "https://public.simplyblk.xyz/6.1.1.rar", available: true),
|
GameBuild(gameVersion: "6.1.1", link: "https://builds.rebootfn.org/6.1.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.02", link: "https://public.simplyblk.xyz/6.02.rar", available: true),
|
GameBuild(gameVersion: "6.02", link: "https://builds.rebootfn.org/6.02.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.2.1", link: "https://public.simplyblk.xyz/6.2.1.rar", available: true),
|
GameBuild(gameVersion: "6.2.1", link: "https://builds.rebootfn.org/6.2.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.10", link: "https://public.simplyblk.xyz/6.10.rar", available: true),
|
GameBuild(gameVersion: "6.10", link: "https://builds.rebootfn.org/6.10.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.10.1", link: "https://public.simplyblk.xyz/6.10.1.rar", available: true),
|
GameBuild(gameVersion: "6.10.1", link: "https://builds.rebootfn.org/6.10.1.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.10.2", link: "https://public.simplyblk.xyz/6.10.2.rar", available: true),
|
GameBuild(gameVersion: "6.10.2", link: "https://builds.rebootfn.org/6.10.2.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.21", link: "https://public.simplyblk.xyz/6.21.rar", available: true),
|
GameBuild(gameVersion: "6.21", link: "https://builds.rebootfn.org/6.21.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.22", link: "https://public.simplyblk.xyz/6.22.rar", available: true),
|
GameBuild(gameVersion: "6.22", link: "https://builds.rebootfn.org/6.22.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.30", link: "https://public.simplyblk.xyz/6.30.rar", available: true),
|
GameBuild(gameVersion: "6.30", link: "https://builds.rebootfn.org/6.30.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "6.31", link: "https://public.simplyblk.xyz/6.31.rar", available: true),
|
GameBuild(gameVersion: "6.31", link: "https://builds.rebootfn.org/6.31.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "7.00", link: "https://public.simplyblk.xyz/7.00.rar", available: true),
|
GameBuild(gameVersion: "7.00", link: "https://builds.rebootfn.org/7.00.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "7.10", link: "https://public.simplyblk.xyz/7.10.rar", available: true),
|
GameBuild(gameVersion: "7.10", link: "https://builds.rebootfn.org/7.10.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "7.20", link: "https://public.simplyblk.xyz/7.20.rar", available: true),
|
GameBuild(gameVersion: "7.20", link: "https://builds.rebootfn.org/7.20.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "7.30", link: "https://public.simplyblk.xyz/7.30.zip", available: true),
|
GameBuild(gameVersion: "7.30", link: "https://builds.rebootfn.org/7.30.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "7.40", link: "https://public.simplyblk.xyz/7.40.rar", available: true),
|
GameBuild(gameVersion: "7.40", link: "https://builds.rebootfn.org/7.40.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "8.00", link: "https://public.simplyblk.xyz/8.00.zip", available: true),
|
GameBuild(gameVersion: "8.00", link: "https://builds.rebootfn.org/8.00.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "8.20", link: "https://public.simplyblk.xyz/8.20.rar", available: true),
|
GameBuild(gameVersion: "8.20", link: "https://builds.rebootfn.org/8.20.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "8.30", link: "https://public.simplyblk.xyz/8.30.rar", available: true),
|
GameBuild(gameVersion: "8.30", link: "https://builds.rebootfn.org/8.30.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "8.40", link: "https://public.simplyblk.xyz/8.40.zip", available: true),
|
GameBuild(gameVersion: "8.40", link: "https://builds.rebootfn.org/8.40.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "8.50", link: "https://public.simplyblk.xyz/8.50.zip", available: true),
|
GameBuild(gameVersion: "8.50", link: "https://builds.rebootfn.org/8.50.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "8.51", link: "https://public.simplyblk.xyz/8.51.rar", available: true),
|
GameBuild(gameVersion: "8.51", link: "https://builds.rebootfn.org/8.51.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "9.00", link: "https://public.simplyblk.xyz/9.00.zip", available: true),
|
GameBuild(gameVersion: "9.00", link: "https://builds.rebootfn.org/9.00.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "9.01", link: "https://public.simplyblk.xyz/9.01.zip", available: true),
|
GameBuild(gameVersion: "9.01", link: "https://builds.rebootfn.org/9.01.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "9.10", link: "https://public.simplyblk.xyz/9.10.rar", available: true),
|
GameBuild(gameVersion: "9.10", link: "https://builds.rebootfn.org/9.10.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "9.21", link: "https://public.simplyblk.xyz/9.21.zip", available: true),
|
GameBuild(gameVersion: "9.21", link: "https://builds.rebootfn.org/9.21.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "9.30", link: "https://public.simplyblk.xyz/9.30.zip", available: true),
|
GameBuild(gameVersion: "9.30", link: "https://builds.rebootfn.org/9.30.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "9.40", link: "https://public.simplyblk.xyz/9.40.zip", available: true),
|
GameBuild(gameVersion: "9.40", link: "https://builds.rebootfn.org/9.40.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "9.41", link: "https://public.simplyblk.xyz/9.41.rar", available: true),
|
GameBuild(gameVersion: "9.41", link: "https://builds.rebootfn.org/9.41.rar", available: true),
|
||||||
FortniteBuild(gameVersion: "10.00", link: "https://public.simplyblk.xyz/10.00.zip", available: true),
|
GameBuild(gameVersion: "10.00", link: "https://builds.rebootfn.org/10.00.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "10.10", link: "https://public.simplyblk.xyz/10.10.zip", available: true),
|
GameBuild(gameVersion: "10.10", link: "https://builds.rebootfn.org/10.10.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "10.20", link: "https://public.simplyblk.xyz/10.20.zip", available: true),
|
GameBuild(gameVersion: "10.20", link: "https://builds.rebootfn.org/10.20.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "10.31", link: "https://public.simplyblk.xyz/10.31.zip", available: true),
|
GameBuild(gameVersion: "10.31", link: "https://builds.rebootfn.org/10.31.zip", available: true),
|
||||||
FortniteBuild(gameVersion: "10.40", link: "https://public.simplyblk.xyz/10.40.rar", available: true),
|
GameBuild(gameVersion: "10.40", link: "https://builds.rebootfn.org/10.40.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "11.00", link: "https://public.simplyblk.xyz/11.00.zip", available: true),
|
GameBuild(gameVersion: "11.00", link: "https://builds.rebootfn.org/11.00.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "11.31", link: "https://public.simplyblk.xyz/11.31.rar", available: true),
|
GameBuild(gameVersion: "11.31", link: "https://builds.rebootfn.org/11.31.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "12.00", link: "https://public.simplyblk.xyz/12.00.rar", available: true),
|
GameBuild(gameVersion: "12.00", link: "https://builds.rebootfn.org/12.00.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "12.21", link: "https://public.simplyblk.xyz/12.21.zip", available: true),
|
GameBuild(gameVersion: "12.21", link: "https://builds.rebootfn.org/12.21.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "12.50", link: "https://public.simplyblk.xyz/12.50.zip", available: true),
|
GameBuild(gameVersion: "Fortnite 12.41", link: "https://builds.rebootfn.org/Fortnite%2012.41.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "12.61", link: "https://public.simplyblk.xyz/12.61.zip", available: true),
|
GameBuild(gameVersion: "12.50", link: "https://builds.rebootfn.org/12.50.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "13.00", link: "https://public.simplyblk.xyz/13.00.rar", available: true),
|
GameBuild(gameVersion: "12.61", link: "https://builds.rebootfn.org/12.61.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "13.40", link: "https://public.simplyblk.xyz/13.40.zip", available: true),
|
GameBuild(gameVersion: "13.00", link: "https://builds.rebootfn.org/13.00.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "14.00", link: "https://public.simplyblk.xyz/14.00.rar", available: true),
|
GameBuild(gameVersion: "13.40", link: "https://builds.rebootfn.org/13.40.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "14.40", link: "https://public.simplyblk.xyz/14.40.rar", available: true),
|
GameBuild(gameVersion: "14.00", link: "https://builds.rebootfn.org/14.00.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "14.60", link: "https://public.simplyblk.xyz/14.60.rar", available: true),
|
GameBuild(gameVersion: "14.40", link: "https://builds.rebootfn.org/14.40.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "15.30", link: "https://public.simplyblk.xyz/15.30.rar", available: true),
|
GameBuild(gameVersion: "14.60", link: "https://builds.rebootfn.org/14.60.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "16.40", link: "https://public.simplyblk.xyz/16.40.rar", available: true),
|
GameBuild(gameVersion: "15.30", link: "https://builds.rebootfn.org/15.30.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "17.30", link: "https://public.simplyblk.xyz/17.30.zip", available: true),
|
GameBuild(gameVersion: "16.40", link: "https://builds.rebootfn.org/16.40.rar", available: false),
|
||||||
FortniteBuild(gameVersion: "17.50", link: "https://public.simplyblk.xyz/17.50.zip", available: true),
|
GameBuild(gameVersion: "17.30", link: "https://builds.rebootfn.org/17.30.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "18.40", link: "https://public.simplyblk.xyz/18.40.zip", available: true),
|
GameBuild(gameVersion: "17.50", link: "https://builds.rebootfn.org/17.50.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "19.10", link: "https://public.simplyblk.xyz/19.10.rar", available: true),
|
GameBuild(gameVersion: "18.40", link: "https://builds.rebootfn.org/18.40.zip", available: false),
|
||||||
FortniteBuild(gameVersion: "20.40", link: "https://public.simplyblk.xyz/20.40.zip", available: true),
|
GameBuild(gameVersion: "19.10", link: "https://builds.rebootfn.org/19.10.rar", available: false),
|
||||||
|
GameBuild(gameVersion: "20.40", link: "https://builds.rebootfn.org/20.40.zip", available: false)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
Future<void> downloadArchiveBuild(FortniteBuildDownloadOptions options) async {
|
Future<void> downloadArchiveBuild(GameBuildDownloadOptions options) async {
|
||||||
final fileName = options.build.link.substring(options.build.link.lastIndexOf("/") + 1);
|
final fileName = options.build.link.substring(options.build.link.lastIndexOf("/") + 1);
|
||||||
final outputFile = File("${options.destination.path}\\.build\\$fileName");
|
final outputFile = File("${options.destination.path}\\.build\\$fileName");
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
@@ -259,7 +255,7 @@ Future<bool> _isAriaRunning() async {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _startAriaDownload(FortniteBuildDownloadOptions options, File outputFile) async {
|
Future<String> _startAriaDownload(GameBuildDownloadOptions options, File outputFile) async {
|
||||||
http.Response? addDownloadResponse;
|
http.Response? addDownloadResponse;
|
||||||
try {
|
try {
|
||||||
final addDownloadRequestId = Uuid().toString().replaceAll("-", "");
|
final addDownloadRequestId = Uuid().toString().replaceAll("-", "");
|
||||||
@@ -311,7 +307,7 @@ Future<void> stopDownloadServer() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _extractArchive(Completer<dynamic> stopped, String extension, File tempFile, FortniteBuildDownloadOptions options) async {
|
Future<void> _extractArchive(Completer<dynamic> stopped, String extension, File tempFile, GameBuildDownloadOptions options) async {
|
||||||
Process? process;
|
Process? process;
|
||||||
switch (extension.toLowerCase()) {
|
switch (extension.toLowerCase()) {
|
||||||
case ".zip":
|
case ".zip":
|
||||||
@@ -437,7 +433,7 @@ Future<void> _extractArchive(Completer<dynamic> stopped, String extension, File
|
|||||||
|
|
||||||
void _onProgress(SendPort port, double percentage, int speed, int minutesLeft, bool extracting) {
|
void _onProgress(SendPort port, double percentage, int speed, int minutesLeft, bool extracting) {
|
||||||
if(percentage == 0) {
|
if(percentage == 0) {
|
||||||
port.send(FortniteBuildDownloadProgress(
|
port.send(GameBuildDownloadProgress(
|
||||||
progress: percentage,
|
progress: percentage,
|
||||||
extracting: extracting,
|
extracting: extracting,
|
||||||
timeLeft: null,
|
timeLeft: null,
|
||||||
@@ -446,7 +442,7 @@ void _onProgress(SendPort port, double percentage, int speed, int minutesLeft, b
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
port.send(FortniteBuildDownloadProgress(
|
port.send(GameBuildDownloadProgress(
|
||||||
progress: percentage,
|
progress: percentage,
|
||||||
extracting: extracting,
|
extracting: extracting,
|
||||||
timeLeft: minutesLeft,
|
timeLeft: minutesLeft,
|
||||||
@@ -454,13 +450,13 @@ void _onProgress(SendPort port, double percentage, int speed, int minutesLeft, b
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onError(Object? error, FortniteBuildDownloadOptions options) {
|
void _onError(Object? error, GameBuildDownloadOptions options) {
|
||||||
if(error != null) {
|
if(error != null) {
|
||||||
options.port.send(error.toString());
|
options.port.send(error.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Completer<dynamic> _setupLifecycle(FortniteBuildDownloadOptions options) {
|
Completer<dynamic> _setupLifecycle(GameBuildDownloadOptions options) {
|
||||||
var stopped = Completer();
|
var stopped = Completer();
|
||||||
var lifecyclePort = ReceivePort();
|
var lifecyclePort = ReceivePort();
|
||||||
lifecyclePort.listen((message) {
|
lifecyclePort.listen((message) {
|
||||||
@@ -473,8 +469,6 @@ Completer<dynamic> _setupLifecycle(FortniteBuildDownloadOptions options) {
|
|||||||
return stopped;
|
return stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<bool> hasRebootDllUpdate(int? lastUpdateMs, {int hours = 24, bool force = false}) async {
|
Future<bool> hasRebootDllUpdate(int? lastUpdateMs, {int hours = 24, bool force = false}) async {
|
||||||
final lastUpdate = await _getLastUpdate(lastUpdateMs);
|
final lastUpdate = await _getLastUpdate(lastUpdateMs);
|
||||||
final exists = await rebootBeforeS20DllFile.exists() && await rebootAboveS20DllFile.exists();
|
final exists = await rebootBeforeS20DllFile.exists() && await rebootAboveS20DllFile.exists();
|
||||||
@@ -482,16 +476,16 @@ Future<bool> hasRebootDllUpdate(int? lastUpdateMs, {int hours = 24, bool force =
|
|||||||
return force || !exists || (hours > 0 && lastUpdate != null && now.difference(lastUpdate).inHours > hours);
|
return force || !exists || (hours > 0 && lastUpdate != null && now.difference(lastUpdate).inHours > hours);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> downloadDependency(InjectableDll dll, String outputPath) async {
|
Future<bool> downloadDependency(GameDll dll, String outputPath) async {
|
||||||
String? name;
|
String? name;
|
||||||
switch(dll) {
|
switch(dll) {
|
||||||
case InjectableDll.console:
|
case GameDll.console:
|
||||||
name = "console.dll";
|
name = "console.dll";
|
||||||
case InjectableDll.auth:
|
case GameDll.auth:
|
||||||
name = "cobalt.dll";
|
name = "sinum.dll";
|
||||||
case InjectableDll.memoryLeak:
|
case GameDll.memoryLeak:
|
||||||
name = "memory.dll";
|
name = "memory.dll";
|
||||||
case InjectableDll.gameServer:
|
case GameDll.gameServer:
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
if(name == null) {
|
if(name == null) {
|
||||||
@@ -9,7 +9,7 @@ class GameInstance {
|
|||||||
final int gamePid;
|
final int gamePid;
|
||||||
final int? launcherPid;
|
final int? launcherPid;
|
||||||
final int? eacPid;
|
final int? eacPid;
|
||||||
final List<InjectableDll> injectedDlls;
|
final List<GameDll> injectedDlls;
|
||||||
final bool headless;
|
final bool headless;
|
||||||
bool launched;
|
bool launched;
|
||||||
bool tokenError;
|
bool tokenError;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user