From 03a9e52dbcbda35f8e3a2ae9d64aec39fcdaeb94 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 12 Oct 2025 16:51:14 +0800 Subject: [PATCH] add multiple pack support for xp3 --- src/args.rs | 10 ++++++ src/main.rs | 2 ++ .../kirikiri/archive/xp3pack/segmenter.rs | 6 ++++ .../kirikiri/archive/xp3pack/writer.rs | 36 ++++++++++++------- src/types.rs | 5 +++ 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/args.rs b/src/args.rs index f7e6a41..98b2c59 100644 --- a/src/args.rs +++ b/src/args.rs @@ -515,6 +515,16 @@ pub struct Arg { #[arg(long, global = true)] /// Use zstd compression for files in Kirikiri XP3 archive when creating. (Warning: Kirikiri engine don't support this. Hook is required.) pub xp3_zstd: bool, + #[cfg(feature = "kirikiri-arc")] + #[arg( + long, + global = true, + default_value_t = 1, + visible_alias = "xp3-pack-jobs" + )] + /// Workers count for packing file in Kirikiri XP3 archive in parallel. + /// This not works when segment is disabled. + pub xp3_pack_workers: usize, #[command(subcommand)] /// Command pub command: Command, diff --git a/src/main.rs b/src/main.rs index 406bbc2..4f94735 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2759,6 +2759,8 @@ fn main() { xp3_compress_workers: arg.xp3_compress_workers, #[cfg(feature = "kirikiri-arc")] xp3_zstd: arg.xp3_zstd, + #[cfg(feature = "kirikiri-arc")] + xp3_pack_workers: arg.xp3_pack_workers, }); match &arg.command { args::Command::Export { input, output } => { diff --git a/src/scripts/kirikiri/archive/xp3pack/segmenter.rs b/src/scripts/kirikiri/archive/xp3pack/segmenter.rs index b719a2f..b623144 100644 --- a/src/scripts/kirikiri/archive/xp3pack/segmenter.rs +++ b/src/scripts/kirikiri/archive/xp3pack/segmenter.rs @@ -28,6 +28,12 @@ impl Default for SegmenterConfig { } } +impl SegmenterConfig { + pub fn is_none(&self) -> bool { + matches!(self, SegmenterConfig::None) + } +} + /// A trait for strategies that split a byte slice into one or more segments. pub trait Segmenter { fn segment<'a>( diff --git a/src/scripts/kirikiri/archive/xp3pack/writer.rs b/src/scripts/kirikiri/archive/xp3pack/writer.rs index c182a17..fbf04d1 100644 --- a/src/scripts/kirikiri/archive/xp3pack/writer.rs +++ b/src/scripts/kirikiri/archive/xp3pack/writer.rs @@ -71,7 +71,7 @@ pub struct Xp3ArchiveWriter { zlib_compression_level: u32, segmenter: Option>>, stats: Arc, - compress_workers: Option>>>, + compress_workers: usize, processing_segments: Arc>>, use_zstd: bool, zstd_compression_level: i32, @@ -99,21 +99,21 @@ impl Xp3ArchiveWriter> { file: Arc::new(Mutex::new(file)), segments: Arc::new(Mutex::new(HashMap::new())), items: Arc::new(Mutex::new(items)), - runner: ThreadPool::new(1, Some("xp3-writer"), false)?, + runner: ThreadPool::new( + if config.xp3_segmenter.is_none() { + 1 + } else { + config.xp3_pack_workers.max(1) + }, + Some("xp3-writer"), + false, + )?, compress_files: config.xp3_compress_files, compress_index: config.xp3_compress_index, zlib_compression_level: config.zlib_compression_level, segmenter, stats: Arc::new(Stats::default()), - compress_workers: if config.xp3_compress_files { - Some(Arc::new(ThreadPool::new( - config.xp3_compress_workers.max(1), - Some("xp3-compress"), - false, - )?)) - } else { - None - }, + compress_workers: config.xp3_compress_workers.max(1), processing_segments: Arc::new(Mutex::new(HashSet::new())), use_zstd: config.xp3_zstd, zstd_compression_level: config.zstd_compression_level, @@ -173,7 +173,9 @@ impl Archive for Xp3ArchiveWriter { } fn new_file_non_seek<'a>(&'a mut self, name: &str) -> Result> { - self.runner.join(); + if self.segmenter.is_none() { + self.runner.join(); + } for err in self.runner.take_results() { err?; } @@ -196,7 +198,15 @@ impl Archive for Xp3ArchiveWriter { let stats = self.stats.clone(); let is_compressed = self.compress_files; let zlib_compression_level = self.zlib_compression_level; - let workers = self.compress_workers.clone(); + let workers = if self.segmenter.is_some() { + Some(Arc::new(ThreadPool::>::new( + self.compress_workers, + Some("xp3-compress"), + false, + )?)) + } else { + None + }; let processiong_segments = self.processing_segments.clone(); let use_zstd = self.use_zstd; let zstd_compression_level = self.zstd_compression_level; diff --git a/src/types.rs b/src/types.rs index 0de026d..005d836 100644 --- a/src/types.rs +++ b/src/types.rs @@ -498,6 +498,11 @@ pub struct ExtraConfig { #[cfg(feature = "kirikiri-arc")] /// Use zstd compression for files in Kirikiri XP3 archive when creating. (Warning: Kirikiri engine don't support this. Hook is required.) pub xp3_zstd: bool, + #[cfg(feature = "kirikiri-arc")] + #[default(1)] + /// Workers count for packing file in Kirikiri XP3 archive in parallel. Default is 1. + /// This not works when segment is disabled. + pub xp3_pack_workers: usize, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]