feat: RSILauncherEnhance

This commit is contained in:
xkeyC 2024-05-01 13:48:37 +08:00
parent 5d0c3f5fd4
commit f6907f233a
18 changed files with 1230 additions and 12 deletions

View File

@ -20,7 +20,7 @@ final routerProvider = AutoDisposeProvider<GoRouter>.internal(
);
typedef RouterRef = AutoDisposeProviderRef<GoRouter>;
String _$appGlobalModelHash() => r'a604c415d2d855ede8727dd75ef991ab2afcf234';
String _$appGlobalModelHash() => r'11a172d5fb19ad6566f1025354c8f8d91fe85a84';
/// See also [AppGlobalModel].
@ProviderFor(AppGlobalModel)

View File

@ -16,6 +16,9 @@ class URLConf {
static String get gitlabLocalizationUrl =>
"$gitApiHome/SCToolBox/LocalizationData";
static String get gitApiRSILauncherEnhanceUrl =>
"$gitApiHome/SCToolBox/RSILauncherEnhance";
static String get apiRepoPath => "$gitApiHome/SCToolBox/api/raw/branch/main";
static String get gitlabApiPath => "$gitApiHome/api/v1/";

View File

@ -82,7 +82,7 @@ class SystemHelper {
}
/// RSI
static Future<String> getRSILauncherPath() async {
static Future<String> getRSILauncherPath({bool skipEXE = false}) async {
final confBox = await Hive.openBox("app_conf");
final path = confBox.get("custom_launcher_path");
if (path != null && path != "") {
@ -102,6 +102,9 @@ class SystemHelper {
]);
if (r.stdout.toString().contains("RSI Launcher.exe")) {
final start = r.stdout.toString().split("RSI Launcher.exe");
if (skipEXE) {
return start[0];
}
return "${start[0]}RSI Launcher.exe";
}
}
@ -257,8 +260,8 @@ foreach ($adapter in $adapterMemory) {
static Future openDir(path, {bool isFile = false}) async {
dPrint("SystemHelper.openDir path === $path");
await Process.run(
SystemHelper.powershellPath, ["explorer.exe", isFile ? "/select,$path" : "\"/select,\"$path\"\""]);
await Process.run(SystemHelper.powershellPath,
["explorer.exe", isFile ? "/select,$path" : "\"/select,\"$path\"\""]);
}
static String getHostsFilePath() {

View File

@ -0,0 +1,40 @@
// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ 2.0.0-dev.32.
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Future<RsiLauncherAsarData> getRsiLauncherAsarData(
{required String asarPath, dynamic hint}) =>
RustLib.instance.api.getRsiLauncherAsarData(asarPath: asarPath, hint: hint);
class RsiLauncherAsarData {
final String asarPath;
final String mainJsPath;
final Uint8List mainJsContent;
const RsiLauncherAsarData({
required this.asarPath,
required this.mainJsPath,
required this.mainJsContent,
});
Future<void> writeMainJs({required List<int> content, dynamic hint}) =>
RustLib.instance.api.rsiLauncherAsarDataWriteMainJs(
that: this, content: content, hint: hint);
@override
int get hashCode =>
asarPath.hashCode ^ mainJsPath.hashCode ^ mainJsContent.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is RsiLauncherAsarData &&
runtimeType == other.runtimeType &&
asarPath == other.asarPath &&
mainJsPath == other.mainJsPath &&
mainJsContent == other.mainJsContent;
}

View File

@ -6,7 +6,6 @@
import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
// The type `RS_PROCESS_MAP` is not used by any `pub` functions, thus it is ignored.
// The type `RsProcess` is not used by any `pub` functions, thus it is ignored.
Stream<RsProcessStreamData> start(

View File

@ -3,6 +3,7 @@
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
import 'api/asar_api.dart';
import 'api/http_api.dart';
import 'api/rs_process.dart';
import 'api/win32_api.dart';
@ -57,7 +58,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.0.0-dev.32';
@override
int get rustContentHash => 1453545208;
int get rustContentHash => 1832496273;
static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
@ -68,6 +69,14 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
}
abstract class RustLibApi extends BaseApi {
Future<RsiLauncherAsarData> getRsiLauncherAsarData(
{required String asarPath, dynamic hint});
Future<void> rsiLauncherAsarDataWriteMainJs(
{required RsiLauncherAsarData that,
required List<int> content,
dynamic hint});
Future<List<String>> dnsLookupIps({required String host, dynamic hint});
Future<List<String>> dnsLookupTxt({required String host, dynamic hint});
@ -109,6 +118,59 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
required super.portManager,
});
@override
Future<RsiLauncherAsarData> getRsiLauncherAsarData(
{required String asarPath, dynamic hint}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
var arg0 = cst_encode_String(asarPath);
return wire.wire_get_rsi_launcher_asar_data(port_, arg0);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_rsi_launcher_asar_data,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kGetRsiLauncherAsarDataConstMeta,
argValues: [asarPath],
apiImpl: this,
hint: hint,
));
}
TaskConstMeta get kGetRsiLauncherAsarDataConstMeta => const TaskConstMeta(
debugName: "get_rsi_launcher_asar_data",
argNames: ["asarPath"],
);
@override
Future<void> rsiLauncherAsarDataWriteMainJs(
{required RsiLauncherAsarData that,
required List<int> content,
dynamic hint}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
var arg0 = cst_encode_box_autoadd_rsi_launcher_asar_data(that);
var arg1 = cst_encode_list_prim_u_8_loose(content);
return wire.wire_rsi_launcher_asar_data_write_main_js(
port_, arg0, arg1);
},
codec: DcoCodec(
decodeSuccessData: dco_decode_unit,
decodeErrorData: dco_decode_AnyhowException,
),
constMeta: kRsiLauncherAsarDataWriteMainJsConstMeta,
argValues: [that, content],
apiImpl: this,
hint: hint,
));
}
TaskConstMeta get kRsiLauncherAsarDataWriteMainJsConstMeta =>
const TaskConstMeta(
debugName: "rsi_launcher_asar_data_write_main_js",
argNames: ["that", "content"],
);
@override
Future<List<String>> dnsLookupIps({required String host, dynamic hint}) {
return handler.executeNormal(NormalTask(
@ -354,6 +416,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as bool;
}
@protected
RsiLauncherAsarData dco_decode_box_autoadd_rsi_launcher_asar_data(
dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return dco_decode_rsi_launcher_asar_data(raw);
}
@protected
int dco_decode_box_autoadd_u_64(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@ -372,6 +441,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return (raw as List<dynamic>).map(dco_decode_String).toList();
}
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return raw as List<int>;
}
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@ -452,6 +527,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return RsProcessStreamDataType.values[raw as int];
}
@protected
RsiLauncherAsarData dco_decode_rsi_launcher_asar_data(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
final arr = raw as List<dynamic>;
if (arr.length != 3)
throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
return RsiLauncherAsarData(
asarPath: dco_decode_String(arr[0]),
mainJsPath: dco_decode_String(arr[1]),
mainJsContent: dco_decode_list_prim_u_8_strict(arr[2]),
);
}
@protected
RustHttpResponse dco_decode_rust_http_response(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@ -535,6 +623,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0;
}
@protected
RsiLauncherAsarData sse_decode_box_autoadd_rsi_launcher_asar_data(
SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
return (sse_decode_rsi_launcher_asar_data(deserializer));
}
@protected
int sse_decode_box_autoadd_u_64(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@ -559,6 +654,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return ans_;
}
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var len_ = sse_decode_i_32(deserializer);
return deserializer.buffer.getUint8List(len_);
}
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@ -666,6 +768,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return RsProcessStreamDataType.values[inner];
}
@protected
RsiLauncherAsarData sse_decode_rsi_launcher_asar_data(
SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
var var_asarPath = sse_decode_String(deserializer);
var var_mainJsPath = sse_decode_String(deserializer);
var var_mainJsContent = sse_decode_list_prim_u_8_strict(deserializer);
return RsiLauncherAsarData(
asarPath: var_asarPath,
mainJsPath: var_mainJsPath,
mainJsContent: var_mainJsContent);
}
@protected
RustHttpResponse sse_decode_rust_http_response(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@ -808,6 +923,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
serializer.buffer.putUint8(self ? 1 : 0);
}
@protected
void sse_encode_box_autoadd_rsi_launcher_asar_data(
RsiLauncherAsarData self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_rsi_launcher_asar_data(self, serializer);
}
@protected
void sse_encode_box_autoadd_u_64(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@ -829,6 +951,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}
}
@protected
void sse_encode_list_prim_u_8_loose(
List<int> self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_i_32(self.length, serializer);
serializer.buffer
.putUint8List(self is Uint8List ? self : Uint8List.fromList(self));
}
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer) {
@ -926,6 +1057,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_i_32(self.index, serializer);
}
@protected
void sse_encode_rsi_launcher_asar_data(
RsiLauncherAsarData self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_String(self.asarPath, serializer);
sse_encode_String(self.mainJsPath, serializer);
sse_encode_list_prim_u_8_strict(self.mainJsContent, serializer);
}
@protected
void sse_encode_rust_http_response(
RustHttpResponse self, SseSerializer serializer) {

View File

@ -3,6 +3,7 @@
// ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field
import 'api/asar_api.dart';
import 'api/http_api.dart';
import 'api/rs_process.dart';
import 'api/win32_api.dart';
@ -37,6 +38,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool dco_decode_bool(dynamic raw);
@protected
RsiLauncherAsarData dco_decode_box_autoadd_rsi_launcher_asar_data(
dynamic raw);
@protected
int dco_decode_box_autoadd_u_64(dynamic raw);
@ -46,6 +51,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
List<String> dco_decode_list_String(dynamic raw);
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@ -79,6 +87,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
RsProcessStreamDataType dco_decode_rs_process_stream_data_type(dynamic raw);
@protected
RsiLauncherAsarData dco_decode_rsi_launcher_asar_data(dynamic raw);
@protected
RustHttpResponse dco_decode_rust_http_response(dynamic raw);
@ -115,6 +126,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
bool sse_decode_bool(SseDeserializer deserializer);
@protected
RsiLauncherAsarData sse_decode_box_autoadd_rsi_launcher_asar_data(
SseDeserializer deserializer);
@protected
int sse_decode_box_autoadd_u_64(SseDeserializer deserializer);
@ -124,6 +139,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
List<String> sse_decode_list_String(SseDeserializer deserializer);
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@ -162,6 +180,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
RsProcessStreamDataType sse_decode_rs_process_stream_data_type(
SseDeserializer deserializer);
@protected
RsiLauncherAsarData sse_decode_rsi_launcher_asar_data(
SseDeserializer deserializer);
@protected
RustHttpResponse sse_decode_rust_http_response(SseDeserializer deserializer);
@ -212,6 +234,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return cst_encode_list_prim_u_8_strict(utf8.encoder.convert(raw));
}
@protected
ffi.Pointer<wire_cst_rsi_launcher_asar_data>
cst_encode_box_autoadd_rsi_launcher_asar_data(RsiLauncherAsarData raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
final ptr = wire.cst_new_box_autoadd_rsi_launcher_asar_data();
cst_api_fill_to_wire_rsi_launcher_asar_data(raw, ptr.ref);
return ptr;
}
@protected
ffi.Pointer<ffi.Uint64> cst_encode_box_autoadd_u_64(int raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
@ -228,6 +259,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return ans;
}
@protected
ffi.Pointer<wire_cst_list_prim_u_8_loose> cst_encode_list_prim_u_8_loose(
List<int> raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
final ans = wire.cst_new_list_prim_u_8_loose(raw.length);
ans.ref.ptr.asTypedList(raw.length).setAll(0, raw);
return ans;
}
@protected
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_encode_list_prim_u_8_strict(
Uint8List raw) {
@ -281,6 +321,13 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return raw.toInt();
}
@protected
void cst_api_fill_to_wire_box_autoadd_rsi_launcher_asar_data(
RsiLauncherAsarData apiObj,
ffi.Pointer<wire_cst_rsi_launcher_asar_data> wireObj) {
cst_api_fill_to_wire_rsi_launcher_asar_data(apiObj, wireObj.ref);
}
@protected
void cst_api_fill_to_wire_record_string_string(
(String, String) apiObj, wire_cst_record_string_string wireObj) {
@ -296,6 +343,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
wireObj.rs_pid = cst_encode_u_32(apiObj.rsPid);
}
@protected
void cst_api_fill_to_wire_rsi_launcher_asar_data(
RsiLauncherAsarData apiObj, wire_cst_rsi_launcher_asar_data wireObj) {
wireObj.asar_path = cst_encode_String(apiObj.asarPath);
wireObj.main_js_path = cst_encode_String(apiObj.mainJsPath);
wireObj.main_js_content =
cst_encode_list_prim_u_8_strict(apiObj.mainJsContent);
}
@protected
void cst_api_fill_to_wire_rust_http_response(
RustHttpResponse apiObj, wire_cst_rust_http_response wireObj) {
@ -354,6 +410,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_rsi_launcher_asar_data(
RsiLauncherAsarData self, SseSerializer serializer);
@protected
void sse_encode_box_autoadd_u_64(int self, SseSerializer serializer);
@ -363,6 +423,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_list_String(List<String> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
@ -403,6 +466,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
void sse_encode_rs_process_stream_data_type(
RsProcessStreamDataType self, SseSerializer serializer);
@protected
void sse_encode_rsi_launcher_asar_data(
RsiLauncherAsarData self, SseSerializer serializer);
@protected
void sse_encode_rust_http_response(
RustHttpResponse self, SseSerializer serializer);
@ -464,6 +531,49 @@ class RustLibWire implements BaseWire {
late final _store_dart_post_cobject = _store_dart_post_cobjectPtr
.asFunction<void Function(DartPostCObjectFnType)>();
void wire_get_rsi_launcher_asar_data(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> asar_path,
) {
return _wire_get_rsi_launcher_asar_data(
port_,
asar_path,
);
}
late final _wire_get_rsi_launcher_asar_dataPtr = _lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Int64, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
'frbgen_starcitizen_doctor_wire_get_rsi_launcher_asar_data');
late final _wire_get_rsi_launcher_asar_data =
_wire_get_rsi_launcher_asar_dataPtr.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
void wire_rsi_launcher_asar_data_write_main_js(
int port_,
ffi.Pointer<wire_cst_rsi_launcher_asar_data> that,
ffi.Pointer<wire_cst_list_prim_u_8_loose> content,
) {
return _wire_rsi_launcher_asar_data_write_main_js(
port_,
that,
content,
);
}
late final _wire_rsi_launcher_asar_data_write_main_jsPtr = _lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Int64,
ffi.Pointer<wire_cst_rsi_launcher_asar_data>,
ffi.Pointer<wire_cst_list_prim_u_8_loose>)>>(
'frbgen_starcitizen_doctor_wire_rsi_launcher_asar_data_write_main_js');
late final _wire_rsi_launcher_asar_data_write_main_js =
_wire_rsi_launcher_asar_data_write_main_jsPtr.asFunction<
void Function(int, ffi.Pointer<wire_cst_rsi_launcher_asar_data>,
ffi.Pointer<wire_cst_list_prim_u_8_loose>)>();
void wire_dns_lookup_ips(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> host,
@ -660,6 +770,19 @@ class RustLibWire implements BaseWire {
_wire_set_foreground_windowPtr.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
ffi.Pointer<wire_cst_rsi_launcher_asar_data>
cst_new_box_autoadd_rsi_launcher_asar_data() {
return _cst_new_box_autoadd_rsi_launcher_asar_data();
}
late final _cst_new_box_autoadd_rsi_launcher_asar_dataPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<wire_cst_rsi_launcher_asar_data> Function()>>(
'frbgen_starcitizen_doctor_cst_new_box_autoadd_rsi_launcher_asar_data');
late final _cst_new_box_autoadd_rsi_launcher_asar_data =
_cst_new_box_autoadd_rsi_launcher_asar_dataPtr.asFunction<
ffi.Pointer<wire_cst_rsi_launcher_asar_data> Function()>();
ffi.Pointer<ffi.Uint64> cst_new_box_autoadd_u_64(
int value,
) {
@ -689,6 +812,21 @@ class RustLibWire implements BaseWire {
late final _cst_new_list_String = _cst_new_list_StringPtr
.asFunction<ffi.Pointer<wire_cst_list_String> Function(int)>();
ffi.Pointer<wire_cst_list_prim_u_8_loose> cst_new_list_prim_u_8_loose(
int len,
) {
return _cst_new_list_prim_u_8_loose(
len,
);
}
late final _cst_new_list_prim_u_8_loosePtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<wire_cst_list_prim_u_8_loose> Function(ffi.Int32)>>(
'frbgen_starcitizen_doctor_cst_new_list_prim_u_8_loose');
late final _cst_new_list_prim_u_8_loose = _cst_new_list_prim_u_8_loosePtr
.asFunction<ffi.Pointer<wire_cst_list_prim_u_8_loose> Function(int)>();
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_new_list_prim_u_8_strict(
int len,
) {
@ -749,6 +887,21 @@ final class wire_cst_list_prim_u_8_strict extends ffi.Struct {
external int len;
}
final class wire_cst_rsi_launcher_asar_data extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> asar_path;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> main_js_path;
external ffi.Pointer<wire_cst_list_prim_u_8_strict> main_js_content;
}
final class wire_cst_list_prim_u_8_loose extends ffi.Struct {
external ffi.Pointer<ffi.Uint8> ptr;
@ffi.Int32()
external int len;
}
final class wire_cst_record_string_string extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> field0;

View File

@ -6,7 +6,7 @@ part of 'home_ui_model.dart';
// RiverpodGenerator
// **************************************************************************
String _$homeUIModelHash() => r'8308b6e327b7eeda64c39bcd73e9f2d9e6470437';
String _$homeUIModelHash() => r'85d3242abb4264a814768a2d5ce108df46df38d9';
/// See also [HomeUIModel].
@ProviderFor(HomeUIModel)

View File

@ -0,0 +1,383 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:archive/archive_io.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/app.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/helper/system_helper.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/rust/api/asar_api.dart' as asar_api;
import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/generated/no_l10n_strings.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
part 'rsi_launcher_enhance_dialog_ui.freezed.dart';
@freezed
class RSILauncherStateData with _$RSILauncherStateData {
const factory RSILauncherStateData({
required String version,
required asar_api.RsiLauncherAsarData data,
required String serverData,
@Default(false) bool isPatchInstalled,
String? enabledLocalization,
bool? enableDownloaderBoost,
}) = _RSILauncherStateData;
}
class RsiLauncherEnhanceDialogUI extends HookConsumerWidget {
const RsiLauncherEnhanceDialogUI({super.key});
static const supportLocalizationMap = {
"en": NoL10n.langEn,
"zh_CN": NoL10n.langZHS,
};
@override
Widget build(BuildContext context, WidgetRef ref) {
final workingText = useState("");
final assarState = useState<RSILauncherStateData?>(null);
Future<void> readState() async {
workingText.value = "读取启动器信息...";
assarState.value = await _readState(context).unwrap(context: context);
if (assarState.value == null) {
workingText.value = "";
return;
}
workingText.value = "正在从网络获取增强数据...";
if (!context.mounted) return;
await _loadEnhanceData(context, ref, assarState)
.unwrap(context: context)
.unwrap(context: context);
workingText.value = "";
}
void doInstall() async {
workingText.value = "生成补丁 ...";
final newScript =
await _genNewScript(assarState).unwrap(context: context);
workingText.value = "安装补丁,这需要一点时间,取决于您的计算机性能 ...";
if (!context.mounted) return;
await assarState.value?.data
.writeMainJs(content: utf8.encode(newScript))
.unwrap(context: context);
await readState();
}
useEffect(() {
readState();
return null;
}, const []);
return ContentDialog(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .48),
title: Row(children: [
IconButton(
icon: const Icon(
FluentIcons.back,
size: 22,
),
onPressed:
workingText.value.isEmpty ? Navigator.of(context).pop : null),
const SizedBox(width: 12),
const Text("RSI 启动器增强"),
]),
content: AnimatedSize(
duration: const Duration(milliseconds: 130),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (workingText.value.isNotEmpty) ...[
Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Row(),
const SizedBox(height: 12),
const ProgressRing(),
const SizedBox(height: 12),
Text(workingText.value),
const SizedBox(height: 12),
],
),
),
] else ...[
Row(
children: [
Expanded(
child: Text(
"启动器内部版本信息:${assarState.value?.version}",
style: TextStyle(
color: Colors.white.withOpacity(.6),
),
),
),
Text(
"补丁状态:${(assarState.value?.isPatchInstalled ?? false) ? "已安装" : "未安装"}",
style: TextStyle(
color: Colors.white.withOpacity(.6),
),
)
],
),
if (assarState.value?.serverData.isEmpty ?? true) ...[
const Text("获取增强数据失败,可能是网络问题或当前版本不支持"),
] else ...[
const SizedBox(height: 24),
if (assarState.value?.enabledLocalization != null)
Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("RSI 启动器本地化"),
const SizedBox(height: 3),
Text(
"为 RSI 启动器增加多语言支持。",
style: TextStyle(
fontSize: 13,
color: Colors.white.withOpacity(.6),
),
),
],
)),
ComboBox(
items: [
for (final key in supportLocalizationMap.keys)
ComboBoxItem(
value: key,
child: Text(supportLocalizationMap[key]!))
],
value: assarState.value?.enabledLocalization,
onChanged: (v) {
assarState.value = assarState.value!
.copyWith(enabledLocalization: v);
},
),
],
)),
const SizedBox(height: 3),
if (assarState.value?.enableDownloaderBoost != null)
Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: FluentTheme.of(context).cardColor,
borderRadius: BorderRadius.circular(12),
),
child: Row(children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("RSI 启动器下载增强"),
const SizedBox(height: 3),
Text(
"下载游戏时可使用更多线程以提升下载速度,启用后请在启动器设置修改线程数。",
style: TextStyle(
fontSize: 13,
color: Colors.white.withOpacity(.6),
),
),
],
)),
ToggleSwitch(
onChanged: (value) {
assarState.value = assarState.value
?.copyWith(enableDownloaderBoost: value);
},
checked:
assarState.value?.enableDownloaderBoost ?? false,
)
])),
const SizedBox(height: 12),
Center(
child: FilledButton(
onPressed: doInstall,
child: const Padding(
padding:
EdgeInsets.symmetric(vertical: 4, horizontal: 6),
child: Text("安装增强补丁"),
))),
],
const SizedBox(height: 16),
Text(
"* 如需卸载增强补丁,请覆盖安装 RSI 启动器。",
style: TextStyle(
color: Colors.white.withOpacity(.6), fontSize: 13),
),
],
],
),
),
);
}
Future<RSILauncherStateData?> _readState(BuildContext context) async {
final lPath = await SystemHelper.getRSILauncherPath(skipEXE: true);
if (lPath.isEmpty) {
if (!context.mounted) return null;
showToast(context, "未找到 RSI 启动器");
return null;
}
dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherPath ==== $lPath");
final dataPath = "${lPath}resources\\app.asar";
dPrint("[RsiLauncherEnhanceDialogUI] rsiLauncherDataPath ==== $dataPath");
try {
final data = await asar_api.getRsiLauncherAsarData(asarPath: dataPath);
dPrint(
"[RsiLauncherEnhanceDialogUI] rsiLauncherPath main.js path == ${data.mainJsPath}");
final version =
RegExp(r"main\.(\w+)\.js").firstMatch(data.mainJsPath)?.group(1);
if (version == null) {
if (!context.mounted) return null;
showToast(context, "读取启动器信息失败!");
return null;
}
dPrint(
"[RsiLauncherEnhanceDialogUI] rsiLauncherPath main.js version == $version");
final mainJsString = String.fromCharCodes(data.mainJsContent);
final (enabledLocalization, enableDownloaderBoost) =
_readScriptState(mainJsString);
return RSILauncherStateData(
version: version,
data: data,
serverData: "",
isPatchInstalled: mainJsString.contains("SC_TOOLBOX"),
enabledLocalization: enabledLocalization,
enableDownloaderBoost: enableDownloaderBoost,
);
} catch (e) {
if (!context.mounted) return null;
showToast(context, "读取启动器信息失败:$e");
return null;
}
}
Future<String> _loadEnhanceData(BuildContext context, WidgetRef ref,
ValueNotifier<RSILauncherStateData?> assarState) async {
final globalModel = ref.read(appGlobalModelProvider);
final enhancePath =
"${globalModel.applicationSupportDir}/launcher_enhance_data";
final enhanceFile =
File("$enhancePath/${assarState.value?.version}.tar.gz");
if (!await enhanceFile.exists()) {
final downloadUrl =
"${URLConf.gitApiRSILauncherEnhanceUrl}/archive/${assarState.value?.version}.tar.gz";
final r = await RSHttp.get(downloadUrl).unwrap();
if (r.statusCode != 200 || r.data == null) {
return "";
}
await enhanceFile.create(recursive: true);
await enhanceFile.writeAsBytes(r.data!, flush: true);
}
final severMainJS =
await compute(_readArchive, (enhanceFile.path, "main.js"));
final serverMainJSString = severMainJS.toString();
final scriptState = _readScriptState(serverMainJSString);
if (assarState.value?.enabledLocalization == null) {
assarState.value =
assarState.value?.copyWith(enabledLocalization: scriptState.$1);
dPrint(
"[RsiLauncherEnhanceDialogUI] _loadEnhanceData enabledLocalization == ${scriptState.$1}");
}
if (assarState.value?.enableDownloaderBoost == null) {
assarState.value =
assarState.value?.copyWith(enableDownloaderBoost: scriptState.$2);
dPrint(
"[RsiLauncherEnhanceDialogUI] _loadEnhanceData enableDownloaderBoost == ${scriptState.$2}");
}
assarState.value =
assarState.value?.copyWith(serverData: serverMainJSString);
return serverMainJSString;
}
static StringBuffer _readArchive((String savePath, String fileName) data) {
final inputStream = InputFileStream(data.$1);
final archive =
TarDecoder().decodeBytes(GZipDecoder().decodeBuffer(inputStream));
StringBuffer dataBuffer = StringBuffer("");
for (var element in archive.files) {
if (element.name.endsWith(data.$2)) {
for (var value
in (element.rawContent?.readString() ?? "").split("\n")) {
final tv = value;
if (tv.isNotEmpty) dataBuffer.writeln(tv);
}
}
}
archive.clear();
return dataBuffer;
}
// ignore: constant_identifier_names
static const SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START =
"const SC_TOOLBOX_ENABLED_LOCALIZATION = ";
// ignore: constant_identifier_names
static const SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START =
"const SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST = ";
(String?, bool?) _readScriptState(String mainJsString) {
String? enabledLocalization;
bool? enableDownloaderBoost;
for (final line in mainJsString.split("\n")) {
final lineTrim = line.trim();
if (lineTrim.startsWith(SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START)) {
enabledLocalization = lineTrim
.substring(SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START.length)
.replaceAll("\"", "")
.replaceAll(";", "");
} else if (lineTrim
.startsWith(SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START)) {
enableDownloaderBoost = lineTrim
.substring(
SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START.length)
.toLowerCase() ==
"true;";
}
}
return (enabledLocalization, enableDownloaderBoost);
}
Future<String> _genNewScript(
ValueNotifier<RSILauncherStateData?> assarState) async {
final serverScriptLines = assarState.value!.serverData.split("\n");
final StringBuffer scriptBuffer = StringBuffer("");
for (final line in serverScriptLines) {
final lineTrim = line.trim();
if (lineTrim.startsWith(SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START)) {
scriptBuffer.writeln(
"$SC_TOOLBOX_ENABLED_LOCALIZATION_SCRIPT_START\"${assarState.value!.enabledLocalization}\";");
} else if (lineTrim
.startsWith(SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START)) {
scriptBuffer.writeln(
"$SC_TOOLBOX_ENABLE_DOWNLOADER_BOOST_SCRIPT_START${assarState.value!.enableDownloaderBoost};");
} else {
scriptBuffer.writeln(line);
}
}
return scriptBuffer.toString();
}
}

View File

@ -0,0 +1,245 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'rsi_launcher_enhance_dialog_ui.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
/// @nodoc
mixin _$RSILauncherStateData {
String get version => throw _privateConstructorUsedError;
asar_api.RsiLauncherAsarData get data => throw _privateConstructorUsedError;
String get serverData => throw _privateConstructorUsedError;
bool get isPatchInstalled => throw _privateConstructorUsedError;
String? get enabledLocalization => throw _privateConstructorUsedError;
bool? get enableDownloaderBoost => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$RSILauncherStateDataCopyWith<RSILauncherStateData> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $RSILauncherStateDataCopyWith<$Res> {
factory $RSILauncherStateDataCopyWith(RSILauncherStateData value,
$Res Function(RSILauncherStateData) then) =
_$RSILauncherStateDataCopyWithImpl<$Res, RSILauncherStateData>;
@useResult
$Res call(
{String version,
asar_api.RsiLauncherAsarData data,
String serverData,
bool isPatchInstalled,
String? enabledLocalization,
bool? enableDownloaderBoost});
}
/// @nodoc
class _$RSILauncherStateDataCopyWithImpl<$Res,
$Val extends RSILauncherStateData>
implements $RSILauncherStateDataCopyWith<$Res> {
_$RSILauncherStateDataCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? version = null,
Object? data = null,
Object? serverData = null,
Object? isPatchInstalled = null,
Object? enabledLocalization = freezed,
Object? enableDownloaderBoost = freezed,
}) {
return _then(_value.copyWith(
version: null == version
? _value.version
: version // ignore: cast_nullable_to_non_nullable
as String,
data: null == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as asar_api.RsiLauncherAsarData,
serverData: null == serverData
? _value.serverData
: serverData // ignore: cast_nullable_to_non_nullable
as String,
isPatchInstalled: null == isPatchInstalled
? _value.isPatchInstalled
: isPatchInstalled // ignore: cast_nullable_to_non_nullable
as bool,
enabledLocalization: freezed == enabledLocalization
? _value.enabledLocalization
: enabledLocalization // ignore: cast_nullable_to_non_nullable
as String?,
enableDownloaderBoost: freezed == enableDownloaderBoost
? _value.enableDownloaderBoost
: enableDownloaderBoost // ignore: cast_nullable_to_non_nullable
as bool?,
) as $Val);
}
}
/// @nodoc
abstract class _$$RSILauncherStateDataImplCopyWith<$Res>
implements $RSILauncherStateDataCopyWith<$Res> {
factory _$$RSILauncherStateDataImplCopyWith(_$RSILauncherStateDataImpl value,
$Res Function(_$RSILauncherStateDataImpl) then) =
__$$RSILauncherStateDataImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String version,
asar_api.RsiLauncherAsarData data,
String serverData,
bool isPatchInstalled,
String? enabledLocalization,
bool? enableDownloaderBoost});
}
/// @nodoc
class __$$RSILauncherStateDataImplCopyWithImpl<$Res>
extends _$RSILauncherStateDataCopyWithImpl<$Res, _$RSILauncherStateDataImpl>
implements _$$RSILauncherStateDataImplCopyWith<$Res> {
__$$RSILauncherStateDataImplCopyWithImpl(_$RSILauncherStateDataImpl _value,
$Res Function(_$RSILauncherStateDataImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? version = null,
Object? data = null,
Object? serverData = null,
Object? isPatchInstalled = null,
Object? enabledLocalization = freezed,
Object? enableDownloaderBoost = freezed,
}) {
return _then(_$RSILauncherStateDataImpl(
version: null == version
? _value.version
: version // ignore: cast_nullable_to_non_nullable
as String,
data: null == data
? _value.data
: data // ignore: cast_nullable_to_non_nullable
as asar_api.RsiLauncherAsarData,
serverData: null == serverData
? _value.serverData
: serverData // ignore: cast_nullable_to_non_nullable
as String,
isPatchInstalled: null == isPatchInstalled
? _value.isPatchInstalled
: isPatchInstalled // ignore: cast_nullable_to_non_nullable
as bool,
enabledLocalization: freezed == enabledLocalization
? _value.enabledLocalization
: enabledLocalization // ignore: cast_nullable_to_non_nullable
as String?,
enableDownloaderBoost: freezed == enableDownloaderBoost
? _value.enableDownloaderBoost
: enableDownloaderBoost // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
/// @nodoc
class _$RSILauncherStateDataImpl implements _RSILauncherStateData {
const _$RSILauncherStateDataImpl(
{required this.version,
required this.data,
required this.serverData,
this.isPatchInstalled = false,
this.enabledLocalization,
this.enableDownloaderBoost});
@override
final String version;
@override
final asar_api.RsiLauncherAsarData data;
@override
final String serverData;
@override
@JsonKey()
final bool isPatchInstalled;
@override
final String? enabledLocalization;
@override
final bool? enableDownloaderBoost;
@override
String toString() {
return 'RSILauncherStateData(version: $version, data: $data, serverData: $serverData, isPatchInstalled: $isPatchInstalled, enabledLocalization: $enabledLocalization, enableDownloaderBoost: $enableDownloaderBoost)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$RSILauncherStateDataImpl &&
(identical(other.version, version) || other.version == version) &&
(identical(other.data, data) || other.data == data) &&
(identical(other.serverData, serverData) ||
other.serverData == serverData) &&
(identical(other.isPatchInstalled, isPatchInstalled) ||
other.isPatchInstalled == isPatchInstalled) &&
(identical(other.enabledLocalization, enabledLocalization) ||
other.enabledLocalization == enabledLocalization) &&
(identical(other.enableDownloaderBoost, enableDownloaderBoost) ||
other.enableDownloaderBoost == enableDownloaderBoost));
}
@override
int get hashCode => Object.hash(runtimeType, version, data, serverData,
isPatchInstalled, enabledLocalization, enableDownloaderBoost);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$RSILauncherStateDataImplCopyWith<_$RSILauncherStateDataImpl>
get copyWith =>
__$$RSILauncherStateDataImplCopyWithImpl<_$RSILauncherStateDataImpl>(
this, _$identity);
}
abstract class _RSILauncherStateData implements RSILauncherStateData {
const factory _RSILauncherStateData(
{required final String version,
required final asar_api.RsiLauncherAsarData data,
required final String serverData,
final bool isPatchInstalled,
final String? enabledLocalization,
final bool? enableDownloaderBoost}) = _$RSILauncherStateDataImpl;
@override
String get version;
@override
asar_api.RsiLauncherAsarData get data;
@override
String get serverData;
@override
bool get isPatchInstalled;
@override
String? get enabledLocalization;
@override
bool? get enableDownloaderBoost;
@override
@JsonKey(ignore: true)
_$$RSILauncherStateDataImplCopyWith<_$RSILauncherStateDataImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -23,6 +23,7 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:xml/xml.dart';
import 'dialogs/hosts_booster_dialog_ui.dart';
import 'dialogs/rsi_launcher_enhance_dialog_ui.dart';
part 'tools_ui_model.g.dart';
@ -90,6 +91,13 @@ class ToolsUIModel extends _$ToolsUIModel {
const Icon(FluentIcons.virtual_network, size: 24),
onTap: () => _doHostsBooster(context),
),
ToolsItemData(
"rsilauncher_enhance_mod",
"RSI 启动器增强",
"启动器汉化,下载线程增强",
const Icon(FluentIcons.c_plus_plus, size: 24),
onTap: () => _rsiEnhance(context),
),
ToolsItemData(
"reinstall_eac",
S.current.tools_action_reinstall_easyanticheat,
@ -584,4 +592,10 @@ class ToolsUIModel extends _$ToolsUIModel {
_unp4kc(BuildContext context) async {
context.push("/tools/unp4kc");
}
_rsiEnhance(BuildContext context) async {
showDialog(
context: context,
builder: (BuildContext context) => const RsiLauncherEnhanceDialogUI());
}
}

View File

@ -6,7 +6,7 @@ part of 'tools_ui_model.dart';
// RiverpodGenerator
// **************************************************************************
String _$toolsUIModelHash() => r'5753016dc2cbcf3fafd2fa561d5b91a3295ca04b';
String _$toolsUIModelHash() => r'6cf170210fa7a7c2c63bde9d0920c64a20a81263';
/// See also [ToolsUIModel].
@ProviderFor(ToolsUIModel)

View File

@ -45,8 +45,6 @@ dependencies:
flutter_rust_bridge: ^2.0.0-dev.32
freezed_annotation: ^2.4.1
meta: ^1.9.1
cryptography: ^2.7.0
cryptography_flutter: ^2.3.2
hexcolor: ^3.0.1
dart_rss: ^3.0.1
html: ^0.15.4

View File

@ -22,4 +22,5 @@ anyhow = "1.0"
win32job = "2"
scopeguard = "1.2"
notify-rust = "4"
windows = { version = "0.56.0", features = ["Win32_UI_WindowsAndMessaging"] }
windows = { version = "0.56.0", features = ["Win32_UI_WindowsAndMessaging"] }
asar = "0.3.0"

52
rust/src/api/asar_api.rs Normal file
View File

@ -0,0 +1,52 @@
use std::fs::File;
use asar::{AsarReader, AsarWriter};
use tokio::fs;
pub struct RsiLauncherAsarData {
pub asar_path: String,
pub main_js_path: String,
pub main_js_content: Vec<u8>,
}
impl RsiLauncherAsarData {
pub async fn write_main_js(&self, content: Vec<u8>) -> anyhow::Result<()> {
let mut asar_writer = AsarWriter::new();
let asar_mem_file = fs::read(self.asar_path.clone()).await?;
let asar = AsarReader::new(&asar_mem_file, None)?;
asar.files().iter().for_each(|v| {
let (path, file) = v;
let path_string = path.clone().into_os_string().into_string().unwrap();
if path_string == self.main_js_path {
asar_writer.write_file(path, &content, true).unwrap();
} else {
asar_writer.write_file(path, file.data(), true).unwrap();
}
});
// rm old asar
fs::remove_file(&self.asar_path).await?;
// write new asar
asar_writer.finalize(File::create(&self.asar_path)?)?;
Ok(())
}
}
pub async fn get_rsi_launcher_asar_data(asar_path: &str) -> anyhow::Result<RsiLauncherAsarData> {
let asar_mem_file = fs::read(asar_path).await?;
let asar = AsarReader::new(&asar_mem_file, None)?;
let mut main_js_path = String::from("");
let mut main_js_content: Vec<u8> = Vec::new();
asar.files().iter().for_each(|v| {
let (path, file) = v;
let path_string = path.clone().into_os_string().into_string().unwrap();
if path_string.starts_with("app\\static\\js\\main.") && path_string.ends_with(".js") {
main_js_path = path_string;
main_js_content = file.data().to_vec();
}
});
Ok(RsiLauncherAsarData {
asar_path: asar_path.to_string(),
main_js_path,
main_js_content,
})
}

View File

@ -4,3 +4,4 @@
pub mod http_api;
pub mod rs_process;
pub mod win32_api;
pub mod asar_api;

View File

@ -57,6 +57,13 @@ impl CstDecode<String> for *mut wire_cst_list_prim_u_8_strict {
String::from_utf8(vec).unwrap()
}
}
impl CstDecode<crate::api::asar_api::RsiLauncherAsarData> for *mut wire_cst_rsi_launcher_asar_data {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> crate::api::asar_api::RsiLauncherAsarData {
let wrap = unsafe { flutter_rust_bridge::for_generated::box_from_leak_ptr(self) };
CstDecode::<crate::api::asar_api::RsiLauncherAsarData>::cst_decode(*wrap).into()
}
}
impl CstDecode<u64> for *mut u64 {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> u64 {
@ -73,6 +80,15 @@ impl CstDecode<Vec<String>> for *mut wire_cst_list_String {
vec.into_iter().map(CstDecode::cst_decode).collect()
}
}
impl CstDecode<Vec<u8>> for *mut wire_cst_list_prim_u_8_loose {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> Vec<u8> {
unsafe {
let wrap = flutter_rust_bridge::for_generated::box_from_leak_ptr(self);
flutter_rust_bridge::for_generated::vec_from_leak_ptr(wrap.ptr, wrap.len)
}
}
}
impl CstDecode<Vec<u8>> for *mut wire_cst_list_prim_u_8_strict {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> Vec<u8> {
@ -108,6 +124,16 @@ impl CstDecode<crate::api::rs_process::RsProcessStreamData> for wire_cst_rs_proc
}
}
}
impl CstDecode<crate::api::asar_api::RsiLauncherAsarData> for wire_cst_rsi_launcher_asar_data {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> crate::api::asar_api::RsiLauncherAsarData {
crate::api::asar_api::RsiLauncherAsarData {
asar_path: self.asar_path.cst_decode(),
main_js_path: self.main_js_path.cst_decode(),
main_js_content: self.main_js_content.cst_decode(),
}
}
}
impl CstDecode<crate::http_package::RustHttpResponse> for wire_cst_rust_http_response {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> crate::http_package::RustHttpResponse {
@ -149,6 +175,20 @@ impl Default for wire_cst_rs_process_stream_data {
Self::new_with_null_ptr()
}
}
impl NewWithNullPtr for wire_cst_rsi_launcher_asar_data {
fn new_with_null_ptr() -> Self {
Self {
asar_path: core::ptr::null_mut(),
main_js_path: core::ptr::null_mut(),
main_js_content: core::ptr::null_mut(),
}
}
}
impl Default for wire_cst_rsi_launcher_asar_data {
fn default() -> Self {
Self::new_with_null_ptr()
}
}
impl NewWithNullPtr for wire_cst_rust_http_response {
fn new_with_null_ptr() -> Self {
Self {
@ -168,6 +208,23 @@ impl Default for wire_cst_rust_http_response {
}
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_wire_get_rsi_launcher_asar_data(
port_: i64,
asar_path: *mut wire_cst_list_prim_u_8_strict,
) {
wire_get_rsi_launcher_asar_data_impl(port_, asar_path)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_wire_rsi_launcher_asar_data_write_main_js(
port_: i64,
that: *mut wire_cst_rsi_launcher_asar_data,
content: *mut wire_cst_list_prim_u_8_loose,
) {
wire_rsi_launcher_asar_data_write_main_js_impl(port_, that, content)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_wire_dns_lookup_ips(
port_: i64,
@ -243,6 +300,14 @@ pub extern "C" fn frbgen_starcitizen_doctor_wire_set_foreground_window(
wire_set_foreground_window_impl(port_, window_name)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_cst_new_box_autoadd_rsi_launcher_asar_data(
) -> *mut wire_cst_rsi_launcher_asar_data {
flutter_rust_bridge::for_generated::new_leak_box_ptr(
wire_cst_rsi_launcher_asar_data::new_with_null_ptr(),
)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_cst_new_box_autoadd_u_64(value: u64) -> *mut u64 {
flutter_rust_bridge::for_generated::new_leak_box_ptr(value)
@ -262,6 +327,17 @@ pub extern "C" fn frbgen_starcitizen_doctor_cst_new_list_String(
flutter_rust_bridge::for_generated::new_leak_box_ptr(wrap)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_cst_new_list_prim_u_8_loose(
len: i32,
) -> *mut wire_cst_list_prim_u_8_loose {
let ans = wire_cst_list_prim_u_8_loose {
ptr: flutter_rust_bridge::for_generated::new_leak_vec_ptr(Default::default(), len),
len,
};
flutter_rust_bridge::for_generated::new_leak_box_ptr(ans)
}
#[no_mangle]
pub extern "C" fn frbgen_starcitizen_doctor_cst_new_list_prim_u_8_strict(
len: i32,
@ -295,6 +371,12 @@ pub struct wire_cst_list_String {
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_list_prim_u_8_loose {
ptr: *mut u8,
len: i32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_list_prim_u_8_strict {
ptr: *mut u8,
len: i32,
@ -320,6 +402,13 @@ pub struct wire_cst_rs_process_stream_data {
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_rsi_launcher_asar_data {
asar_path: *mut wire_cst_list_prim_u_8_strict,
main_js_path: *mut wire_cst_list_prim_u_8_strict,
main_js_content: *mut wire_cst_list_prim_u_8_strict,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_rust_http_response {
status_code: u16,
headers: *mut wire_cst_list_record_string_string,

View File

@ -31,7 +31,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
default_rust_auto_opaque = RustAutoOpaqueNom,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.0.0-dev.32";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1453545208;
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1832496273;
// Section: executor
@ -39,6 +39,58 @@ flutter_rust_bridge::frb_generated_default_handler!();
// Section: wire_funcs
fn wire_get_rsi_launcher_asar_data_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
asar_path: impl CstDecode<String>,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "get_rsi_launcher_asar_data",
port: Some(port_),
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
},
move || {
let api_asar_path = asar_path.cst_decode();
move |context| async move {
transform_result_dco(
(move || async move {
crate::api::asar_api::get_rsi_launcher_asar_data(&api_asar_path).await
})()
.await,
)
}
},
)
}
fn wire_rsi_launcher_asar_data_write_main_js_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
that: impl CstDecode<crate::api::asar_api::RsiLauncherAsarData>,
content: impl CstDecode<Vec<u8>>,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "rsi_launcher_asar_data_write_main_js",
port: Some(port_),
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
},
move || {
let api_that = that.cst_decode();
let api_content = content.cst_decode();
move |context| async move {
transform_result_dco(
(move || async move {
crate::api::asar_api::RsiLauncherAsarData::write_main_js(
&api_that,
api_content,
)
.await
})()
.await,
)
}
},
)
}
fn wire_dns_lookup_ips_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
host: impl CstDecode<String>,
@ -544,6 +596,20 @@ impl SseDecode for crate::api::rs_process::RsProcessStreamDataType {
}
}
impl SseDecode for crate::api::asar_api::RsiLauncherAsarData {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut var_asarPath = <String>::sse_decode(deserializer);
let mut var_mainJsPath = <String>::sse_decode(deserializer);
let mut var_mainJsContent = <Vec<u8>>::sse_decode(deserializer);
return crate::api::asar_api::RsiLauncherAsarData {
asar_path: var_asarPath,
main_js_path: var_mainJsPath,
main_js_content: var_mainJsContent,
};
}
}
impl SseDecode for crate::http_package::RustHttpResponse {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@ -721,6 +787,28 @@ impl flutter_rust_bridge::IntoIntoDart<crate::api::rs_process::RsProcessStreamDa
}
}
// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::api::asar_api::RsiLauncherAsarData {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
[
self.asar_path.into_into_dart().into_dart(),
self.main_js_path.into_into_dart().into_dart(),
self.main_js_content.into_into_dart().into_dart(),
]
.into_dart()
}
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
for crate::api::asar_api::RsiLauncherAsarData
{
}
impl flutter_rust_bridge::IntoIntoDart<crate::api::asar_api::RsiLauncherAsarData>
for crate::api::asar_api::RsiLauncherAsarData
{
fn into_into_dart(self) -> crate::api::asar_api::RsiLauncherAsarData {
self
}
}
// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::http_package::RustHttpResponse {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
[
@ -941,6 +1029,15 @@ impl SseEncode for crate::api::rs_process::RsProcessStreamDataType {
}
}
impl SseEncode for crate::api::asar_api::RsiLauncherAsarData {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<String>::sse_encode(self.asar_path, serializer);
<String>::sse_encode(self.main_js_path, serializer);
<Vec<u8>>::sse_encode(self.main_js_content, serializer);
}
}
impl SseEncode for crate::http_package::RustHttpResponse {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {