#modding #lua #light #dat #faster #game #package

ftldat

Rust 实现的 FTLDat - 一个用于解包和重新打包 .dat 文件的简单库,该文件由游戏《Into the Breach》和《Faster than Light》使用

2 个版本

0.1.1 2023 年 4 月 19 日
0.1.0 2023 年 4 月 16 日

#679 in 文件系统

GPL-3.0 许可证

50KB
762

FTLDat-rs

Rust 实现的 FTLDat - 一个用于解包和重新打包 .dat 文件的简单库,该文件由游戏《Into the Breach》和《Faster than Light》(直到版本 1.6.1)使用。

此库还支持 FTL 版本 1.6.1 之后使用的 PKG 格式。

使用说明

打开包相当简单

use ftldat::Package;

let package = Package::from_path_dat("path/to/file.dat");

// Can now query the package's contents, list or iterate...
println!("Number of entries: {}", &package.entry_count());
println!("Does the package contain a file at path 'test.txt'? {}", &package.entry_exists("test.txt"));

// List paths of all files within the package
let inner_paths = package.inner_paths();

for entry in package.iter() {
    // Do something with each entry
}

底层文件是内存映射的,仅在首次创建 package 实例或获取条目内容时读取。

可以修改包以添加、替换或删除条目

use ftldat::{Package, PackageEntry};

let mut package = Package::from_path_dat("path/to/file.dat");

// `add_entry` will only add the entry if the package does NOT already contain an entry at the specified
// path (test.txt). Otherwise, an error is returned.
package.add_entry(PackageEntry::from_string("test.txt", "My text file's content."));

// `put_entry` will overwrite the entry at the specified path (test2.txt) with the provided entry.
package.put_entry(PackageEntry::from_string("test2.txt", "Lorem ipsum dolor sit amet"));

// Remove individual entry
package.remove_entry("test.txt");

// Remove all entries
package.clear();

条目可以通过几种方式创建

// Directly from a string, mostly useful for testing (functionally the same as in-memory byte array)
let entry = PackageEntry::from_string("file.txt", "Lorem ipsum dolor sit amet");

// From a file on disk
let entry = PackageEntry::from_file("file.png", "path/to/file.png");

// From an in-memory byte array
let content = [0, 1, 2, 3];
PackageEntry::from_byte_array("file.bin", content.into());

// From a memory-mapped file
let mmap = ...     // Reference to the memory map
let mmap_rc = Rc::new(mmap);
let offset = ...   // Offset to the beginning of the entry's content within the memory-mapped file
let length = ...   // Number of bytes that make up the entry's content
let entry = PackageEntry::from_memory_mapped_file(
    "file.wav",
    mmap_rc.clone(),
    offset,
    length
);

可以将包写回文件

use ftldat::Package;

let package = Package::from_path_dat("path/to/file.dat");

// `write_to_path_*` does not consume the `package`, allowing for multiple writes, but only allows writing
// to files other than the file from which the package was originally loaded.
package.to_path_dat("path/to/other/file.dat");

// `write_into_path_*` consumes the `package`, but releases file system resources and allows overwriting
// the file from which the package was originally loaded.
package.write_into_path_dat(package, "path/to/file.dat");

也可以提取包的内容

use ftldat::Package;

let package = Package::from_path_dat("path/to/file.dat");
package.extract("destination/directory/");

许可证

该项目根据 GPLv3 许可证授权,因为其部分内容最初受到 Slipstream Mod Manager 实现的启发

改进区域

鉴于这个项目是我熟悉 Rust 的方式,肯定有很多改进的空间。以下是一些无序的建议

  • 错误处理。尝试使用流行的错误处理 crate thiserror,但对此不太自信。
  • 字符串的所有权,我只是使用了堆分配的 Strings 并四处复制它们
  • 函数命名,遵循 Rust 正确的约定(frominto 等)
  • 将结构体序列化为字节的处理可能更好(尽管我喜欢将内存和磁盘上的表示分开)

依赖关系

~0.5–1MB
~22K SLoC