From 7b3b85248365ff084792a08e30635ac0e541050a Mon Sep 17 00:00:00 2001 From: lifegpc Date: Thu, 28 Aug 2025 20:35:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(artemis):=20add=20support=20for=20?= =?UTF-8?q?=E3=81=B1=E3=82=93=E3=81=BF=E3=81=BF=E3=81=9D=E3=81=B5=E3=81=A8?= =?UTF-8?q?=20TXT=20scripts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Updated main.rs to include new configuration options for artemis-panmimisoft. - Modified asb.rs to handle both .asb and .iet file extensions. - Introduced new module for panmimisoft scripts and implemented TxtBuilder for parsing. - Enhanced the parser to support new tag structures and attributes specific to ぱんみみそふと scripts. - Updated types.rs to reflect changes in configuration options and script types. - Adjusted mod.rs to register the new TxtBuilder for panmimisoft. --- Cargo.lock | 109 ++++++++++++++++++- Cargo.toml | 4 +- README.md | 4 +- src/args.rs | 39 +++++-- src/main.rs | 12 +- src/scripts/artemis/asb.rs | 33 ++++-- src/scripts/artemis/mod.rs | 3 +- src/scripts/artemis/panmimisoft/mod.rs | 2 + src/scripts/artemis/{ => panmimisoft}/txt.rs | 43 ++++---- src/scripts/mod.rs | 4 +- src/types.rs | 18 +-- 11 files changed, 210 insertions(+), 61 deletions(-) create mode 100644 src/scripts/artemis/panmimisoft/mod.rs rename src/scripts/artemis/{ => panmimisoft}/txt.rs (97%) diff --git a/Cargo.lock b/Cargo.lock index 668e54e..7af12e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,6 +217,26 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -235,6 +255,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -312,6 +338,15 @@ dependencies = [ "syn", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dunce" version = "1.0.5" @@ -467,6 +502,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -476,7 +522,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -485,6 +531,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.5" @@ -622,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.5", ] [[package]] @@ -664,7 +716,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom", + "getrandom 0.3.3", "libc", ] @@ -836,6 +888,7 @@ dependencies = [ "pelite", "png", "rand 0.9.2", + "rust-ini", "serde", "serde_json", "serde_yaml_ng", @@ -901,12 +954,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "once_cell_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + [[package]] name = "overf" version = "0.1.2" @@ -1124,7 +1193,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.3", ] [[package]] @@ -1162,6 +1231,17 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "rust-ini" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" +dependencies = [ + "cfg-if", + "ordered-multimap", + "trim-in-place", +] + [[package]] name = "ryu" version = "1.0.20" @@ -1324,6 +1404,15 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -1334,6 +1423,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "trim-in-place" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" + [[package]] name = "typenum" version = "1.18.0" @@ -1402,6 +1497,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasi" version = "0.14.2+wasi-0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 127d9c0..916eb0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ overf = "0.1" pelite = { version = "0.10", optional = true } png = { version = "0.17", optional = true } rand = { version = "0.9", optional = true } +rust-ini = { version = "0.21", optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml_ng = "0.10" @@ -45,11 +46,12 @@ zstd = { version = "0.13", optional = true } [features] default = ["all-fmt", "image-jpg", "image-webp"] all-fmt = ["all-script", "all-img", "all-arc", "all-audio"] -all-script = ["artemis", "bgi", "cat-system", "circus", "entis-gls", "escude", "ex-hibit", "hexen-haus", "kirikiri", "softpal", "will-plus", "yaneurao", "yaneurao-itufuru"] +all-script = ["artemis", "artemis-panmimisoft", "bgi", "cat-system", "circus", "entis-gls", "escude", "ex-hibit", "hexen-haus", "kirikiri", "softpal", "will-plus", "yaneurao", "yaneurao-itufuru"] all-img = ["bgi-img", "cat-system-img", "circus-img", "emote-img", "kirikiri-img"] all-arc = ["artemis-arc", "bgi-arc", "cat-system-arc", "circus-arc", "escude-arc"] all-audio = ["bgi-audio", "circus-audio"] artemis = ["utils-escape"] +artemis-panmimisoft = ["artemis", "rust-ini"] artemis-arc = ["artemis", "msg_tool_macro/artemis-arc", "sha1"] bgi = ["fancy-regex"] bgi-arc = ["bgi", "rand", "utils-bit-stream"] diff --git a/README.md b/README.md index c97a511..6d86589 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,8 @@ msg-tool create -t | Script Type | Feature Name | Name | Export | Import | Custom Export | Custom Import | Create | Remarks | |---|---|---|---|---|---|---|---|---| | `artemis` | `artemis` | Artemis Engine AST file (.ast) | ✔️ | ✔️ | ❌ | ❌ | ❌ | | -| `artemis-asb` | `artemis` | Artemis Engine ASB file (.asb) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | | -| `artemis-txt` | `artemis` | Artemis Engine TXT file (.txt) | ✔️ | ✔️ | ❌ | ❌ | ❌ | | +| `artemis-asb` | `artemis` | Artemis Engine ASB file (.asb/.iet) | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | For `.iet` files, only custom export/import and create features are supported. | +| `artemis-panmimisoft-txt` | `artemis-panmimisoft` | Artemis Engine TXT ([ぱんみみそふと](https://pannomimi.net/panmimisoft)) file (.txt) | ✔️ | ✔️ | ❌ | ❌ | ❌ | | | Archive Type | Feature Name | Name | Unpack | Pack | Remarks | |---|---|---|---|---|---| diff --git a/src/args.rs b/src/args.rs index db429ce..7df9301 100644 --- a/src/args.rs +++ b/src/args.rs @@ -240,21 +240,26 @@ pub struct Arg { /// Specify the language of Artemis AST script. /// If not specified, the first language will be used. pub artemis_ast_lang: Option, - #[cfg(feature = "artemis")] + // Default value is from tagFilters in macro.iet + #[cfg(feature = "artemis-panmimisoft")] #[arg( long, global = true, value_delimiter = ',', - default_value = "遅延イベントCG,遅延背景,bgv_in,イベントCG,遅延ポップアップ" + default_value = "背景,イベントCG,遅延背景,遅延背景予約,背景予約,遅延イベントCG,遅延イベントCG予約,イベントCG予約,遅延ポップアップ,遅延bgm_in,遅延bgm_out,遅延se_in,遅延se_out,遅延bgs_in,遅延bgs_out,立ち絵face非連動,セーブサムネイル置換終了,シネスコ" )] /// Artemis Engine blacklist tag names for TXT script. - /// This is used to ignore these tags when finding names in Artemis TXT script. - pub artemis_txt_blacklist_names: Vec, - #[cfg(feature = "artemis")] + /// This is used to ignore these tags when finding names in Artemis TXT script (ぱんみみそふと). + pub artemis_panmimisoft_txt_blacklist_names: Vec, + #[cfg(feature = "artemis-panmimisoft")] #[arg(long, global = true)] - /// Specify the language of Artemis TXT script. + /// Specify the language of Artemis TXT (ぱんみみそふと) script. /// If not specified, the first language will be used. - pub artemis_txt_lang: Option, + pub artemis_panmimisoft_txt_lang: Option, + #[cfg(feature = "artemis-panmimisoft")] + #[arg(long, global = true)] + /// The path to the tag.ini file, which contains the tags to be ignored when finding names in Artemis TXT script (ぱんみみそふと). + pub artemis_panmimisoft_txt_tag_ini: Option, #[cfg(feature = "cat-system")] #[arg(long, global = true)] /// CatSystem2 CSTL script language, used to extract messages from CSTL script. @@ -505,3 +510,23 @@ pub fn get_cat_system_int_encrypt_password(arg: &Arg) -> anyhow::Result anyhow::Result> { + match &arg.artemis_panmimisoft_txt_tag_ini { + Some(path) => { + let mut set = crate::scripts::artemis::panmimisoft::txt::read_tags_from_ini(path)?; + for name in &arg.artemis_panmimisoft_txt_blacklist_names { + set.insert(name.clone()); + } + Ok(set) + } + None => Ok(arg + .artemis_panmimisoft_txt_blacklist_names + .iter() + .cloned() + .collect()), + } +} diff --git a/src/main.rs b/src/main.rs index 2a35dd6..71b684a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1765,12 +1765,12 @@ fn main() { entis_gls_srcxml_lang: arg.entis_gls_srcxml_lang.clone(), #[cfg(feature = "will-plus")] will_plus_ws2_no_disasm: arg.will_plus_ws2_no_disasm, - #[cfg(feature = "artemis")] - artemis_txt_blacklist_names: std::sync::Arc::new(std::collections::HashSet::from_iter( - arg.artemis_txt_blacklist_names.iter().cloned(), - )), - #[cfg(feature = "artemis")] - artemis_txt_lang: arg.artemis_txt_lang.clone(), + #[cfg(feature = "artemis-panmimisoft")] + artemis_panmimisoft_txt_blacklist_names: std::sync::Arc::new( + args::get_artemis_panmimisoft_txt_blacklist_names(&arg).unwrap(), + ), + #[cfg(feature = "artemis-panmimisoft")] + artemis_panmimisoft_txt_lang: arg.artemis_panmimisoft_txt_lang.clone(), }; match &arg.command { args::Command::Export { input, output } => { diff --git a/src/scripts/artemis/asb.rs b/src/scripts/artemis/asb.rs index 2cea01e..6275b93 100644 --- a/src/scripts/artemis/asb.rs +++ b/src/scripts/artemis/asb.rs @@ -1,4 +1,4 @@ -//! Artemis Engine ASB file (.asb) +//! Artemis Engine ASB file (.asb/.iet) use crate::ext::io::*; use crate::scripts::base::*; use crate::types::*; @@ -30,17 +30,17 @@ impl ScriptBuilder for ArtemisAsbBuilder { fn build_script( &self, buf: Vec, - _filename: &str, + filename: &str, encoding: Encoding, _archive_encoding: Encoding, config: &ExtraConfig, _archive: Option<&Box>, ) -> Result> { - Ok(Box::new(Asb::new(buf, encoding, config)?)) + Ok(Box::new(Asb::new(buf, encoding, config, filename)?)) } fn extensions(&self) -> &'static [&'static str] { - &["asb"] + &["asb", "iet"] } fn script_type(&self) -> &'static ScriptType { @@ -421,6 +421,7 @@ impl<'a> TextParser<'a> { pub struct Asb { items: Vec, custom_yaml: bool, + is_iet: bool, } impl Asb { @@ -429,7 +430,12 @@ impl Asb { /// * `buf` - The buffer containing the ASB data. /// * `encoding` - The encoding used for the ASB data. /// * `config` - Extra configuration options. - pub fn new(buf: Vec, encoding: Encoding, config: &ExtraConfig) -> Result { + pub fn new( + buf: Vec, + encoding: Encoding, + config: &ExtraConfig, + filename: &str, + ) -> Result { let mut data = MemReader::new(buf); let mut magic = [0; 5]; data.read_exact(&mut magic)?; @@ -444,17 +450,28 @@ impl Asb { Ok(Asb { items, custom_yaml: config.custom_yaml, + is_iet: std::path::Path::new(filename) + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("iet")), }) } } impl Script for Asb { fn default_output_script_type(&self) -> OutputScriptType { - OutputScriptType::Json + if self.is_iet { + OutputScriptType::Custom + } else { + OutputScriptType::Json + } } - fn is_output_supported(&self, _: OutputScriptType) -> bool { - true + fn is_output_supported(&self, out: OutputScriptType) -> bool { + if self.is_iet { + matches!(out, OutputScriptType::Custom) + } else { + true + } } fn default_format_type(&self) -> FormatOptions { diff --git a/src/scripts/artemis/mod.rs b/src/scripts/artemis/mod.rs index b6dd4ed..ed3cb77 100644 --- a/src/scripts/artemis/mod.rs +++ b/src/scripts/artemis/mod.rs @@ -3,4 +3,5 @@ pub mod archive; pub mod asb; pub mod ast; -pub mod txt; +#[cfg(feature = "artemis-panmimisoft")] +pub mod panmimisoft; diff --git a/src/scripts/artemis/panmimisoft/mod.rs b/src/scripts/artemis/panmimisoft/mod.rs new file mode 100644 index 0000000..42790ed --- /dev/null +++ b/src/scripts/artemis/panmimisoft/mod.rs @@ -0,0 +1,2 @@ +//! Special parsers for [ぱんみみそふと](https://pannomimi.net/panmimisoft) games using the Artemis Engine. +pub mod txt; diff --git a/src/scripts/artemis/txt.rs b/src/scripts/artemis/panmimisoft/txt.rs similarity index 97% rename from src/scripts/artemis/txt.rs rename to src/scripts/artemis/panmimisoft/txt.rs index 8998aeb..4fe590c 100644 --- a/src/scripts/artemis/txt.rs +++ b/src/scripts/artemis/panmimisoft/txt.rs @@ -41,7 +41,7 @@ impl ScriptBuilder for TxtBuilder { } fn script_type(&self) -> &'static ScriptType { - &ScriptType::ArtemisTxt + &ScriptType::ArtemisPanmimisoftTxt } } @@ -138,7 +138,7 @@ impl TagNode { /// Returns true if the tag is not suitable for name. pub fn is_blocked_name(&self, set: &HashSet) -> bool { - set.contains(&self.name) + self.name.is_ascii() || set.contains(&self.name) } /// Checks if the tag has a specific attribute. @@ -814,8 +814,8 @@ impl TxtScript { let tree = parser.parse(true)?; Ok(Self { tree, - blacklist_names: config.artemis_txt_blacklist_names.clone(), - lang: config.artemis_txt_lang.clone(), + blacklist_names: config.artemis_panmimisoft_txt_blacklist_names.clone(), + lang: config.artemis_panmimisoft_txt_lang.clone(), }) } } @@ -873,23 +873,13 @@ impl Script for TxtScript { let mes = message.to_xml(); message.clear(); if !mes.is_empty() { - let name = if mes.starts_with("「") { - match &last_tag_block { - Some(block) => { - Some(if let Some(name) = block.get_attr("name") { - name.to_string() - } else { - block.name.clone() - }) - } - _ => { - eprintln!("Warn: Name block not found."); - crate::COUNTER.inc_warning(); - None - } - } - } else { - None + let name = match &last_tag_block { + Some(block) => Some(if let Some(name) = block.get_attr("name") { + name.to_string() + } else { + block.name.clone() + }), + _ => None, }; messages.push(Message { name, message: mes }); } @@ -1177,6 +1167,17 @@ impl Script for TxtScript { } } +/// Reads tags list from tag.ini file. +pub fn read_tags_from_ini>(path: P) -> Result> { + let conf = ini::Ini::load_from_file(path)?; + let set = HashSet::from_iter(conf.sections().flat_map(|s| s.map(|s| s.to_string()))); + eprintln!( + "Read tags from ini: {}", + set.iter().map(|s| s.as_str()).collect::>().join(",") + ); + Ok(set) +} + #[test] fn test_xml_parser() { let data = "测试文本\nok测试"; diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index cafa589..44eebab 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -112,8 +112,8 @@ lazy_static::lazy_static! { Box::new(entis_gls::srcxml::SrcXmlScriptBuilder::new()), #[cfg(feature = "softpal")] Box::new(softpal::scr::SoftpalScriptBuilder::new()), - #[cfg(feature = "artemis")] - Box::new(artemis::txt::TxtBuilder::new()), + #[cfg(feature = "artemis-panmimisoft")] + Box::new(artemis::panmimisoft::txt::TxtBuilder::new()), ]; /// A list of all script extensions. pub static ref ALL_EXTS: Vec = diff --git a/src/types.rs b/src/types.rs index 386ef1b..d70f3b2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -344,14 +344,14 @@ pub struct ExtraConfig { /// Use another parser to parse the script. /// Should only be used when the default parser not works well. pub will_plus_ws2_no_disasm: bool, - #[cfg(feature = "artemis")] + #[cfg(feature = "artemis-panmimisoft")] /// Artemis Engine blacklist tag names for TXT script. - /// This is used to ignore these tags when finding names in Artemis TXT script. - pub artemis_txt_blacklist_names: std::sync::Arc>, - #[cfg(feature = "artemis")] - /// Specify the language of Artemis TXT script. + /// This is used to ignore these tags when finding names in Artemis TXT (ぱんみみそふと) script. + pub artemis_panmimisoft_txt_blacklist_names: std::sync::Arc>, + #[cfg(feature = "artemis-panmimisoft")] + /// Specify the language of Artemis TXT (ぱんみみそふと) script. /// If not specified, the first language will be used. - pub artemis_txt_lang: Option, + pub artemis_panmimisoft_txt_lang: Option, } #[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)] @@ -363,9 +363,9 @@ pub enum ScriptType { #[cfg(feature = "artemis")] /// Artemis Engine ASB script ArtemisAsb, - #[cfg(feature = "artemis")] - /// Artemis Engine TXT script - ArtemisTxt, + #[cfg(feature = "artemis-panmimisoft")] + /// Artemis Engine TXT (ぱんみみそふと) script + ArtemisPanmimisoftTxt, #[cfg(feature = "artemis-arc")] #[value(alias("pfs"))] /// Artemis archive (pfs)