From 5095d2c8d23d4c5a66f0fae9346c2ae176026d8a Mon Sep 17 00:00:00 2001 From: ArthurHeitmann <37270165+ArthurHeitmann@users.noreply.github.com> Date: Fri, 16 Feb 2024 22:39:29 +0100 Subject: [PATCH] Added support for nested DATs; Added prompt when no dat export dir is defined; fixed top level dats exporting to wrong folder --- lib/stateManagement/changesExporter.dart | 9 +-- lib/stateManagement/events/statusInfo.dart | 5 +- .../hierarchy/types/DatHierarchyEntry.dart | 11 +-- .../openFiles/types/FtbFileData.dart | 11 +-- .../openFiles/types/McdFileData.dart | 11 +-- lib/utils/utils.dart | 73 +++++++++++++++++++ lib/widgets/misc/confirmCancelDialog.dart | 3 +- lib/widgets/misc/confirmDialog.dart | 6 +- 8 files changed, 86 insertions(+), 43 deletions(-) diff --git a/lib/stateManagement/changesExporter.dart b/lib/stateManagement/changesExporter.dart index 2ac7c942..110fa4f8 100644 --- a/lib/stateManagement/changesExporter.dart +++ b/lib/stateManagement/changesExporter.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:path/path.dart'; -import '../fileTypeUtils/dat/datRepacker.dart'; import '../fileTypeUtils/pak/pakRepacker.dart'; import '../fileTypeUtils/ruby/pythonRuby.dart'; import '../fileTypeUtils/yax/xmlToYax.dart'; @@ -83,12 +82,8 @@ Future processChangedFiles() async { // } // repack DAT - if (prefs.exportDats?.value == true && prefs.dataExportPath?.value != "") { - await Future.wait(dats.map((datDir) { - var datBaseName = basename(datDir); - var exportPath = join(prefs.dataExportPath!.value, getDatFolder(datBaseName), datBaseName); - return repackDat(datDir, exportPath); - })); + if (prefs.exportDats?.value == true && (prefs.dataExportPath?.value ?? "") != "") { + await Future.wait(dats.map((dat) => exportDat(dat, checkForNesting: true))); } // save WAI diff --git a/lib/stateManagement/events/statusInfo.dart b/lib/stateManagement/events/statusInfo.dart index c6c91792..d877bbe6 100644 --- a/lib/stateManagement/events/statusInfo.dart +++ b/lib/stateManagement/events/statusInfo.dart @@ -26,4 +26,7 @@ class IsLoadingStatus extends ChangeNotifier { final isLoadingStatus = IsLoadingStatus(); final ValueListNotifier messageLog = ValueListNotifier([], fileId: null) - ..addListener(() => print("messageLog: ${messageLog.last}")); + ..addListener(() { + if (messageLog.isNotEmpty) + print("messageLog: ${messageLog.last}"); + }); diff --git a/lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart b/lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart index 956401dc..2333f564 100644 --- a/lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart +++ b/lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart @@ -2,13 +2,11 @@ import 'package:flutter/material.dart'; import 'package:path/path.dart'; -import '../../../fileTypeUtils/dat/datRepacker.dart'; import '../../../main.dart'; import '../../../utils/utils.dart'; import '../../../widgets/FileHierarchyExplorer/datFilesSelector.dart'; import '../../../widgets/misc/confirmDialog.dart'; import '../../Property.dart'; -import '../../preferencesData.dart'; import '../../undoable.dart'; import '../FileHierarchy.dart'; import '../HierarchyEntryTypes.dart'; @@ -105,14 +103,7 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry { } Future repackDatAction() async { - var prefs = PreferencesData(); - if (prefs.dataExportPath?.value == null) { - showToast("No export path set. Go to Settings to set an export path"); - return; - } - var datBaseName = basename(extractedPath); - var exportPath = join(prefs.dataExportPath!.value, getDatFolder(datBaseName), datBaseName); - await repackDat(extractedPath, exportPath); + await exportDat(extractedPath, checkForNesting: true); } @override diff --git a/lib/stateManagement/openFiles/types/FtbFileData.dart b/lib/stateManagement/openFiles/types/FtbFileData.dart index 686c09be..b52ac6ea 100644 --- a/lib/stateManagement/openFiles/types/FtbFileData.dart +++ b/lib/stateManagement/openFiles/types/FtbFileData.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:path/path.dart'; import 'package:tuple/tuple.dart'; -import '../../../fileTypeUtils/dat/datRepacker.dart'; import '../../../fileTypeUtils/ftb/ftbIO.dart'; import '../../../fileTypeUtils/mcd/fontAtlasGeneratorTypes.dart'; import '../../../fileTypeUtils/wta/wtaReader.dart'; @@ -16,7 +15,6 @@ import '../../../utils/assetDirFinder.dart'; import '../../../utils/utils.dart'; import '../../../widgets/filesView/FileType.dart'; import '../../changesExporter.dart'; -import '../../preferencesData.dart'; import '../../undoable.dart'; import '../openFileTypes.dart'; import 'McdFileData.dart'; @@ -295,14 +293,7 @@ class FtbData extends ChangeNotifier { await File(wtpPath).writeAsBytes(wtpBytes.buffer.asUint8List()); // export dtt var dttPath = dirname(wtpPath); - var prefs = PreferencesData(); - if (prefs.dataExportPath?.value == "") { - showToast("Couldn't export DTT file: no export path set"); - } else { - var dttName = basename(dttPath); - var exportPath = join(prefs.dataExportPath!.value, getDatFolder(dttName), dttName); - await repackDat(dttPath, exportPath); - } + await exportDat(dttPath); // update texture sizes for (int i = 0; i < textureBatches.length; i++) { diff --git a/lib/stateManagement/openFiles/types/McdFileData.dart b/lib/stateManagement/openFiles/types/McdFileData.dart index 8e471b34..899a6018 100644 --- a/lib/stateManagement/openFiles/types/McdFileData.dart +++ b/lib/stateManagement/openFiles/types/McdFileData.dart @@ -9,7 +9,6 @@ import 'package:path/path.dart'; import 'package:tuple/tuple.dart'; import '../../../fileTypeUtils/dat/datExtractor.dart'; -import '../../../fileTypeUtils/dat/datRepacker.dart'; import '../../../fileTypeUtils/mcd/defaultFontKerningMap.dart'; import '../../../fileTypeUtils/mcd/fontAtlasGeneratorTypes.dart'; import '../../../fileTypeUtils/mcd/mcdIO.dart'; @@ -24,7 +23,6 @@ import '../../events/statusInfo.dart'; import '../../hasUuid.dart'; import '../../listNotifier.dart'; import '../../openFiles/openFilesManager.dart'; -import '../../preferencesData.dart'; import '../../undoable.dart'; import '../openFileTypes.dart'; @@ -975,14 +973,7 @@ class McdData extends _McdFilePart { // export dtt var dttPath = dirname(textureWtpPath!.value); - var prefs = PreferencesData(); - if (prefs.dataExportPath?.value == "") { - showToast("Couldn't export DTT file: no export path set"); - } else { - var dttName = basename(dttPath); - var exportPath = join(prefs.dataExportPath!.value, getDatFolder(dttName), dttName); - await repackDat(dttPath, exportPath); - } + await exportDat(dttPath); print("Generated font texture with ${symbols.length} symbols"); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index ca734e60..9c4ce313 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:math'; import 'package:crclib/catalog.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; @@ -15,6 +16,7 @@ import 'package:uuid/uuid.dart'; import 'package:xml/xml.dart'; import '../fileTypeUtils/dat/datExtractor.dart'; +import '../fileTypeUtils/dat/datRepacker.dart'; import '../fileTypeUtils/utils/ByteDataWrapper.dart'; import '../fileTypeUtils/yax/hashToStringMap.dart'; import '../fileTypeUtils/yax/japToEng.dart'; @@ -23,6 +25,8 @@ import '../stateManagement/Property.dart'; import '../stateManagement/events/statusInfo.dart'; import '../stateManagement/miscValues.dart'; import '../stateManagement/openFiles/types/xml/xmlProps/xmlProp.dart'; +import '../stateManagement/preferencesData.dart'; +import '../widgets/misc/confirmCancelDialog.dart'; import '../widgets/misc/contextMenuBuilder.dart'; import '../widgets/theme/customTheme.dart'; import 'assetDirFinder.dart'; @@ -468,7 +472,17 @@ const Map _nameStartToFolder = { "subtitle": "subtitle", "txt": "txtmess", }; +const _topLevelFileNames = { + "autoshadereff.dat", + "autoshadereffInfo.bxm", + "shader.dat", + "shader2.dat", + "shadereff.dat", + "shadereffcs.dat", +}; String getDatFolder(String datName) { + if (_topLevelFileNames.contains(datName)) + return ""; if (datName.endsWith(".eff")) return "effect"; var c2 = datName.substring(0, 2); @@ -532,6 +546,65 @@ Future> _getDatFileListFromMetadata(String metadataPath) async { return files; } +Future exportDat(String datFolder, { bool checkForNesting = false }) async { + var exportDir = PreferencesData().dataExportPath?.value ?? ""; + if (exportDir.isNotEmpty && !await Directory(exportDir).exists()) { + messageLog.add("Export path does not exist: $exportDir"); + exportDir = ""; + } + var datName = basename(datFolder); + String datExportDir = ""; + bool recursive = false; + // check if this DAT is inside another DAT + if (checkForNesting) { + var parentDirs = [dirname(datFolder), dirname(dirname(datFolder))]; + for (var parentDir in parentDirs) { + if (!await Directory(parentDir).exists()) + break; + var dirName = basename(parentDir); + if (!dirName.contains(".")) + continue; + var ext = extension(dirName); + if (!datExtensions.contains(ext)) + continue; + var exportToParent = await confirmOrCancelDialog( + getGlobalContext(), + title: "Export $datName to parent DAT folder?", + body: "Parent is ...\\$dirName\\", + yesText: "To $dirName", + noText: exportDir.isEmpty ? "Select export path" : "To export path", + ); + if (exportToParent == null) + return; + if (!exportToParent) + break; + datExportDir = parentDir; + recursive = true; + } + } + if (datExportDir.isEmpty) { + // select export path + if (exportDir.isEmpty) { + var dir = await FilePicker.platform.getDirectoryPath( + dialogTitle: "Select DAT export folder", + ); + if (dir == null) + return; + datExportDir = dir; + } + // export to export path from preferences + else { + var datSubDir = getDatFolder(datName); + datExportDir = join(exportDir, datSubDir); + } + } + var datExportPath = join(datExportDir, datName); + await repackDat(datFolder, datExportPath); + + if (recursive) + await exportDat(datExportDir, checkForNesting: true); +} + String pluralStr(int number, String label, [String numberSuffix = ""]) { if (number == 1) return "$number$numberSuffix $label"; diff --git a/lib/widgets/misc/confirmCancelDialog.dart b/lib/widgets/misc/confirmCancelDialog.dart index a7a9acd2..5d3473c9 100644 --- a/lib/widgets/misc/confirmCancelDialog.dart +++ b/lib/widgets/misc/confirmCancelDialog.dart @@ -31,8 +31,7 @@ Future confirmOrCancelDialog(BuildContext context, { required String titl Text(body, style: Theme.of(context).textTheme.bodyText2), ], const SizedBox(height: 16), - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 300), + IntrinsicWidth( child: RowSeparated( separatorWidth: 5, mainAxisAlignment: MainAxisAlignment.end, diff --git a/lib/widgets/misc/confirmDialog.dart b/lib/widgets/misc/confirmDialog.dart index 9ec2508e..d24b7af1 100644 --- a/lib/widgets/misc/confirmDialog.dart +++ b/lib/widgets/misc/confirmDialog.dart @@ -7,7 +7,7 @@ import '../../widgets/theme/customTheme.dart'; import 'RowSeparated.dart'; import 'SmoothScrollBuilder.dart'; -Future confirmDialog(BuildContext context, { required String title, String? body }) { +Future confirmDialog(BuildContext context, { required String title, String? body, confirmText = "Confirm", cancelText = "Cancel" }) { var result = Completer(); showDialog( context: context, @@ -49,7 +49,7 @@ Future confirmDialog(BuildContext context, { required String title, Strin Navigator.of(context).pop(); }, style: getTheme(context).dialogPrimaryButtonStyle, - child: const Text("Confirm"), + child: Text(confirmText), ), ElevatedButton( onPressed: () { @@ -57,7 +57,7 @@ Future confirmDialog(BuildContext context, { required String title, Strin Navigator.of(context).pop(); }, style: getTheme(context).dialogSecondaryButtonStyle, - child: const Text("Cancel"), + child: Text(cancelText), ), ], ),