diff --git a/README.md b/README.md index 5f2390d..a741bcd 100644 --- a/README.md +++ b/README.md @@ -267,3 +267,4 @@ msg-tool create -t | Script Type | Feature Name | Name | Export | Import | Export Multiple | Import Multiple | Custom Export | Custom Import | Create | Remarks | |---|---|---|---|---|---|---|---|---|---|---| | `yuris-yscm` | `yuris` | Yu-Ris YSCM(opcodes metadata) file (.ybn) | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | | +| `yuris-yser` | `yuris` | Yu-Ris YSER(error message) file (.ybn) | ❌ | ❌ | ❌ | ❌ | ✔️ | ❌ | ❌ | | diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index bbb8fca..4803c4d 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -178,6 +178,8 @@ lazy_static::lazy_static! { Box::new(qlie::image::abmp10::Abmp10ImageBuilder::new()), #[cfg(feature = "yuris")] Box::new(yuris::yscm::YSCMBuilder::new()), + #[cfg(feature = "yuris")] + Box::new(yuris::yser::YSERBuilder::new()), ]; /// A list of all script extensions. pub static ref ALL_EXTS: Vec = diff --git a/src/scripts/yuris/mod.rs b/src/scripts/yuris/mod.rs index b16b9e9..c582208 100644 --- a/src/scripts/yuris/mod.rs +++ b/src/scripts/yuris/mod.rs @@ -1,3 +1,4 @@ //! Yu-Ris Engine Scripts mod types; pub mod yscm; +pub mod yser; diff --git a/src/scripts/yuris/yser.rs b/src/scripts/yuris/yser.rs new file mode 100644 index 0000000..a0487f0 --- /dev/null +++ b/src/scripts/yuris/yser.rs @@ -0,0 +1,125 @@ +//! Yu-Ris YSER files +use crate::ext::io::*; +use crate::scripts::base::*; +use crate::types::*; +use crate::utils::encoding::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use msg_tool_macro::*; +use serde::{Deserialize, Serialize}; +use std::io::{Read, Seek, Write}; + +#[derive(Debug)] +pub struct YSERBuilder {} + +impl YSERBuilder { + /// Creates a new instance of `YSERBuilder` + pub const fn new() -> Self { + YSERBuilder {} + } +} + +impl ScriptBuilder for YSERBuilder { + fn default_encoding(&self) -> Encoding { + Encoding::Cp932 + } + + fn build_script( + &self, + buf: Vec, + _filename: &str, + encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + _archive: Option<&Box>, + ) -> Result> { + Ok(Box::new(YSER::new(MemReader::new(buf), encoding, config)?)) + } + + fn extensions(&self) -> &'static [&'static str] { + &["ybn"] + } + + fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option { + if buf_len >= 4 && buf.starts_with(b"YSER") { + return Some(20); + } + None + } + + fn script_type(&self) -> &'static ScriptType { + &ScriptType::YurisYSER + } +} + +#[derive(Debug, StructPack, StructUnpack, Deserialize, Serialize)] +struct StringData { + unk: u32, + #[cstring] + s: String, +} + +#[derive(Debug, StructPack, StructUnpack, Deserialize, Serialize)] +struct YSERData { + engine: u32, + #[pvec(u64)] + strings: Vec, +} + +#[derive(Debug)] +pub struct YSER { + data: YSERData, + custom_yaml: bool, +} + +impl YSER { + pub fn new( + mut reader: T, + encoding: Encoding, + config: &ExtraConfig, + ) -> Result { + let mut sig = [0; 4]; + reader.read_exact(&mut sig)?; + if &sig != b"YSER" { + anyhow::bail!("Unsupported YSER file."); + } + let data = YSERData::unpack(&mut reader, false, encoding, &None)?; + Ok(Self { + data, + custom_yaml: config.custom_yaml, + }) + } +} + +impl Script for YSER { + fn default_output_script_type(&self) -> OutputScriptType { + OutputScriptType::Custom + } + + fn is_output_supported(&self, output: OutputScriptType) -> bool { + matches!(output, OutputScriptType::Custom) + } + + fn default_format_type(&self) -> FormatOptions { + FormatOptions::None + } + + fn custom_output_extension(&self) -> &'static str { + if self.custom_yaml { "yaml" } else { "json" } + } + + fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> { + let s = if self.custom_yaml { + serde_yaml_ng::to_string(&self.data) + .map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))? + } else { + serde_json::to_string_pretty(&self.data) + .map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))? + }; + let mut writer = crate::utils::files::write_file(filename)?; + let s = encode_string(encoding, &s, false)?; + writer.write_all(&s)?; + writer.flush()?; + Ok(()) + } +} diff --git a/src/types.rs b/src/types.rs index 7a2dbaa..0093f90 100644 --- a/src/types.rs +++ b/src/types.rs @@ -911,6 +911,9 @@ pub enum ScriptType { #[cfg(feature = "yuris")] /// Yu-Ris YSCM(opcodes metadata) file (.ybn) YurisYSCM, + #[cfg(feature = "yuris")] + /// Yu-Ris YSER(error message) file (.ybn) + YurisYSER, } #[derive(Clone, Debug, Serialize, Deserialize)]