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