mirror of
https://ghfast.top/https://github.com/StarCitizenToolBox/app.git
synced 2025-06-28 07:54:44 +08:00
feat: unp4kc
This commit is contained in:
@ -6,7 +6,7 @@ part of 'aria2c.dart';
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$aria2cModelHash() => r'6685f6a716016113487de190a61f71196094526e';
|
||||
String _$aria2cModelHash() => r'5431c2d9667f17ff03d0794711af22b015feda0d';
|
||||
|
||||
/// See also [Aria2cModel].
|
||||
@ProviderFor(Aria2cModel)
|
||||
|
191
lib/provider/unp4kc.dart
Normal file
191
lib/provider/unp4kc.dart
Normal file
@ -0,0 +1,191 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:starcitizen_doctor/common/conf/binary_conf.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/log.dart';
|
||||
import 'package:starcitizen_doctor/common/utils/provider.dart';
|
||||
import 'package:starcitizen_doctor/data/app_unp4k_p4k_item_data.dart';
|
||||
import 'package:starcitizen_doctor/ui/tools/tools_ui_model.dart';
|
||||
|
||||
part 'unp4kc.freezed.dart';
|
||||
|
||||
part 'unp4kc.g.dart';
|
||||
|
||||
@freezed
|
||||
class Unp4kcState with _$Unp4kcState {
|
||||
const factory Unp4kcState({
|
||||
required bool startUp,
|
||||
Map<String, AppUnp4kP4kItemData>? files,
|
||||
MemoryFileSystem? fs,
|
||||
required String curPath,
|
||||
String? endMessage,
|
||||
MapEntry<String, String>? tempOpenFile,
|
||||
}) = _Unp4kcState;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class Unp4kCModel extends _$Unp4kCModel {
|
||||
Process? _process;
|
||||
|
||||
@override
|
||||
Unp4kcState build() {
|
||||
state =
|
||||
const Unp4kcState(startUp: false, curPath: '\\', endMessage: "初始化中...");
|
||||
_init();
|
||||
return state;
|
||||
}
|
||||
|
||||
ToolsUIState get _toolsState => ref.read(toolsUIModelProvider);
|
||||
|
||||
String getGamePath() => _toolsState.scInstalledPath;
|
||||
|
||||
void _init() async {
|
||||
final execDir = "${appGlobalState.applicationBinaryModuleDir}\\unp4kc";
|
||||
await BinaryModuleConf.extractModule(
|
||||
["unp4kc"], appGlobalState.applicationBinaryModuleDir!);
|
||||
final exec = "$execDir\\unp4kc.exe";
|
||||
final ps = await Process.start(exec, []);
|
||||
StringBuffer stringBuffer = StringBuffer();
|
||||
_process = ps;
|
||||
ps.stdout.listen((event) async {
|
||||
final eventStr = String.fromCharCodes(event);
|
||||
stringBuffer.write(eventStr);
|
||||
if (!eventStr.endsWith("\n")) return;
|
||||
final str = stringBuffer.toString().trim();
|
||||
stringBuffer.clear();
|
||||
try {
|
||||
final eventJson = await compute(json.decode, str);
|
||||
_handleMessage(eventJson, ps);
|
||||
} catch (e) {
|
||||
dPrint("[unp4kc] json error: $e");
|
||||
}
|
||||
});
|
||||
ps.stderr.listen((event) {
|
||||
final eventStr = String.fromCharCodes(event);
|
||||
dPrint("[unp4kc] stderr: $eventStr");
|
||||
});
|
||||
state = state.copyWith(startUp: true);
|
||||
ref.onDispose(() {
|
||||
ps.kill();
|
||||
dPrint("[unp4kc] kill ...");
|
||||
});
|
||||
}
|
||||
|
||||
void _handleMessage(Map<String, dynamic> eventJson, Process ps) async {
|
||||
final action = eventJson["action"];
|
||||
final data = eventJson["data"];
|
||||
final gamePath = getGamePath();
|
||||
final gameP4kPath = "$gamePath\\Data.p4k";
|
||||
switch (action.toString().trim()) {
|
||||
case "info: startup":
|
||||
ps.stdin.writeln(gameP4kPath);
|
||||
state = state.copyWith(endMessage: "正在读取P4K 文件 ...");
|
||||
break;
|
||||
case "data: P4K_Files":
|
||||
final p4kFiles = (data as List<dynamic>);
|
||||
final files = <String, AppUnp4kP4kItemData>{};
|
||||
final fs = MemoryFileSystem(style: FileSystemStyle.posix);
|
||||
state = state.copyWith(endMessage: "正在处理文件 ...");
|
||||
for (var i = 0; i < p4kFiles.length; i++) {
|
||||
final item = AppUnp4kP4kItemData.fromJson(p4kFiles[i]);
|
||||
item.name = "${item.name}";
|
||||
files["\\${item.name}"] = item;
|
||||
await fs
|
||||
.file(item.name?.replaceAll("\\", "/") ?? "")
|
||||
.create(recursive: true);
|
||||
}
|
||||
state = state.copyWith(
|
||||
files: files, fs: fs, endMessage: "加载完毕:${files.length} 个文件");
|
||||
break;
|
||||
case "info: Extracted_Open":
|
||||
final filePath = data.toString();
|
||||
dPrint("[unp4kc] Extracted_Open file: $filePath");
|
||||
const textExt = [".txt", ".xml", ".json", ".lua", ".cfg", ".ini"];
|
||||
const imgExt = [".png"];
|
||||
String openType = "unknown";
|
||||
for (var element in textExt) {
|
||||
if (filePath.endsWith(element)) {
|
||||
openType = "text";
|
||||
}
|
||||
}
|
||||
for (var element in imgExt) {
|
||||
if (filePath.endsWith(element)) {
|
||||
openType = "image";
|
||||
}
|
||||
}
|
||||
|
||||
state = state.copyWith(
|
||||
tempOpenFile: MapEntry(openType, filePath),
|
||||
endMessage: "打开文件:$filePath");
|
||||
break;
|
||||
default:
|
||||
dPrint("[unp4kc] unknown action: $action");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<AppUnp4kP4kItemData>? getFiles() {
|
||||
final path = state.curPath.replaceAll("\\", "/");
|
||||
final fs = state.fs;
|
||||
if (fs == null) return null;
|
||||
final dir = fs.directory(path);
|
||||
if (!dir.existsSync()) return [];
|
||||
final files = dir.listSync(recursive: false, followLinks: false);
|
||||
files.sort((a, b) {
|
||||
if (a is Directory && b is File) {
|
||||
return -1;
|
||||
} else if (a is File && b is Directory) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.path.compareTo(b.path);
|
||||
}
|
||||
});
|
||||
final result = <AppUnp4kP4kItemData>[];
|
||||
for (var file in files) {
|
||||
if (file is File) {
|
||||
final f = state.files?[file.path.replaceAll("/", "\\")];
|
||||
if (f != null) {
|
||||
if (!(f.name?.startsWith("\\") ?? true)) {
|
||||
f.name = "\\${f.name}";
|
||||
}
|
||||
result.add(f);
|
||||
}
|
||||
} else {
|
||||
result.add(AppUnp4kP4kItemData(
|
||||
name: file.path.replaceAll("/", "\\"), isDirectory: true));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void changeDir(String name, {bool fullPath = false}) {
|
||||
if (fullPath) {
|
||||
state = state.copyWith(curPath: name);
|
||||
} else {
|
||||
state = state.copyWith(curPath: "${state.curPath}$name\\");
|
||||
}
|
||||
}
|
||||
|
||||
openFile(String filePath) async {
|
||||
final tempPath = "${appGlobalState.applicationSupportDir}\\temp\\unp4k\\";
|
||||
state = state.copyWith(
|
||||
tempOpenFile: const MapEntry("loading", ""),
|
||||
endMessage: "读取文件:$filePath ...");
|
||||
extractFile(filePath, tempPath, mode: "extract_open");
|
||||
}
|
||||
|
||||
extractFile(String filePath, String outputPath,
|
||||
{String mode = "extract"}) async {
|
||||
// remove first \\
|
||||
if (filePath.startsWith("\\")) {
|
||||
filePath = filePath.substring(1);
|
||||
}
|
||||
outputPath = "$outputPath$filePath";
|
||||
dPrint("extractFile .... $filePath");
|
||||
_process?.stdin.writeln("$mode<:,:>$filePath<:,:>$outputPath");
|
||||
}
|
||||
}
|
269
lib/provider/unp4kc.freezed.dart
Normal file
269
lib/provider/unp4kc.freezed.dart
Normal file
@ -0,0 +1,269 @@
|
||||
// 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 'unp4kc.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 _$Unp4kcState {
|
||||
bool get startUp => throw _privateConstructorUsedError;
|
||||
Map<String, AppUnp4kP4kItemData>? get files =>
|
||||
throw _privateConstructorUsedError;
|
||||
MemoryFileSystem? get fs => throw _privateConstructorUsedError;
|
||||
String get curPath => throw _privateConstructorUsedError;
|
||||
String? get endMessage => throw _privateConstructorUsedError;
|
||||
MapEntry<String, String>? get tempOpenFile =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$Unp4kcStateCopyWith<Unp4kcState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $Unp4kcStateCopyWith<$Res> {
|
||||
factory $Unp4kcStateCopyWith(
|
||||
Unp4kcState value, $Res Function(Unp4kcState) then) =
|
||||
_$Unp4kcStateCopyWithImpl<$Res, Unp4kcState>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool startUp,
|
||||
Map<String, AppUnp4kP4kItemData>? files,
|
||||
MemoryFileSystem? fs,
|
||||
String curPath,
|
||||
String? endMessage,
|
||||
MapEntry<String, String>? tempOpenFile});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$Unp4kcStateCopyWithImpl<$Res, $Val extends Unp4kcState>
|
||||
implements $Unp4kcStateCopyWith<$Res> {
|
||||
_$Unp4kcStateCopyWithImpl(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? startUp = null,
|
||||
Object? files = freezed,
|
||||
Object? fs = freezed,
|
||||
Object? curPath = null,
|
||||
Object? endMessage = freezed,
|
||||
Object? tempOpenFile = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
startUp: null == startUp
|
||||
? _value.startUp
|
||||
: startUp // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
files: freezed == files
|
||||
? _value.files
|
||||
: files // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, AppUnp4kP4kItemData>?,
|
||||
fs: freezed == fs
|
||||
? _value.fs
|
||||
: fs // ignore: cast_nullable_to_non_nullable
|
||||
as MemoryFileSystem?,
|
||||
curPath: null == curPath
|
||||
? _value.curPath
|
||||
: curPath // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endMessage: freezed == endMessage
|
||||
? _value.endMessage
|
||||
: endMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
tempOpenFile: freezed == tempOpenFile
|
||||
? _value.tempOpenFile
|
||||
: tempOpenFile // ignore: cast_nullable_to_non_nullable
|
||||
as MapEntry<String, String>?,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$Unp4kcStateImplCopyWith<$Res>
|
||||
implements $Unp4kcStateCopyWith<$Res> {
|
||||
factory _$$Unp4kcStateImplCopyWith(
|
||||
_$Unp4kcStateImpl value, $Res Function(_$Unp4kcStateImpl) then) =
|
||||
__$$Unp4kcStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{bool startUp,
|
||||
Map<String, AppUnp4kP4kItemData>? files,
|
||||
MemoryFileSystem? fs,
|
||||
String curPath,
|
||||
String? endMessage,
|
||||
MapEntry<String, String>? tempOpenFile});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$Unp4kcStateImplCopyWithImpl<$Res>
|
||||
extends _$Unp4kcStateCopyWithImpl<$Res, _$Unp4kcStateImpl>
|
||||
implements _$$Unp4kcStateImplCopyWith<$Res> {
|
||||
__$$Unp4kcStateImplCopyWithImpl(
|
||||
_$Unp4kcStateImpl _value, $Res Function(_$Unp4kcStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? startUp = null,
|
||||
Object? files = freezed,
|
||||
Object? fs = freezed,
|
||||
Object? curPath = null,
|
||||
Object? endMessage = freezed,
|
||||
Object? tempOpenFile = freezed,
|
||||
}) {
|
||||
return _then(_$Unp4kcStateImpl(
|
||||
startUp: null == startUp
|
||||
? _value.startUp
|
||||
: startUp // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
files: freezed == files
|
||||
? _value._files
|
||||
: files // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, AppUnp4kP4kItemData>?,
|
||||
fs: freezed == fs
|
||||
? _value.fs
|
||||
: fs // ignore: cast_nullable_to_non_nullable
|
||||
as MemoryFileSystem?,
|
||||
curPath: null == curPath
|
||||
? _value.curPath
|
||||
: curPath // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
endMessage: freezed == endMessage
|
||||
? _value.endMessage
|
||||
: endMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
tempOpenFile: freezed == tempOpenFile
|
||||
? _value.tempOpenFile
|
||||
: tempOpenFile // ignore: cast_nullable_to_non_nullable
|
||||
as MapEntry<String, String>?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$Unp4kcStateImpl with DiagnosticableTreeMixin implements _Unp4kcState {
|
||||
const _$Unp4kcStateImpl(
|
||||
{required this.startUp,
|
||||
final Map<String, AppUnp4kP4kItemData>? files,
|
||||
this.fs,
|
||||
required this.curPath,
|
||||
this.endMessage,
|
||||
this.tempOpenFile})
|
||||
: _files = files;
|
||||
|
||||
@override
|
||||
final bool startUp;
|
||||
final Map<String, AppUnp4kP4kItemData>? _files;
|
||||
@override
|
||||
Map<String, AppUnp4kP4kItemData>? get files {
|
||||
final value = _files;
|
||||
if (value == null) return null;
|
||||
if (_files is EqualUnmodifiableMapView) return _files;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
final MemoryFileSystem? fs;
|
||||
@override
|
||||
final String curPath;
|
||||
@override
|
||||
final String? endMessage;
|
||||
@override
|
||||
final MapEntry<String, String>? tempOpenFile;
|
||||
|
||||
@override
|
||||
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
|
||||
return 'Unp4kcState(startUp: $startUp, files: $files, fs: $fs, curPath: $curPath, endMessage: $endMessage, tempOpenFile: $tempOpenFile)';
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('type', 'Unp4kcState'))
|
||||
..add(DiagnosticsProperty('startUp', startUp))
|
||||
..add(DiagnosticsProperty('files', files))
|
||||
..add(DiagnosticsProperty('fs', fs))
|
||||
..add(DiagnosticsProperty('curPath', curPath))
|
||||
..add(DiagnosticsProperty('endMessage', endMessage))
|
||||
..add(DiagnosticsProperty('tempOpenFile', tempOpenFile));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$Unp4kcStateImpl &&
|
||||
(identical(other.startUp, startUp) || other.startUp == startUp) &&
|
||||
const DeepCollectionEquality().equals(other._files, _files) &&
|
||||
(identical(other.fs, fs) || other.fs == fs) &&
|
||||
(identical(other.curPath, curPath) || other.curPath == curPath) &&
|
||||
(identical(other.endMessage, endMessage) ||
|
||||
other.endMessage == endMessage) &&
|
||||
(identical(other.tempOpenFile, tempOpenFile) ||
|
||||
other.tempOpenFile == tempOpenFile));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
startUp,
|
||||
const DeepCollectionEquality().hash(_files),
|
||||
fs,
|
||||
curPath,
|
||||
endMessage,
|
||||
tempOpenFile);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$Unp4kcStateImplCopyWith<_$Unp4kcStateImpl> get copyWith =>
|
||||
__$$Unp4kcStateImplCopyWithImpl<_$Unp4kcStateImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _Unp4kcState implements Unp4kcState {
|
||||
const factory _Unp4kcState(
|
||||
{required final bool startUp,
|
||||
final Map<String, AppUnp4kP4kItemData>? files,
|
||||
final MemoryFileSystem? fs,
|
||||
required final String curPath,
|
||||
final String? endMessage,
|
||||
final MapEntry<String, String>? tempOpenFile}) = _$Unp4kcStateImpl;
|
||||
|
||||
@override
|
||||
bool get startUp;
|
||||
@override
|
||||
Map<String, AppUnp4kP4kItemData>? get files;
|
||||
@override
|
||||
MemoryFileSystem? get fs;
|
||||
@override
|
||||
String get curPath;
|
||||
@override
|
||||
String? get endMessage;
|
||||
@override
|
||||
MapEntry<String, String>? get tempOpenFile;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$Unp4kcStateImplCopyWith<_$Unp4kcStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
25
lib/provider/unp4kc.g.dart
Normal file
25
lib/provider/unp4kc.g.dart
Normal file
@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'unp4kc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$unp4kCModelHash() => r'46b6ac12670a6ff6ffb9d5bc8a8d04c07c570a8c';
|
||||
|
||||
/// See also [Unp4kCModel].
|
||||
@ProviderFor(Unp4kCModel)
|
||||
final unp4kCModelProvider =
|
||||
AutoDisposeNotifierProvider<Unp4kCModel, Unp4kcState>.internal(
|
||||
Unp4kCModel.new,
|
||||
name: r'unp4kCModelProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$unp4kCModelHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$Unp4kCModel = AutoDisposeNotifier<Unp4kcState>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
Reference in New Issue
Block a user