Skip to content

Commit

Permalink
show unopenable dat children; remember last repack target
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurHeitmann committed Dec 13, 2024
1 parent c9d8f1d commit b78ca0b
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 29 deletions.
4 changes: 3 additions & 1 deletion assets/help/dat.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ The file structure of the extracted files is the following:

Note: The *nier2blender_extracted* folder name has been chosen for backwards compatibility with the Blender addons DAT extractor.

F-SERVO will ONLY display files it can edit in the ui. If you want to see all files, you have to go to the extracted folder. You can right click on the file and select "Show in Explorer" to open the folder.
F-SERVO will by default display files it can edit in the ui. If you want to see all files, you either have to go to the extracted folder. You can right click on the file and select "Show in Explorer" to open the folder.
Alternatively in the settings enable "Show non editable DAT children".

## Editing files

Expand All @@ -42,6 +43,7 @@ be placed in `...\Metal Gear Rising Revengeance\GameData\pl\pl3000.dat`.
### Manually select file location

If you haven't set the "Data export path" in settings, clicking "Repack DAT" will open a file dialog where you can select the folder to save the repacked DAT.
For the next export, you can choose "Repack DAT to last location" to export to the same file again.

### Overwrite original

Expand Down
13 changes: 7 additions & 6 deletions lib/stateManagement/hierarchy/FileHierarchy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,18 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
return entry;
}

Future<HierarchyEntry> openDat(String datPath, { HierarchyEntry? parent, bool allowMissingInfoFile = false }) async {
Future<HierarchyEntry> openDat(String datPath, { HierarchyEntry? parent, String? datExtractDir, bool allowMissingInfoFile = false }) async {
var existing = findRecWhere((entry) => entry is DatHierarchyEntry && entry.path == datPath);
if (existing != null)
return existing;

// get DAT infos
var fileName = basename(datPath);
var datFolder = dirname(datPath);
var datExtractDir = join(datFolder, datSubExtractDir, fileName);
datExtractDir ??= join(datFolder, datSubExtractDir, fileName);
DatFiles? datFilePaths;
if (!await Directory(datExtractDir).exists()) {
var srcDatExists = await File(datPath).exists();
if (!await Directory(datExtractDir).exists() && srcDatExists) {
await extractDatFiles(datPath, shouldExtractPakFiles: true);
}
else {
Expand All @@ -222,12 +223,12 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
if (shouldExtractDatFiles) {
await extractDatFiles(datPath, shouldExtractPakFiles: true);
}
else if (datFilePaths?.originalFileOrder == null) {
else if (datFilePaths?.originalFileOrder == null && srcDatExists) {
await updateDatInfoFileOriginalOrder(datPath, datExtractDir);
}
}

var datEntry = DatHierarchyEntry(StringProp(fileName, fileId: null), datPath, datExtractDir);
var datEntry = DatHierarchyEntry(StringProp(fileName, fileId: null), datPath, datExtractDir, srcDatExists: srcDatExists);
if (parent != null) {
datEntry.isCollapsed.value = true;
parent.add(datEntry);
Expand All @@ -243,7 +244,7 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
Future<HierarchyEntry> openExtractedDat(String datDirPath, { HierarchyEntry? parent }) {
var srcDatDir = dirname(dirname(datDirPath));
var srcDatPath = join(srcDatDir, basename(datDirPath));
return openDat(srcDatPath, parent: parent, allowMissingInfoFile: true);
return openDat(srcDatPath, parent: parent, datExtractDir: datDirPath, allowMissingInfoFile: true);
}

HapGroupHierarchyEntry? findPakParentGroup(String fileName) {
Expand Down
31 changes: 24 additions & 7 deletions lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import 'RubyScriptHierarchyEntry.dart';
import 'XmlScriptHierarchyEntry.dart';

class DatHierarchyEntry extends ExtractableHierarchyEntry {
DatHierarchyEntry(StringProp name, String path, String extractedPath)
final bool srcDatExists;
String? lastExportPath;

DatHierarchyEntry(StringProp name, String path, String extractedPath, {this.srcDatExists = true})
: super(name, path, extractedPath, true, false, priority: 1000);

@override
Expand Down Expand Up @@ -115,7 +118,13 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry {
}

Future<void> repackDatAction() async {
await exportDat(extractedPath, checkForNesting: true);
var datPath = await exportDat(extractedPath, checkForNesting: true);
if (datPath != null)
lastExportPath = datPath;
}

Future<void> repackDatToLastAction() async {
await exportDat(extractedPath, datExportPath: lastExportPath, checkForNesting: true);
}

Future<void> repackOverwriteDatAction() async {
Expand All @@ -125,17 +134,25 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry {
@override
List<HierarchyEntryAction> getActions() {
var scriptRelatedClasses = [RubyScriptGroupHierarchyEntry, RubyScriptHierarchyEntry, XmlScriptHierarchyEntry, PakHierarchyEntry];
var prefs = PreferencesData();
return [
HierarchyEntryAction(
name: "Repack DAT",
icon: Icons.file_upload,
action: repackDatAction,
),
HierarchyEntryAction(
name: "Repack DAT (overwrite)",
icon: Icons.file_upload,
action: repackOverwriteDatAction,
),
if (lastExportPath != null && (prefs.dataExportPath?.value ?? "").isEmpty)
HierarchyEntryAction(
name: "Repack DAT to last location",
icon: Icons.file_upload,
action: repackDatToLastAction,
),
if (srcDatExists)
HierarchyEntryAction(
name: "Repack DAT (overwrite)",
icon: Icons.file_upload,
action: repackOverwriteDatAction,
),
HierarchyEntryAction(
name: "Change packed files",
icon: Icons.folder_open,
Expand Down
10 changes: 6 additions & 4 deletions lib/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ Future<DatFiles> _getDatFileListFromMetadata(String metadataPath) async {
return DatFiles(files, files);
}

Future<void> exportDat(String datFolder, { bool checkForNesting = false, bool overwriteOriginal = false }) async {
Future<String?> exportDat(String datFolder, { bool checkForNesting = false, bool overwriteOriginal = false, String? datExportPath }) async {
var exportDir = PreferencesData().dataExportPath?.value ?? "";
if (exportDir.isNotEmpty && !await Directory(exportDir).exists()) {
messageLog.add("Export path does not exist: $exportDir");
Expand Down Expand Up @@ -599,7 +599,7 @@ Future<void> exportDat(String datFolder, { bool checkForNesting = false, bool ov
noText: exportDir.isEmpty ? "Select export path" : "To export path",
);
if (exportToParent == null)
return;
return null;
if (!exportToParent)
break;
datExportDir = parentDir;
Expand All @@ -613,7 +613,7 @@ Future<void> exportDat(String datFolder, { bool checkForNesting = false, bool ov
dialogTitle: "Select DAT export folder",
);
if (dir == null)
return;
return null;
datExportDir = dir;
}
// export to export path from preferences
Expand All @@ -622,7 +622,7 @@ Future<void> exportDat(String datFolder, { bool checkForNesting = false, bool ov
datExportDir = join(exportDir, datSubDir);
}
}
var datExportPath = join(datExportDir, datName);
datExportPath ??= join(datExportDir, datName);
try {
await repackDat(datFolder, datExportPath);
} catch (e) {
Expand All @@ -632,6 +632,8 @@ Future<void> exportDat(String datFolder, { bool checkForNesting = false, bool ov

if (recursive)
await exportDat(datExportDir, checkForNesting: true);

return datExportPath;
}

String pluralStr(int number, String label, [String numberSuffix = ""]) {
Expand Down
16 changes: 8 additions & 8 deletions lib/widgets/FileHierarchyExplorer/HierarchyEntryWidget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ class _HierarchyEntryState extends ChangeNotifierState<HierarchyEntryWidget> {

Widget setupContextMenu({ required Widget child }) {
return ContextMenu(
config: widget.entry.getContextMenuActions()
.map((action) => ContextMenuConfig(
label: action.name,
icon: Icon(action.icon, size: 15 * action.iconScale,),
action: () => action.action(),
))
.toList(),
child: child,
configBuilder: () => widget.entry.getContextMenuActions()
.map((action) => ContextMenuConfig(
label: action.name,
icon: Icon(action.icon, size: 15 * action.iconScale,),
action: () => action.action(),
))
.toList(),
child: child,
);
}

Expand Down
7 changes: 4 additions & 3 deletions lib/widgets/misc/contextMenuBuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ class ContextMenuConfig {
}

class ContextMenu extends StatefulWidget {
final List<ContextMenuConfig?> config;
final List<ContextMenuConfig?>? config;
final List<ContextMenuConfig?> Function()? configBuilder;
final Widget child;

const ContextMenu({super.key, required this.config, required this.child});
const ContextMenu({super.key, this.config, this.configBuilder, required this.child});

@override
State<ContextMenu> createState() => _ContextMenuState();
Expand Down Expand Up @@ -59,7 +60,7 @@ class _ContextMenuState extends State<ContextMenu> {
var x = min(pos.dx, size.width - 300);
var y = min(pos.dy, size.height - 300);
return _ContextMenu(
config: widget.config,
config: widget.config ?? widget.configBuilder?.call() ?? [],
x: x,
y: y,
hide: hide,
Expand Down

0 comments on commit b78ca0b

Please sign in to comment.