mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-06-06 21:08:48 +08:00
Add comumode export support for scn script
This commit is contained in:
@@ -114,6 +114,11 @@ pub struct Arg {
|
||||
#[arg(long, global = true)]
|
||||
/// 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,
|
||||
#[command(subcommand)]
|
||||
/// Command
|
||||
pub command: Command,
|
||||
|
||||
@@ -1358,6 +1358,8 @@ fn main() {
|
||||
cat_system_image_canvas: arg.cat_system_image_canvas,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_language_index: arg.kirikiri_language_index.clone(),
|
||||
#[cfg(feature = "kirikiri")]
|
||||
kirikiri_export_comumode: arg.kirikiri_export_comumode,
|
||||
};
|
||||
match &arg.command {
|
||||
args::Command::Export { input, output } => {
|
||||
|
||||
@@ -6,6 +6,7 @@ use anyhow::Result;
|
||||
use emote_psb::types::PsbValue;
|
||||
use emote_psb::{PsbReader, PsbWriter, VirtualPsb};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -100,6 +101,8 @@ impl ScriptBuilder for ScnScriptBuilder {
|
||||
pub struct ScnScript {
|
||||
psb: VirtualPsb,
|
||||
language_index: usize,
|
||||
export_comumode: bool,
|
||||
filename: String,
|
||||
}
|
||||
|
||||
impl ScnScript {
|
||||
@@ -112,6 +115,8 @@ impl ScnScript {
|
||||
Ok(Self {
|
||||
psb,
|
||||
language_index: config.kirikiri_language_index.unwrap_or(0),
|
||||
export_comumode: config.kirikiri_export_comumode,
|
||||
filename: filename.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -173,8 +178,13 @@ impl Script for ScnScript {
|
||||
PsbValue::List(list) => list,
|
||||
_ => return Err(anyhow::anyhow!("scenes is not a list")),
|
||||
};
|
||||
for (i, scene) in scenes.iter().enumerate() {
|
||||
let scene = match scene {
|
||||
let mut comu = if self.export_comumode {
|
||||
Some(ExportComuMes::new())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
for (i, oscene) in scenes.iter().enumerate() {
|
||||
let scene = match oscene {
|
||||
PsbValue::Object(obj) => obj,
|
||||
_ => return Err(anyhow::anyhow!("scene at index {} is not an object", i)),
|
||||
};
|
||||
@@ -304,7 +314,34 @@ impl Script for ScnScript {
|
||||
}
|
||||
}
|
||||
}
|
||||
// #TODO: comudata(circus)
|
||||
comu.as_mut().map(|c| c.export(&oscene));
|
||||
}
|
||||
if let Some(comu) = comu {
|
||||
if !comu.messages.is_empty() {
|
||||
let mut pb = std::path::PathBuf::from(&self.filename);
|
||||
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));
|
||||
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);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Failed to create COMU messages file {}: {:?}",
|
||||
pb.display(),
|
||||
e
|
||||
);
|
||||
crate::COUNTER.inc_warning();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(messages)
|
||||
}
|
||||
@@ -352,3 +389,62 @@ impl Script for ScnScript {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExportComuMes {
|
||||
pub messages: HashSet<String>,
|
||||
}
|
||||
|
||||
impl ExportComuMes {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
messages: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn export(&mut self, value: &PsbValue) {
|
||||
match value {
|
||||
PsbValue::Object(obj) => {
|
||||
for (k, v) in obj.iter() {
|
||||
if k == "comumode" {
|
||||
if let PsbValue::List(list) = v {
|
||||
for item in list.iter() {
|
||||
if let PsbValue::Object(obj) = item {
|
||||
if let Some(PsbValue::String(s)) = obj.get_value("text".into())
|
||||
{
|
||||
self.messages.insert(s.string().to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.export(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
PsbValue::List(list) => {
|
||||
let list = list.values();
|
||||
if list.len() > 1 {
|
||||
if let PsbValue::String(s) = &list[0] {
|
||||
if s.string() == "comumode" {
|
||||
for i in 1..list.len() {
|
||||
if let PsbValue::String(s) = &list[i - 1] {
|
||||
if s.string() == "text" {
|
||||
if let PsbValue::String(text) = &list[i] {
|
||||
self.messages.insert(text.string().to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for item in list {
|
||||
self.export(item);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +209,8 @@ pub struct ExtraConfig {
|
||||
pub cat_system_image_canvas: bool,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
pub kirikiri_language_index: Option<usize>,
|
||||
#[cfg(feature = "kirikiri")]
|
||||
pub kirikiri_export_comumode: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
||||
Reference in New Issue
Block a user