fix: use the worst hack to correct a TexTools mistake
This commit is contained in:
parent
05a704df75
commit
af175a6509
|
@ -11,6 +11,7 @@ flate2 = "1"
|
|||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
sha3 = "0.10"
|
||||
tempfile = "3"
|
||||
thiserror = "1"
|
||||
zip = { version = "0.6", default-features = false, features = ["deflate"] }
|
||||
sqpack = { git = "https://git.anna.lgbt/ascclemens/sqpack-rs", features = ["read", "write"] }
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
|||
|
||||
use flate2::read::DeflateDecoder;
|
||||
use sqpack::{DatBlockHeader, DatStdFileBlockInfos, FileKind, LodBlock, ModelBlock, SqPackFileInfo, SqPackFileInfoHeader};
|
||||
use sqpack::binrw::{BinRead, BinWriterExt, VecArgs};
|
||||
use sqpack::binrw::{BinRead, BinReaderExt, BinWriterExt, VecArgs};
|
||||
use zip::ZipArchive;
|
||||
|
||||
use crate::Error;
|
||||
|
@ -15,10 +15,10 @@ use crate::tracking_reader::TrackingReader;
|
|||
use crate::util::{MAX_MODEL_LODS, read_struct};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait WriteSeek: Write + Seek {}
|
||||
pub trait WriteSeek: Write + Seek + Read {}
|
||||
|
||||
impl<T> WriteSeek for T
|
||||
where T: Write + Seek {}
|
||||
where T: Write + Seek + Read {}
|
||||
|
||||
pub struct TtmpExtractor<R> {
|
||||
manifest: ManifestKind,
|
||||
|
@ -128,7 +128,7 @@ impl<R: Read + Seek> TtmpExtractor<R> {
|
|||
}
|
||||
|
||||
impl<R: Read> TtmpExtractor<R> {
|
||||
pub fn extract_one_into<W: Write + Seek>(mod_file: &ModFile, mut reader: R, mut writer: W) -> Result<()> {
|
||||
pub fn extract_one_into<W: Read + Write + Seek>(mod_file: &ModFile, mut reader: R, mut writer: W) -> Result<()> {
|
||||
let mut reader = TrackingReader::new(&mut reader);
|
||||
let mut buf = [0; 4096];
|
||||
let file = mod_file.file;
|
||||
|
@ -175,7 +175,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_model_file<T: Read, W: Write + Seek>(info: &SqPackFileInfoHeader, mut reader: T, mut writer: W, buf: &mut [u8]) -> Result<()> {
|
||||
fn extract_model_file<T: Read, W: Read + Write + Seek>(info: &SqPackFileInfoHeader, mut reader: T, mut writer: W, buf: &mut [u8]) -> Result<()> {
|
||||
let model_info: ModelBlock = read_struct(&mut reader, buf)?;
|
||||
|
||||
let block_counts = &model_info.block_num;
|
||||
|
@ -192,7 +192,10 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
- std::mem::size_of::<u16>() * total_blocks as usize;
|
||||
Self::skip(&mut reader, buf, skip_amt)?;
|
||||
|
||||
writer.seek(SeekFrom::Start(0x44)).map_err(Error::Io)?;
|
||||
// we need to modify the mdl file because tt sucks ass, so write into
|
||||
// a temp file first, then copy into the real writer
|
||||
let mut temp = tempfile::tempfile().map_err(Error::Io)?;
|
||||
temp.seek(SeekFrom::Start(0x44)).map_err(Error::Io)?;
|
||||
|
||||
let stack_size = Self::read_blocks_into(
|
||||
model_info.block_num.stack,
|
||||
|
@ -200,7 +203,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
model_info.offset.stack,
|
||||
&block_sizes,
|
||||
&mut reader,
|
||||
&mut writer,
|
||||
&mut temp,
|
||||
buf,
|
||||
)?;
|
||||
|
||||
|
@ -210,7 +213,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
model_info.offset.runtime,
|
||||
&block_sizes,
|
||||
&mut reader,
|
||||
&mut writer,
|
||||
&mut temp,
|
||||
buf,
|
||||
)?;
|
||||
|
||||
|
@ -225,7 +228,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
let block_count = model_info.block_num.vertex_buffer[lod_index];
|
||||
if block_count != 0 {
|
||||
if lod_index == 0 || block_count > 0 {
|
||||
vertex_data_offsets[lod_index] = writer.stream_position().map_err(Error::Io)? as u32;
|
||||
vertex_data_offsets[lod_index] = temp.stream_position().map_err(Error::Io)? as u32;
|
||||
}
|
||||
|
||||
vertex_buffer_sizes[lod_index] = Self::read_blocks_into(
|
||||
|
@ -234,7 +237,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
model_info.offset.vertex_buffer[lod_index],
|
||||
&block_sizes,
|
||||
&mut reader,
|
||||
&mut writer,
|
||||
&mut temp,
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
|
@ -248,7 +251,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
model_info.offset.edge_geometry_vertex_buffer[lod_index],
|
||||
&block_sizes,
|
||||
&mut reader,
|
||||
&mut writer,
|
||||
&mut temp,
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
|
@ -257,7 +260,7 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
let block_count = model_info.block_num.index_buffer[lod_index];
|
||||
if block_count != 0 {
|
||||
if lod_index == 0 || block_count > 0 {
|
||||
index_data_offsets[lod_index] = writer.stream_position().map_err(Error::Io)? as u32;
|
||||
index_data_offsets[lod_index] = temp.stream_position().map_err(Error::Io)? as u32;
|
||||
}
|
||||
|
||||
index_buffer_sizes[lod_index] = Self::read_blocks_into(
|
||||
|
@ -266,27 +269,44 @@ impl<R: Read> TtmpExtractor<R> {
|
|||
model_info.offset.index_buffer[lod_index],
|
||||
&block_sizes,
|
||||
&mut reader,
|
||||
&mut writer,
|
||||
&mut temp,
|
||||
buf,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the header now we've collected the info for it.
|
||||
writer.seek(SeekFrom::Start(0)).map_err(Error::Io)?;
|
||||
writer.write_le(&model_info.version).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&stack_size).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&runtime_size).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&model_info.vertex_declaration_num).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&model_info.material_num).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&vertex_data_offsets).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&index_data_offsets).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&vertex_buffer_sizes).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&index_buffer_sizes).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&model_info.num_lods).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&model_info.index_buffer_streaming_enabled).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&model_info.edge_geometry_enabled).map_err(Error::BinRwWrite)?;
|
||||
writer.write_le(&0u8).map_err(Error::BinRwWrite)?;
|
||||
temp.seek(SeekFrom::Start(0)).map_err(Error::Io)?;
|
||||
temp.write_le(&model_info.version).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&stack_size).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&runtime_size).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&model_info.vertex_declaration_num).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&model_info.material_num).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&vertex_data_offsets).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&index_data_offsets).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&vertex_buffer_sizes).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&index_buffer_sizes).map_err(Error::BinRwWrite)?;
|
||||
// apparently textools only writes one lod, though the header says three
|
||||
// temp.write_le(&model_info.num_lods).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&1u8).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&model_info.index_buffer_streaming_enabled).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&model_info.edge_geometry_enabled).map_err(Error::BinRwWrite)?;
|
||||
temp.write_le(&0u8).map_err(Error::BinRwWrite)?;
|
||||
|
||||
// fix textools lod number being wrong
|
||||
let strings_length_offset = 0x44 + stack_size as u64 + 4;
|
||||
temp.seek(SeekFrom::Start(strings_length_offset)).map_err(Error::Io)?;
|
||||
let strings_length: u32 = temp.read_le().map_err(Error::BinRwRead)?;
|
||||
let lod_offset = strings_length_offset + strings_length as u64 + 4 + 22;
|
||||
temp.rewind().map_err(Error::Io)?;
|
||||
|
||||
// copy bytes up to the offset
|
||||
std::io::copy(&mut (&mut temp).take(lod_offset), &mut writer).map_err(Error::Io)?;
|
||||
// write 1 lod
|
||||
writer.write_le(&1u8).map_err(Error::BinRwWrite)?;
|
||||
temp.seek(SeekFrom::Current(1)).map_err(Error::Io)?;
|
||||
// copy bytes after the offset
|
||||
std::io::copy(&mut temp, &mut writer).map_err(Error::Io)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue