mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-08 05:48:46 +08:00
Add support to export all chat message
This commit is contained in:
18
src/args.rs
18
src/args.rs
@@ -69,6 +69,7 @@ fn parse_flac_compression_level(level: &str) -> Result<u32, String> {
|
||||
group = ArgGroup::new("ex_hibit_rld_def_xor_keyg").multiple(false),
|
||||
group = ArgGroup::new("webp_qualityg").multiple(false),
|
||||
group = ArgGroup::new("cat_system_int_encrypt_passwordg").multiple(false),
|
||||
group = ArgGroup::new("kirikiri_chat_jsong").multiple(false),
|
||||
)]
|
||||
#[command(
|
||||
version,
|
||||
@@ -185,14 +186,19 @@ pub struct Arg {
|
||||
/// Kirikiri language index in script. If not specified, the first language will be used.
|
||||
pub kirikiri_language_index: Option<usize>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true, action = ArgAction::SetTrue)]
|
||||
/// Export COMU message to extra json file. (for Kirikiri SCN script.)
|
||||
/// Only CIRCUS's game have COMU message.
|
||||
pub kirikiri_export_comumode: bool,
|
||||
#[arg(long, global = true)]
|
||||
/// Export chat message to extra json file. (for Kirikiri SCN script.)
|
||||
/// For example, CIRCUS's comu message. Yuzusoft's phone chat message.
|
||||
pub kirikiri_export_chat: bool,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true)]
|
||||
/// Kirikiri COMU message translation file. (Map<String, String>, key is original text, value is translated text.)
|
||||
pub kirikiri_comumode_json: Option<String>,
|
||||
/// Kirikiri chat message key. For example, CIRCUS's key is "comumode". Yuzusoft's key is "phonechat".
|
||||
/// If not specified, "comumode" will be used.
|
||||
pub kirikiri_chat_key: Option<String>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true, group = "kirikiri_chat_jsong")]
|
||||
/// Kirikiri chat message translation file. (Map<String, String>, key is original text, value is translated text.)
|
||||
pub kirikiri_chat_json: Option<String>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
#[arg(long, global = true, action = ArgAction::SetTrue, alias = "kr-no-empty-lines", alias = "kirikiri-no-empty-lines")]
|
||||
/// Remove empty lines in Kirikiri KS script.
|
||||
|
||||
@@ -1698,10 +1698,12 @@ fn main() {
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_language_index: arg.kirikiri_language_index.clone(),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_export_comumode: arg.kirikiri_export_comumode,
|
||||
kirikiri_export_chat: arg.kirikiri_export_chat,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_comumode_json: arg
|
||||
.kirikiri_comumode_json
|
||||
kirikiri_chat_key: arg.kirikiri_chat_key.clone(),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_chat_json: arg
|
||||
.kirikiri_chat_json
|
||||
.as_ref()
|
||||
.map(|s| scripts::kirikiri::read_kirikiri_comu_json(s).unwrap()),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
|
||||
@@ -110,9 +110,10 @@ impl ScriptBuilder for ScnScriptBuilder {
|
||||
pub struct ScnScript {
|
||||
psb: VirtualPsbFixed,
|
||||
language_index: usize,
|
||||
export_comumode: bool,
|
||||
export_chat: bool,
|
||||
filename: String,
|
||||
comumode_json: Option<Arc<HashMap<String, String>>>,
|
||||
chat_key: Option<String>,
|
||||
chat_json: Option<Arc<HashMap<String, String>>>,
|
||||
custom_yaml: bool,
|
||||
}
|
||||
|
||||
@@ -144,9 +145,10 @@ impl ScnScript {
|
||||
Ok(Self {
|
||||
psb: psb.to_psb_fixed(),
|
||||
language_index: config.kirikiri_language_index.unwrap_or(0),
|
||||
export_comumode: config.kirikiri_export_comumode,
|
||||
export_chat: config.kirikiri_export_chat,
|
||||
filename: filename.to_string(),
|
||||
comumode_json: config.kirikiri_comumode_json.clone(),
|
||||
chat_key: config.kirikiri_chat_key.clone(),
|
||||
chat_json: config.kirikiri_chat_json.clone(),
|
||||
custom_yaml: config.custom_yaml,
|
||||
})
|
||||
}
|
||||
@@ -179,8 +181,10 @@ impl Script for ScnScript {
|
||||
PsbValueFixed::List(list) => list,
|
||||
_ => return Err(anyhow::anyhow!("scenes is not a list")),
|
||||
};
|
||||
let mut comu = if self.export_comumode {
|
||||
Some(ExportComuMes::new())
|
||||
let mut comu = if self.export_chat {
|
||||
Some(ExportMes::new(
|
||||
self.chat_key.clone().unwrap_or("comumode".to_string()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -322,19 +326,19 @@ impl Script for ScnScript {
|
||||
let filename = pb
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy())
|
||||
.unwrap_or(std::borrow::Cow::from("comumode"));
|
||||
pb.set_file_name(format!("{}_comumode.json", filename));
|
||||
.unwrap_or(std::borrow::Cow::from(comu.key.as_str()));
|
||||
pb.set_file_name(format!("{}_{}.json", filename, comu.key));
|
||||
match std::fs::File::create(&pb) {
|
||||
Ok(mut f) => {
|
||||
let messages: Vec<String> = comu.messages.into_iter().collect();
|
||||
if let Err(e) = serde_json::to_writer_pretty(&mut f, &messages) {
|
||||
eprintln!("Failed to write COMU messages to {}: {:?}", pb.display(), e);
|
||||
eprintln!("Failed to write chat messages to {}: {:?}", pb.display(), e);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to create COMU messages file {}: {:?}",
|
||||
"Failed to create chat messages file {}: {:?}",
|
||||
pb.display(),
|
||||
e
|
||||
);
|
||||
@@ -362,10 +366,13 @@ impl Script for ScnScript {
|
||||
if !scenes.is_list() {
|
||||
return Err(anyhow::anyhow!("scenes is not an array"));
|
||||
}
|
||||
let comu = self
|
||||
.comumode_json
|
||||
.as_ref()
|
||||
.map(|json| ImportComuMes::new(json, replacement));
|
||||
let comu = self.chat_json.as_ref().map(|json| {
|
||||
ImportMes::new(
|
||||
json,
|
||||
replacement,
|
||||
self.chat_key.clone().unwrap_or("comumode".to_string()),
|
||||
)
|
||||
});
|
||||
for (i, scene) in scenes.members_mut().enumerate() {
|
||||
if !scene.is_object() {
|
||||
return Err(anyhow::anyhow!("scene at {} is not an object", i));
|
||||
@@ -653,14 +660,16 @@ impl Script for ScnScript {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExportComuMes {
|
||||
struct ExportMes {
|
||||
pub messages: HashSet<String>,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
impl ExportComuMes {
|
||||
pub fn new() -> Self {
|
||||
impl ExportMes {
|
||||
pub fn new(key: String) -> Self {
|
||||
Self {
|
||||
messages: HashSet::new(),
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,7 +677,7 @@ impl ExportComuMes {
|
||||
match value {
|
||||
PsbValueFixed::Object(obj) => {
|
||||
for (k, v) in obj.iter() {
|
||||
if k == "comumode" {
|
||||
if k == &self.key {
|
||||
if let PsbValueFixed::List(list) = v {
|
||||
for item in list.iter() {
|
||||
if let PsbValueFixed::Object(obj) = item {
|
||||
@@ -687,7 +696,7 @@ impl ExportComuMes {
|
||||
let list = list.values();
|
||||
if list.len() > 1 {
|
||||
if let PsbValueFixed::String(s) = &list[0] {
|
||||
if s.string() == "comumode" {
|
||||
if s.string() == &self.key {
|
||||
for i in 1..list.len() {
|
||||
if let PsbValueFixed::String(s) = &list[i - 1] {
|
||||
if s.string() == "text" {
|
||||
@@ -712,19 +721,22 @@ impl ExportComuMes {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ImportComuMes<'a> {
|
||||
struct ImportMes<'a> {
|
||||
messages: &'a Arc<HashMap<String, String>>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
key: String,
|
||||
}
|
||||
|
||||
impl<'a> ImportComuMes<'a> {
|
||||
impl<'a> ImportMes<'a> {
|
||||
pub fn new(
|
||||
messages: &'a Arc<HashMap<String, String>>,
|
||||
replacement: Option<&'a ReplacementTable>,
|
||||
key: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
messages,
|
||||
replacement,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,7 +744,7 @@ impl<'a> ImportComuMes<'a> {
|
||||
match value {
|
||||
PsbValueFixed::Object(obj) => {
|
||||
for (k, v) in obj.iter_mut() {
|
||||
if k == "comumode" {
|
||||
if k == &self.key {
|
||||
for obj in v.members_mut() {
|
||||
if let Some(text) = obj["text"].as_str() {
|
||||
if let Some(replace_text) = self.messages.get(text) {
|
||||
@@ -745,7 +757,7 @@ impl<'a> ImportComuMes<'a> {
|
||||
obj["text"].set_string(text.replace("\n", "\\n"));
|
||||
} else {
|
||||
eprintln!(
|
||||
"Warning: COMU message '{}' not found in translation table.",
|
||||
"Warning: chat message '{}' not found in translation table.",
|
||||
text
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
@@ -759,7 +771,7 @@ impl<'a> ImportComuMes<'a> {
|
||||
}
|
||||
PsbValueFixed::List(list) => {
|
||||
if list.len() > 1 {
|
||||
if list[0] == "comumode" {
|
||||
if list[0] == self.key {
|
||||
for i in 1..list.len() {
|
||||
if list[i - 1] == "text" {
|
||||
if let Some(text) = list[i].as_str() {
|
||||
@@ -773,7 +785,7 @@ impl<'a> ImportComuMes<'a> {
|
||||
list[i].set_string(text.replace("\n", "\\n"));
|
||||
} else {
|
||||
eprintln!(
|
||||
"Warning: COMU message '{}' not found in translation table.",
|
||||
"Warning: chat message '{}' not found in translation table.",
|
||||
text
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
|
||||
14
src/types.rs
14
src/types.rs
@@ -260,12 +260,16 @@ pub struct ExtraConfig {
|
||||
/// Kirikiri language index in script. If not specified, the first language will be used.
|
||||
pub kirikiri_language_index: Option<usize>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Export COMU message to extra json file. (for Kirikiri SCN script.)
|
||||
/// Only CIRCUS's game have COMU message.
|
||||
pub kirikiri_export_comumode: bool,
|
||||
/// Export chat message to extra json file. (for Kirikiri SCN script.)
|
||||
/// For example, CIRCUS's comu message. Yuzusoft's phone chat message.
|
||||
pub kirikiri_export_chat: bool,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Kirikiri COMU message translation. key is original text, value is translated text.
|
||||
pub kirikiri_comumode_json: Option<std::sync::Arc<HashMap<String, String>>>,
|
||||
/// Kirikiri chat message key. For example, CIRCUS's key is "comumode". Yuzusoft's key is "phonechat".
|
||||
/// If not specified, "comumode" will be used.
|
||||
pub kirikiri_chat_key: Option<String>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Kirikiri chat message translation. key is original text, value is translated text.
|
||||
pub kirikiri_chat_json: Option<std::sync::Arc<HashMap<String, String>>>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
/// Remove empty lines in Kirikiri KS script.
|
||||
pub kirikiri_remove_empty_lines: bool,
|
||||
|
||||
Reference in New Issue
Block a user