diff options
author | Valentin Popov <valentin@popov.link> | 2025-02-08 04:11:02 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2025-02-08 04:11:02 +0300 |
commit | 8d8653133bf3a12ac58c0e4f34624e9beac11751 (patch) | |
tree | ac0831704db9f138a90872b530eabda457db1829 /unpacker | |
parent | 94d2f8a512312b8aff25672760b687e6d90c1ec9 (diff) | |
download | fparkan-8d8653133bf3a12ac58c0e4f34624e9beac11751.tar.xz fparkan-8d8653133bf3a12ac58c0e4f34624e9beac11751.zip |
Обновление структуры проекта
Diffstat (limited to 'unpacker')
-rw-r--r-- | unpacker/Cargo.toml | 9 | ||||
-rw-r--r-- | unpacker/README.md | 41 | ||||
-rw-r--r-- | unpacker/src/main.rs | 124 |
3 files changed, 0 insertions, 174 deletions
diff --git a/unpacker/Cargo.toml b/unpacker/Cargo.toml deleted file mode 100644 index adb64ec..0000000 --- a/unpacker/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "unpacker" -version = "0.1.1" -edition = "2021" - -[dependencies] -byteorder = "1.4.3" -serde = { version = "1.0.160", features = ["derive"] } -serde_json = "1.0.96" diff --git a/unpacker/README.md b/unpacker/README.md deleted file mode 100644 index 2c6be02..0000000 --- a/unpacker/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# NRes Game Resource Unpacker - -At the moment, this is a demonstration of the NRes game resource unpacking algorithm in action. -It unpacks 100% of the NRes game resources for the game "Parkan: Iron Strategy". -The unpacked resources can be packed again using the [packer](../packer) utility and replace the original game files. - -__Attention!__ -This is a test version of the utility. -It overwrites existing files without asking. - -## Building - -To build the tools, you need to run the following command in the root directory: - -```bash -cargo build --release -``` - -## Running - -You can run the utility with the following command: - -```bash -./target/release/unpacker /path/to/file.ex /path/to/output -``` - -- `/path/to/file.ex`: This is the file containing the game resources that will be unpacked. -- `/path/to/output`: This is the directory where the unpacked files will be placed. - -## How it Works - -The structure describing the packed game resources is not fully understood yet. -Therefore, the utility saves unpacked files in the format `file_name.file_index` because some files have the same name. - -Additionally, an `index.json` file is created, which is important for re-packing the files. -This file lists all the fields that game resources have in their packed form. -It is essential to preserve the file index for the game to function correctly, as the game engine looks for the necessary files by index. - -Files can be replaced and packed back using the [packer](../packer). -The newly obtained game resource files are correctly processed by the game engine. -For example, sounds and 3D models of warbots' weapons were successfully replaced. diff --git a/unpacker/src/main.rs b/unpacker/src/main.rs deleted file mode 100644 index 2a84688..0000000 --- a/unpacker/src/main.rs +++ /dev/null @@ -1,124 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write}; - -use byteorder::{ByteOrder, LittleEndian}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug)] -pub struct FileHeader { - pub size: u32, - pub total: u32, - pub type1: u32, - pub type2: u32, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ListElement { - pub extension: String, - pub index: u32, - pub name: String, - #[serde(skip_serializing)] - pub position: u32, - #[serde(skip_serializing)] - pub size: u32, - pub unknown0: u32, - pub unknown1: u32, - pub unknown2: u32, -} - -fn main() { - let args: Vec<String> = env::args().collect(); - - let input = &args[1]; - let output = &args[2]; - - unpack(String::from(input), String::from(output)); -} - -fn unpack(input: String, output: String) { - let file = File::open(input).unwrap(); - let metadata = file.metadata().unwrap(); - - let mut reader = BufReader::new(file); - let mut list: Vec<ListElement> = Vec::new(); - - // Считываем заголовок файла - let mut header_buffer = [0u8; 16]; - reader.seek(SeekFrom::Start(0)).unwrap(); - reader.read_exact(&mut header_buffer).unwrap(); - - let file_header = FileHeader { - size: LittleEndian::read_u32(&header_buffer[12..16]), - total: LittleEndian::read_u32(&header_buffer[8..12]), - type1: LittleEndian::read_u32(&header_buffer[0..4]), - type2: LittleEndian::read_u32(&header_buffer[4..8]), - }; - - if file_header.type1 != 1936020046 || file_header.type2 != 256 { - panic!("this isn't NRes file"); - } - - if metadata.len() != file_header.size as u64 { - panic!("incorrect size") - } - - // Считываем список файлов - let list_files_start_position = file_header.size - (file_header.total * 64); - let list_files_size = file_header.total * 64; - - let mut list_buffer = vec![0u8; list_files_size as usize]; - reader - .seek(SeekFrom::Start(list_files_start_position as u64)) - .unwrap(); - reader.read_exact(&mut list_buffer).unwrap(); - - if list_buffer.len() % 64 != 0 { - panic!("invalid files list") - } - - for i in 0..(list_buffer.len() / 64) { - let from = i * 64; - let to = (i * 64) + 64; - let chunk: &[u8] = &list_buffer[from..to]; - - let element_list = ListElement { - extension: String::from_utf8_lossy(&chunk[0..4]) - .trim_matches(char::from(0)) - .to_string(), - index: LittleEndian::read_u32(&chunk[60..64]), - name: String::from_utf8_lossy(&chunk[20..56]) - .trim_matches(char::from(0)) - .to_string(), - position: LittleEndian::read_u32(&chunk[56..60]), - size: LittleEndian::read_u32(&chunk[12..16]), - unknown0: LittleEndian::read_u32(&chunk[4..8]), - unknown1: LittleEndian::read_u32(&chunk[8..12]), - unknown2: LittleEndian::read_u32(&chunk[16..20]), - }; - - list.push(element_list) - } - - // Распаковываем файлы в директорию - for element in &list { - let path = format!("{}/{}.{}", output, element.name, element.index); - let mut file = File::create(path).unwrap(); - - let mut file_buffer = vec![0u8; element.size as usize]; - reader - .seek(SeekFrom::Start(element.position as u64)) - .unwrap(); - reader.read_exact(&mut file_buffer).unwrap(); - - file.write_all(&file_buffer).unwrap(); - file_buffer.clear(); - } - - // Выгрузка списка файлов в JSON - let path = format!("{}/{}", output, "index.json"); - let file = File::create(path).unwrap(); - let mut writer = BufWriter::new(file); - serde_json::to_writer_pretty(&mut writer, &list).unwrap(); - writer.flush().unwrap(); -} |