mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-22 20:04:20 +08:00
Add kirikiri Scn script support
This commit is contained in:
100
Cargo.lock
generated
100
Cargo.lock
generated
@@ -2,6 +2,12 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -193,6 +199,90 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "emote-psb"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5726783feee87f0effb3e756f3f88e01594be4b47ebd742c70393f20692fb03"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
"byteorder",
|
||||||
|
"encoding",
|
||||||
|
"flate2",
|
||||||
|
"itertools",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding"
|
||||||
|
version = "0.2.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
|
||||||
|
dependencies = [
|
||||||
|
"encoding-index-japanese",
|
||||||
|
"encoding-index-korean",
|
||||||
|
"encoding-index-simpchinese",
|
||||||
|
"encoding-index-singlebyte",
|
||||||
|
"encoding-index-tradchinese",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding-index-japanese"
|
||||||
|
version = "1.20141219.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_index_tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding-index-korean"
|
||||||
|
version = "1.20141219.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_index_tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding-index-simpchinese"
|
||||||
|
version = "1.20141219.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_index_tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding-index-singlebyte"
|
||||||
|
version = "1.20141219.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_index_tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding-index-tradchinese"
|
||||||
|
version = "1.20141219.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_index_tests",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_index_tests"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.35"
|
version = "0.8.35"
|
||||||
@@ -276,6 +366,15 @@ version = "1.70.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.15"
|
version = "1.0.15"
|
||||||
@@ -318,6 +417,7 @@ dependencies = [
|
|||||||
"blowfish",
|
"blowfish",
|
||||||
"clap",
|
"clap",
|
||||||
"csv",
|
"csv",
|
||||||
|
"emote-psb",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"flate2",
|
"flate2",
|
||||||
"int-enum",
|
"int-enum",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ anyhow = "1"
|
|||||||
blowfish = { version = "0.9", optional = true }
|
blowfish = { version = "0.9", optional = true }
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
csv = "1.3"
|
csv = "1.3"
|
||||||
|
emote-psb = { version = "0.5.0", features = ["serde"], optional = true }
|
||||||
encoding_rs = "0.8"
|
encoding_rs = "0.8"
|
||||||
flate2 = { version = "1.1", optional = true }
|
flate2 = { version = "1.1", optional = true }
|
||||||
int-enum = { version = "1.2", optional = true }
|
int-enum = { version = "1.2", optional = true }
|
||||||
@@ -21,7 +22,7 @@ serde_json = "1"
|
|||||||
unicode-segmentation = "1.12"
|
unicode-segmentation = "1.12"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "escude", "escude-arc", "yaneurao", "yaneurao-itufuru"]
|
default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "escude", "escude-arc", "kirikiri", "yaneurao", "yaneurao-itufuru"]
|
||||||
bgi = []
|
bgi = []
|
||||||
bgi-arc = ["bgi", "utils-bit-stream"]
|
bgi-arc = ["bgi", "utils-bit-stream"]
|
||||||
bgi-img = ["bgi", "image", "utils-bit-stream"]
|
bgi-img = ["bgi", "image", "utils-bit-stream"]
|
||||||
@@ -31,6 +32,7 @@ cat-system-img = ["cat-system", "flate2", "image", "utils-bit-stream"]
|
|||||||
circus = []
|
circus = []
|
||||||
escude = ["int-enum"]
|
escude = ["int-enum"]
|
||||||
escude-arc = ["escude", "rand", "utils-bit-stream"]
|
escude-arc = ["escude", "rand", "utils-bit-stream"]
|
||||||
|
kirikiri = ["emote-psb"]
|
||||||
yaneurao = []
|
yaneurao = []
|
||||||
yaneurao-itufuru = ["yaneurao"]
|
yaneurao-itufuru = ["yaneurao"]
|
||||||
# basic feature
|
# basic feature
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ pub struct Arg {
|
|||||||
#[arg(long, global = true, action = ArgAction::SetTrue)]
|
#[arg(long, global = true, action = ArgAction::SetTrue)]
|
||||||
/// Draw CatSystem2 image on canvas (if canvas width and height are specified in file)
|
/// Draw CatSystem2 image on canvas (if canvas width and height are specified in file)
|
||||||
pub cat_system_image_canvas: bool,
|
pub cat_system_image_canvas: bool,
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
#[arg(long, global = true)]
|
||||||
|
/// Kirikiri language index in script. If not specified, the first language will be used.
|
||||||
|
pub kirikiri_language_index: Option<usize>,
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
/// Command
|
/// Command
|
||||||
pub command: Command,
|
pub command: Command,
|
||||||
|
|||||||
@@ -1356,6 +1356,8 @@ fn main() {
|
|||||||
cat_system_int_encrypt_password: arg.cat_system_int_encrypt_password.clone(),
|
cat_system_int_encrypt_password: arg.cat_system_int_encrypt_password.clone(),
|
||||||
#[cfg(feature = "cat-system-img")]
|
#[cfg(feature = "cat-system-img")]
|
||||||
cat_system_image_canvas: arg.cat_system_image_canvas,
|
cat_system_image_canvas: arg.cat_system_image_canvas,
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
kirikiri_language_index: arg.kirikiri_language_index.clone(),
|
||||||
};
|
};
|
||||||
match &arg.command {
|
match &arg.command {
|
||||||
args::Command::Export { input, output } => {
|
args::Command::Export { input, output } => {
|
||||||
|
|||||||
1
src/scripts/kirikiri/mod.rs
Normal file
1
src/scripts/kirikiri/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod scn;
|
||||||
310
src/scripts/kirikiri/scn.rs
Normal file
310
src/scripts/kirikiri/scn.rs
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
use crate::ext::io::*;
|
||||||
|
use crate::scripts::base::*;
|
||||||
|
use crate::types::*;
|
||||||
|
use crate::utils::encoding::{decode_to_string, encode_string};
|
||||||
|
use anyhow::Result;
|
||||||
|
use emote_psb::types::PsbValue;
|
||||||
|
use emote_psb::{PsbReader, PsbWriter, VirtualPsb};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io::{Read, Seek, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScnScriptBuilder {}
|
||||||
|
|
||||||
|
impl ScnScriptBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScriptBuilder for ScnScriptBuilder {
|
||||||
|
fn default_encoding(&self) -> Encoding {
|
||||||
|
Encoding::Utf8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_script(
|
||||||
|
&self,
|
||||||
|
buf: Vec<u8>,
|
||||||
|
filename: &str,
|
||||||
|
_encoding: Encoding,
|
||||||
|
_archive_encoding: Encoding,
|
||||||
|
config: &ExtraConfig,
|
||||||
|
) -> Result<Box<dyn Script>> {
|
||||||
|
Ok(Box::new(ScnScript::new(
|
||||||
|
MemReader::new(buf),
|
||||||
|
filename,
|
||||||
|
config,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_script_from_file(
|
||||||
|
&self,
|
||||||
|
filename: &str,
|
||||||
|
_encoding: Encoding,
|
||||||
|
_archive_encoding: Encoding,
|
||||||
|
config: &ExtraConfig,
|
||||||
|
) -> Result<Box<dyn Script>> {
|
||||||
|
if filename == "-" {
|
||||||
|
let data = crate::utils::files::read_file(filename)?;
|
||||||
|
Ok(Box::new(ScnScript::new(
|
||||||
|
MemReader::new(data),
|
||||||
|
filename,
|
||||||
|
config,
|
||||||
|
)?))
|
||||||
|
} else {
|
||||||
|
let f = std::fs::File::open(filename)?;
|
||||||
|
let reader = std::io::BufReader::new(f);
|
||||||
|
Ok(Box::new(ScnScript::new(reader, filename, config)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_script_from_reader(
|
||||||
|
&self,
|
||||||
|
reader: Box<dyn ReadSeek>,
|
||||||
|
filename: &str,
|
||||||
|
_encoding: Encoding,
|
||||||
|
_archive_encoding: Encoding,
|
||||||
|
config: &ExtraConfig,
|
||||||
|
) -> Result<Box<dyn Script>> {
|
||||||
|
Ok(Box::new(ScnScript::new(reader, filename, config)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extensions(&self) -> &'static [&'static str] {
|
||||||
|
&["scn"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_type(&self) -> &'static ScriptType {
|
||||||
|
&ScriptType::KirikiriScn
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_this_format(&self, filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
|
||||||
|
if Path::new(filename)
|
||||||
|
.file_name()
|
||||||
|
.map(|name| {
|
||||||
|
name.to_ascii_lowercase()
|
||||||
|
.to_string_lossy()
|
||||||
|
.ends_with(".ks.scn")
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
&& buf_len >= 4
|
||||||
|
&& buf.starts_with(b"PSB\0")
|
||||||
|
{
|
||||||
|
return Some(255);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScnScript {
|
||||||
|
psb: VirtualPsb,
|
||||||
|
language_index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScnScript {
|
||||||
|
pub fn new<R: Read + Seek>(reader: R, filename: &str, config: &ExtraConfig) -> Result<Self> {
|
||||||
|
let mut psb = PsbReader::open_psb(reader)
|
||||||
|
.map_err(|e| anyhow::anyhow!("Failed to open PSB from {}: {:?}", filename, e))?;
|
||||||
|
let psb = psb
|
||||||
|
.load()
|
||||||
|
.map_err(|e| anyhow::anyhow!("Failed to load PSB from {}: {:?}", filename, e))?;
|
||||||
|
Ok(Self {
|
||||||
|
psb,
|
||||||
|
language_index: config.kirikiri_language_index.unwrap_or(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct PsbDataRef<'a> {
|
||||||
|
pub version: u16,
|
||||||
|
pub encryption: u16,
|
||||||
|
pub root: &'a emote_psb::types::collection::PsbObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PsbDataRef<'a> {
|
||||||
|
pub fn new(psb: &'a VirtualPsb) -> Self {
|
||||||
|
let header = psb.header();
|
||||||
|
Self {
|
||||||
|
version: header.version,
|
||||||
|
encryption: header.encryption,
|
||||||
|
root: psb.root(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct PsbData {
|
||||||
|
pub version: u16,
|
||||||
|
pub encryption: u16,
|
||||||
|
pub root: emote_psb::types::collection::PsbObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PsbData {
|
||||||
|
pub fn header(&self) -> emote_psb::header::PsbHeader {
|
||||||
|
emote_psb::header::PsbHeader {
|
||||||
|
version: self.version,
|
||||||
|
encryption: self.encryption,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script for ScnScript {
|
||||||
|
fn default_output_script_type(&self) -> OutputScriptType {
|
||||||
|
OutputScriptType::Json
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_format_type(&self) -> FormatOptions {
|
||||||
|
FormatOptions::None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_output_supported(&self, _: OutputScriptType) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_messages(&self) -> Result<Vec<Message>> {
|
||||||
|
let mut messages = Vec::new();
|
||||||
|
let root = self.psb.root();
|
||||||
|
let scenes = root
|
||||||
|
.get_value("scenes".into())
|
||||||
|
.ok_or(anyhow::anyhow!("scenes not found"))?;
|
||||||
|
let scenes = match scenes {
|
||||||
|
PsbValue::List(list) => list,
|
||||||
|
_ => return Err(anyhow::anyhow!("scenes is not a list")),
|
||||||
|
};
|
||||||
|
for (i, scene) in scenes.iter().enumerate() {
|
||||||
|
let scene = match scene {
|
||||||
|
PsbValue::Object(obj) => obj,
|
||||||
|
_ => return Err(anyhow::anyhow!("scene at index {} is not an object", i)),
|
||||||
|
};
|
||||||
|
if let Some(PsbValue::List(texts)) = scene.get_value("texts".into()) {
|
||||||
|
for text in texts.iter() {
|
||||||
|
if let PsbValue::List(text) = text {
|
||||||
|
let values = text.values();
|
||||||
|
if values.len() <= 1 {
|
||||||
|
continue; // Skip if there are not enough values
|
||||||
|
}
|
||||||
|
let name = &values[0];
|
||||||
|
let name = match name {
|
||||||
|
PsbValue::String(s) => Some(s),
|
||||||
|
PsbValue::Null => None,
|
||||||
|
_ => return Err(anyhow::anyhow!("name is not a string or null")),
|
||||||
|
};
|
||||||
|
let mut display_name;
|
||||||
|
let mut message;
|
||||||
|
if matches!(values[1], PsbValue::List(_)) {
|
||||||
|
display_name = None;
|
||||||
|
message = &values[1];
|
||||||
|
} else {
|
||||||
|
if values.len() <= 2 {
|
||||||
|
continue; // Skip if there is no message
|
||||||
|
}
|
||||||
|
display_name = match &values[1] {
|
||||||
|
PsbValue::String(s) => Some(s),
|
||||||
|
PsbValue::Null => None,
|
||||||
|
_ => {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"display name is not a string or null"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
message = &values[2];
|
||||||
|
}
|
||||||
|
if matches!(message, PsbValue::List(_)) {
|
||||||
|
let tmp = message;
|
||||||
|
if let PsbValue::List(list) = tmp {
|
||||||
|
if list.len() > self.language_index {
|
||||||
|
if let PsbValue::List(data) =
|
||||||
|
&list.values()[self.language_index]
|
||||||
|
{
|
||||||
|
if data.len() >= 2 {
|
||||||
|
let data = data.values();
|
||||||
|
display_name = match &data[0] {
|
||||||
|
PsbValue::String(s) => Some(s),
|
||||||
|
PsbValue::Null => None,
|
||||||
|
_ => {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"display name is not a string or null"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
message = &data[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let PsbValue::String(message) = message {
|
||||||
|
match name {
|
||||||
|
Some(name) => {
|
||||||
|
let name = match display_name {
|
||||||
|
Some(name) => name.string(),
|
||||||
|
None => name.string(),
|
||||||
|
};
|
||||||
|
let message = message.string();
|
||||||
|
messages.push(Message {
|
||||||
|
name: Some(name.to_string()),
|
||||||
|
message: message.replace("\\n", "\n"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let message = message.string();
|
||||||
|
messages.push(Message {
|
||||||
|
name: None,
|
||||||
|
message: message.replace("\\n", "\n"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #TODO: selects / comudata(circus)
|
||||||
|
}
|
||||||
|
Ok(messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom_output_extension(&self) -> &'static str {
|
||||||
|
"json"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom_export(&self, filename: &Path, encoding: Encoding) -> Result<()> {
|
||||||
|
if !self.psb.resources().is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: The PSB contains resources, which may not be fully represented in the JSON output."
|
||||||
|
);
|
||||||
|
crate::COUNTER.inc_warning();
|
||||||
|
}
|
||||||
|
if !self.psb.extra().is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Warning: The PSB contains extra data, which may not be fully represented in the JSON output."
|
||||||
|
);
|
||||||
|
crate::COUNTER.inc_warning();
|
||||||
|
}
|
||||||
|
let psb_data = PsbDataRef::new(&self.psb);
|
||||||
|
let str = serde_json::to_string_pretty(&psb_data)?;
|
||||||
|
let s = encode_string(encoding, &str, false)?;
|
||||||
|
let mut f = std::fs::File::create(filename)?;
|
||||||
|
f.write_all(&s)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom_import<'a>(
|
||||||
|
&'a self,
|
||||||
|
custom_filename: &'a str,
|
||||||
|
file: Box<dyn WriteSeek + 'a>,
|
||||||
|
encoding: Encoding,
|
||||||
|
_output_encoding: Encoding,
|
||||||
|
) -> Result<()> {
|
||||||
|
let data = crate::utils::files::read_file(custom_filename)?;
|
||||||
|
let s = decode_to_string(encoding, &data)?;
|
||||||
|
let psb_data: PsbData = serde_json::from_str(&s)?;
|
||||||
|
let psb = VirtualPsb::new(psb_data.header(), Vec::new(), Vec::new(), psb_data.root);
|
||||||
|
let writer = PsbWriter::new(psb, file);
|
||||||
|
writer
|
||||||
|
.finish()
|
||||||
|
.map_err(|e| anyhow::anyhow!("Failed to write PSB: {:?}", e))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ pub mod cat_system;
|
|||||||
pub mod circus;
|
pub mod circus;
|
||||||
#[cfg(feature = "escude")]
|
#[cfg(feature = "escude")]
|
||||||
pub mod escude;
|
pub mod escude;
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
pub mod kirikiri;
|
||||||
#[cfg(feature = "yaneurao")]
|
#[cfg(feature = "yaneurao")]
|
||||||
pub mod yaneurao;
|
pub mod yaneurao;
|
||||||
|
|
||||||
@@ -46,6 +48,8 @@ lazy_static::lazy_static! {
|
|||||||
Box::new(cat_system::archive::int::CSIntArcBuilder::new()),
|
Box::new(cat_system::archive::int::CSIntArcBuilder::new()),
|
||||||
#[cfg(feature = "cat-system-img")]
|
#[cfg(feature = "cat-system-img")]
|
||||||
Box::new(cat_system::image::hg3::Hg3ImageBuilder::new()),
|
Box::new(cat_system::image::hg3::Hg3ImageBuilder::new()),
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
Box::new(kirikiri::scn::ScnScriptBuilder::new()),
|
||||||
];
|
];
|
||||||
pub static ref ALL_EXTS: Vec<String> =
|
pub static ref ALL_EXTS: Vec<String> =
|
||||||
BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect();
|
BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect();
|
||||||
|
|||||||
@@ -207,6 +207,8 @@ pub struct ExtraConfig {
|
|||||||
pub cat_system_int_encrypt_password: Option<String>,
|
pub cat_system_int_encrypt_password: Option<String>,
|
||||||
#[cfg(feature = "cat-system-img")]
|
#[cfg(feature = "cat-system-img")]
|
||||||
pub cat_system_image_canvas: bool,
|
pub cat_system_image_canvas: bool,
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
pub kirikiri_language_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@@ -262,6 +264,10 @@ pub enum ScriptType {
|
|||||||
#[cfg(feature = "escude")]
|
#[cfg(feature = "escude")]
|
||||||
/// Escude list script
|
/// Escude list script
|
||||||
EscudeList,
|
EscudeList,
|
||||||
|
#[cfg(feature = "kirikiri")]
|
||||||
|
#[value(alias("kr-scn"))]
|
||||||
|
/// Kirikiri SCN script
|
||||||
|
KirikiriScn,
|
||||||
#[cfg(feature = "yaneurao-itufuru")]
|
#[cfg(feature = "yaneurao-itufuru")]
|
||||||
#[value(alias("itufuru"))]
|
#[value(alias("itufuru"))]
|
||||||
/// Yaneurao Itufuru script
|
/// Yaneurao Itufuru script
|
||||||
|
|||||||
Reference in New Issue
Block a user