Skip to content

Commit

Permalink
added dat file editor
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurHeitmann committed Dec 18, 2023
1 parent 5af9b4a commit b92497f
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 51 deletions.
53 changes: 8 additions & 45 deletions lib/stateManagement/hierarchy/FileHierarchy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,7 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
else {
datFilePaths = await getDatFileList(datExtractDir);
//check if extracted folder actually contains all dat files
if (await Future.any(
datFilePaths.map((name) async
=> !await File(name).exists()))) {
if (await Future.any(datFilePaths.map((name) async => !await File(name).exists()))) {
await extractDatFiles(datPath, shouldExtractPakFiles: true);
}
}
Expand All @@ -201,42 +199,7 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
else
add(datEntry);

var existingEntries = findAllRecWhere((entry) =>
entry is FileHierarchyEntry && entry.path.startsWith(datExtractDir));
for (var entry in existingEntries)
parentOf(entry).remove(entry);

// process DAT files
List<Future<void>> futures = [];
datFilePaths ??= await getDatFileList(datExtractDir);
RubyScriptGroupHierarchyEntry? rubyScriptGroup;
const supportedFileEndings = { ".pak", "_scp.bin", ".tmd", ".smd", ".mcd", ".ftb", ".bnk", ".bxm", ".wta", ".wtb", ".est", ".sst" };
for (var file in datFilePaths) {
if (supportedFileEndings.every((ending) => !file.endsWith(ending)))
continue;
int existingEntryI = existingEntries.indexWhere((entry) => (entry as FileHierarchyEntry).path == file);
if (existingEntryI != -1) {
datEntry.add(existingEntries[existingEntryI]);
continue;
}
if (file.endsWith("_scp.bin")) {
if (rubyScriptGroup == null) {
rubyScriptGroup = RubyScriptGroupHierarchyEntry();
datEntry.add(rubyScriptGroup);
}
futures.add(openBinMrbScript(file, parent: rubyScriptGroup));
}
else
futures.add(openFile(file, parent: datEntry));
}

await Future.wait(futures);

if (rubyScriptGroup != null) {
rubyScriptGroup.name.value += " (${rubyScriptGroup.children.length})";
if (rubyScriptGroup.children.length > 8)
rubyScriptGroup.isCollapsed.value = true;
}
await datEntry.loadChildren(datFilePaths);

return datEntry;
}
Expand Down Expand Up @@ -836,7 +799,7 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements

@override
void remove(HierarchyEntry child, { bool dispose = false }) {
_removeRec(child);
_removeRec(child, freeFiles: dispose);
super.remove(child, dispose: dispose);
}

Expand All @@ -845,26 +808,26 @@ class OpenHierarchyManager with HasUuid, Undoable, HierarchyEntryBase implements
if (children.isEmpty)
return;
for (var child in children) {
_removeRec(child);
_removeRec(child, freeFiles: true);
child.dispose();
}
super.clear();
treeViewIsDirty.value = true;
}

void removeAny(HierarchyEntry child) {
_removeRec(child);
_removeRec(child, freeFiles: true);
parentOf(child).remove(child, dispose: true);
}

void _removeRec(HierarchyEntry entry) {
if (entry is FileHierarchyEntry)
void _removeRec(HierarchyEntry entry, { bool freeFiles = false }) {
if (freeFiles && entry is FileHierarchyEntry)
areasManager.releaseFile(entry.path);
if (entry == _selectedEntry.value)
setSelectedEntry(null);

for (var child in entry.children) {
_removeRec(child);
_removeRec(child, freeFiles: freeFiles);
}
}

Expand Down
13 changes: 12 additions & 1 deletion lib/stateManagement/hierarchy/HierarchyEntryTypes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import '../openFiles/openFilesManager.dart';
import '../preferencesData.dart';
import '../undoable.dart';
import 'FileHierarchy.dart';
import 'types/PakHierarchyEntry.dart';

class HierarchyEntryAction {
final String name;
Expand Down Expand Up @@ -59,6 +60,10 @@ mixin HierarchyEntryBase implements Disposable {
_children.updateOrReplaceWith(newChildren, copy);
}

void sortChildren([int Function(HierarchyEntry, HierarchyEntry)? compare]) {
_children.sort(compare ?? (a, b) => a.name.toString().compareTo(b.name.toString()));
}

HierarchyEntry? findRecWhere(bool Function(HierarchyEntry) test, { Iterable<HierarchyEntry>? children }) {
children ??= this.children;
for (var child in children) {
Expand Down Expand Up @@ -108,7 +113,13 @@ abstract class HierarchyEntry with HasUuid, Undoable, HierarchyEntryBase {
@override
void dispose() {
super.dispose();
name.dispose();
try {
name.dispose();
} catch (e) {
// fix for HapGroupHierarchyEntry, where the name is owned and disposed by an open file
if (this is! HapGroupHierarchyEntry)
rethrow;
}
isSelected.dispose();
isCollapsed.dispose();
isVisibleWithSearch.dispose();
Expand Down
71 changes: 67 additions & 4 deletions lib/stateManagement/hierarchy/types/DatHierarchyEntry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ 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';
import 'PakHierarchyEntry.dart';
import 'RubyScriptHierarchyEntry.dart';
import 'XmlScriptHierarchyEntry.dart';

class DatHierarchyEntry extends ExtractableHierarchyEntry {
DatHierarchyEntry(StringProp name, String path, String extractedPath)
Expand All @@ -35,6 +39,58 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry {
updateOrReplaceWith(entry.children.toList(), (entry) => entry.takeSnapshot() as HierarchyEntry);
}

Future<void> loadChildren(List<String>? datFilePaths) async {
var existingChildren = openHierarchyManager
.findAllRecWhere((entry) => entry is FileHierarchyEntry && dirname(entry.path) == extractedPath);
for (var child in existingChildren)
openHierarchyManager.parentOf(child).remove(child);

List<Future<void>> futures = [];
datFilePaths ??= await getDatFileList(extractedPath);
RubyScriptGroupHierarchyEntry? rubyScriptGroup;
const supportedFileEndings = { ".pak", "_scp.bin", ".tmd", ".smd", ".mcd", ".ftb", ".bnk", ".bxm", ".wta", ".wtb", ".est", ".sst" };
for (var file in datFilePaths) {
if (supportedFileEndings.every((ending) => !file.endsWith(ending)))
continue;
int existingChildI = existingChildren.indexWhere((entry) => (entry as FileHierarchyEntry).path == file);
if (existingChildI != -1) {
var existingChild = existingChildren.removeAt(existingChildI);
add(existingChild);
continue;
}
if (file.endsWith("_scp.bin")) {
if (rubyScriptGroup == null) {
rubyScriptGroup = RubyScriptGroupHierarchyEntry();
add(rubyScriptGroup);
}
futures.add(openHierarchyManager.openBinMrbScript(file, parent: rubyScriptGroup));
}
else
futures.add(openHierarchyManager.openFile(file, parent: this));
}

await Future.wait(futures);

// leftover existing children are no longer in the DAT
for (var child in existingChildren)
child.dispose();

if (rubyScriptGroup != null) {
rubyScriptGroup.name.value += " (${rubyScriptGroup.children.length})";
if (rubyScriptGroup.children.length > 8)
rubyScriptGroup.isCollapsed.value = true;
}

sortChildren((a, b) {
if (a is! FileHierarchyEntry || b is! FileHierarchyEntry)
return a.name.value.toLowerCase().compareTo(b.name.value.toLowerCase());
var extCmp = extension(a.path).compareTo(extension(b.path));
if (extCmp != 0)
return extCmp;
return a.name.value.toLowerCase().compareTo(b.name.value.toLowerCase());
});
}

Future<void> addNewRubyScript() async {
if (await confirmDialog(getGlobalContext(), title: "Add new Ruby Script?") != true)
return;
Expand All @@ -51,7 +107,7 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry {
Future<void> repackDatAction() async {
var prefs = PreferencesData();
if (prefs.dataExportPath?.value == null) {
showToast("No export path set; go to Settings to set an export path");
showToast("No export path set. Go to Settings to set an export path");
return;
}
var datBaseName = basename(extractedPath);
Expand All @@ -61,17 +117,24 @@ class DatHierarchyEntry extends ExtractableHierarchyEntry {

@override
List<HierarchyEntryAction> getActions() {
var scriptRelatedClasses = [RubyScriptGroupHierarchyEntry, RubyScriptHierarchyEntry, XmlScriptHierarchyEntry, PakHierarchyEntry];
return [
HierarchyEntryAction(
name: "Repack DAT",
icon: Icons.file_upload,
action: repackDatAction,
),
HierarchyEntryAction(
name: "Add new Ruby script",
icon: Icons.code,
action: () => addNewRubyScript(),
name: "Change packed files",
icon: Icons.folder_open,
action: () => showDatSelectorPopup(this),
),
if (children.where((child) => scriptRelatedClasses.any((type) => child.runtimeType == type)).isNotEmpty)
HierarchyEntryAction(
name: "Add new Ruby script",
icon: Icons.code,
action: () => addNewRubyScript(),
),
...super.getActions(),
];
}
Expand Down
Loading

0 comments on commit b92497f

Please sign in to comment.