mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-07-08 01:31:53 +08:00
Add Musica Script (.sc) support
This commit is contained in:
@@ -57,7 +57,7 @@ zstd = { version = "0.13", optional = true }
|
|||||||
[features]
|
[features]
|
||||||
default = ["all-fmt", "image-jpg", "image-jxl", "image-webp", "audio-flac", "jieba"]
|
default = ["all-fmt", "image-jpg", "image-jxl", "image-webp", "audio-flac", "jieba"]
|
||||||
all-fmt = ["all-script", "all-img", "all-arc", "all-audio"]
|
all-fmt = ["all-script", "all-img", "all-arc", "all-audio"]
|
||||||
all-script = ["artemis", "artemis-panmimisoft", "bgi", "cat-system", "circus", "entis-gls", "escude", "ex-hibit", "favorite", "hexen-haus", "kirikiri", "silky", "softpal", "will-plus", "yaneurao", "yaneurao-itufuru"]
|
all-script = ["artemis", "artemis-panmimisoft", "bgi", "cat-system", "circus", "entis-gls", "escude", "ex-hibit", "favorite", "hexen-haus", "kirikiri", "musica", "silky", "softpal", "will-plus", "yaneurao", "yaneurao-itufuru"]
|
||||||
all-img = ["bgi-img", "cat-system-img", "circus-img", "emote-img", "hexen-haus-img", "kirikiri-img", "softpal-img", "will-plus-img"]
|
all-img = ["bgi-img", "cat-system-img", "circus-img", "emote-img", "hexen-haus-img", "kirikiri-img", "softpal-img", "will-plus-img"]
|
||||||
all-arc = ["artemis-arc", "bgi-arc", "cat-system-arc", "circus-arc", "escude-arc", "ex-hibit-arc", "hexen-haus-arc", "kirikiri-arc", "softpal-arc"]
|
all-arc = ["artemis-arc", "bgi-arc", "cat-system-arc", "circus-arc", "escude-arc", "ex-hibit-arc", "hexen-haus-arc", "kirikiri-arc", "softpal-arc"]
|
||||||
all-audio = ["bgi-audio", "circus-audio"]
|
all-audio = ["bgi-audio", "circus-audio"]
|
||||||
@@ -88,6 +88,7 @@ hexen-haus-img = ["hexen-haus", "image"]
|
|||||||
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
||||||
kirikiri-arc = ["kirikiri", "adler", "fastcdc", "flate2", "parse-size", "sha2", "xp3", "zstd"]
|
kirikiri-arc = ["kirikiri", "adler", "fastcdc", "flate2", "parse-size", "sha2", "xp3", "zstd"]
|
||||||
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
||||||
|
musica = []
|
||||||
silky = []
|
silky = []
|
||||||
softpal = ["int-enum"]
|
softpal = ["int-enum"]
|
||||||
softpal-arc = ["softpal"]
|
softpal-arc = ["softpal"]
|
||||||
|
|||||||
@@ -194,6 +194,10 @@ msg-tool create -t <script-type> <input> <output>
|
|||||||
| Image Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Create | Remarks |
|
| Image Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Create | Remarks |
|
||||||
|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|
|
||||||
| `kirikiri-tlg`/`kr-tlg` | `kirikiri-img` | Kirikiri TLG Image File (.tlg) | ✔️ | ✔️ | ❌ | ❌ | ✔️ | tlg6 is not supported when importing/creating image |
|
| `kirikiri-tlg`/`kr-tlg` | `kirikiri-img` | Kirikiri TLG Image File (.tlg) | ✔️ | ✔️ | ❌ | ❌ | ✔️ | tlg6 is not supported when importing/creating image |
|
||||||
|
### Musica
|
||||||
|
| Script Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Custom Export | Custom Import | Create | Remarks |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| `musica-sc` | `musica` | Musica Script File (.sc) | ✔️ | ✔️ | ❌ | ❌ | ❌ | ❌ | ❌ | |
|
||||||
### Silky Engine
|
### Silky Engine
|
||||||
| Script Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Custom Export | Custom Import | Create | Remarks |
|
| Script Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Custom Export | Custom Import | Create | Remarks |
|
||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ pub mod favorite;
|
|||||||
pub mod hexen_haus;
|
pub mod hexen_haus;
|
||||||
#[cfg(feature = "kirikiri")]
|
#[cfg(feature = "kirikiri")]
|
||||||
pub mod kirikiri;
|
pub mod kirikiri;
|
||||||
|
#[cfg(feature = "musica")]
|
||||||
|
pub mod musica;
|
||||||
#[cfg(feature = "silky")]
|
#[cfg(feature = "silky")]
|
||||||
pub mod silky;
|
pub mod silky;
|
||||||
#[cfg(feature = "softpal")]
|
#[cfg(feature = "softpal")]
|
||||||
@@ -156,6 +158,8 @@ lazy_static::lazy_static! {
|
|||||||
Box::new(artemis::txt::ArtemisTxtBuilder::new()),
|
Box::new(artemis::txt::ArtemisTxtBuilder::new()),
|
||||||
#[cfg(feature = "kirikiri-arc")]
|
#[cfg(feature = "kirikiri-arc")]
|
||||||
Box::new(kirikiri::archive::xp3::Xp3ArchiveBuilder::new()),
|
Box::new(kirikiri::archive::xp3::Xp3ArchiveBuilder::new()),
|
||||||
|
#[cfg(feature = "musica")]
|
||||||
|
Box::new(musica::sc::MusicaBuilder::new()),
|
||||||
];
|
];
|
||||||
/// A list of all script extensions.
|
/// A list of all script extensions.
|
||||||
pub static ref ALL_EXTS: Vec<String> =
|
pub static ref ALL_EXTS: Vec<String> =
|
||||||
|
|||||||
2
src/scripts/musica/mod.rs
Normal file
2
src/scripts/musica/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
//! Musica scripts
|
||||||
|
pub mod sc;
|
||||||
150
src/scripts/musica/sc.rs
Normal file
150
src/scripts/musica/sc.rs
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
//! Musica Script (.sc)
|
||||||
|
use crate::scripts::base::*;
|
||||||
|
use crate::types::*;
|
||||||
|
use crate::utils::encoding::*;
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Musica Script Builder
|
||||||
|
pub struct MusicaBuilder {}
|
||||||
|
|
||||||
|
impl MusicaBuilder {
|
||||||
|
/// Create a new MusicaBuilder
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MusicaBuilder {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptBuilder for MusicaBuilder {
|
||||||
|
fn default_encoding(&self) -> Encoding {
|
||||||
|
Encoding::Cp932
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_script(
|
||||||
|
&self,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
_filename: &str,
|
||||||
|
encoding: Encoding,
|
||||||
|
_archive_encoding: Encoding,
|
||||||
|
config: &ExtraConfig,
|
||||||
|
_archive: Option<&Box<dyn Script>>,
|
||||||
|
) -> Result<Box<dyn Script>> {
|
||||||
|
Ok(Box::new(MusicaScript::new(buf, encoding, config)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extensions(&self) -> &'static [&'static str] {
|
||||||
|
&["sc"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_type(&self) -> &'static ScriptType {
|
||||||
|
&ScriptType::Musica
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MusicaScript {
|
||||||
|
lines: Vec<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicaScript {
|
||||||
|
pub fn new(buf: Vec<u8>, encoding: Encoding, _config: &ExtraConfig) -> Result<Self> {
|
||||||
|
let decoded = decode_to_string(encoding, &buf, true)?;
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
for line in decoded.lines() {
|
||||||
|
let parts: Vec<String> = line.split(' ').map(|s| s.to_string()).collect();
|
||||||
|
lines.push(parts);
|
||||||
|
}
|
||||||
|
Ok(MusicaScript { lines })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script for MusicaScript {
|
||||||
|
fn default_output_script_type(&self) -> OutputScriptType {
|
||||||
|
OutputScriptType::Json
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_format_type(&self) -> FormatOptions {
|
||||||
|
FormatOptions::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||||
|
let mut messages = Vec::new();
|
||||||
|
for parts in &self.lines {
|
||||||
|
if parts.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// .message <id> <voice> <name> <text>
|
||||||
|
if parts[0] == ".message" && parts.len() >= 5 {
|
||||||
|
let name = parts[3].clone();
|
||||||
|
let text = parts[4].clone();
|
||||||
|
let message = Message {
|
||||||
|
name: if name.is_empty() { None } else { Some(name) },
|
||||||
|
message: text,
|
||||||
|
};
|
||||||
|
messages.push(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_messages<'a>(
|
||||||
|
&'a self,
|
||||||
|
messages: Vec<Message>,
|
||||||
|
file: Box<dyn WriteSeek + 'a>,
|
||||||
|
_filename: &str,
|
||||||
|
encoding: Encoding,
|
||||||
|
replacement: Option<&'a ReplacementTable>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut writer = std::io::BufWriter::new(file);
|
||||||
|
let mut mes = messages.iter();
|
||||||
|
let mut me = mes.next();
|
||||||
|
for parts in &self.lines {
|
||||||
|
let mut parts = parts.clone();
|
||||||
|
if parts.is_empty() {
|
||||||
|
writeln!(writer)?;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if parts[0] == ".message" && parts.len() >= 5 {
|
||||||
|
let m = match me {
|
||||||
|
Some(m) => m,
|
||||||
|
None => return Err(anyhow::anyhow!("Not enough messages to import.")),
|
||||||
|
};
|
||||||
|
if !parts[3].is_empty() {
|
||||||
|
let mut name = match &m.name {
|
||||||
|
Some(n) => n.clone(),
|
||||||
|
None => {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"Message name is missing for message: {}",
|
||||||
|
m.message
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(repl) = replacement {
|
||||||
|
for (k, v) in &repl.map {
|
||||||
|
name = name.replace(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts[3] = name.replace(' ', "\u{3000}");
|
||||||
|
}
|
||||||
|
let mut text = m.message.clone();
|
||||||
|
if let Some(repl) = replacement {
|
||||||
|
for (k, v) in &repl.map {
|
||||||
|
text = text.replace(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts[4] = text.replace(' ', "\u{3000}");
|
||||||
|
me = mes.next();
|
||||||
|
}
|
||||||
|
let line = parts.join(" ");
|
||||||
|
let d = encode_string(encoding, &line, false)?;
|
||||||
|
writer.write_all(&d)?;
|
||||||
|
writeln!(writer)?;
|
||||||
|
}
|
||||||
|
if me.is_some() || mes.next().is_some() {
|
||||||
|
return Err(anyhow::anyhow!("Too many messages to import."));
|
||||||
|
}
|
||||||
|
writer.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -680,6 +680,9 @@ pub enum ScriptType {
|
|||||||
#[value(alias("kr-tjs-ns0"))]
|
#[value(alias("kr-tjs-ns0"))]
|
||||||
/// Kirikiri TJS NS0 binary encoded script
|
/// Kirikiri TJS NS0 binary encoded script
|
||||||
KirikiriTjsNs0,
|
KirikiriTjsNs0,
|
||||||
|
#[cfg(feature = "musica")]
|
||||||
|
/// Musica Script (.sc)
|
||||||
|
Musica,
|
||||||
#[cfg(feature = "silky")]
|
#[cfg(feature = "silky")]
|
||||||
/// Silky Engine Mes script
|
/// Silky Engine Mes script
|
||||||
Silky,
|
Silky,
|
||||||
|
|||||||
Reference in New Issue
Block a user