feat(script): decode compiled package framing

This commit is contained in:
2026-07-18 20:40:17 +04:00
parent a7b434aeb2
commit d31d1f8eab
12 changed files with 449 additions and 4 deletions
+1
View File
@@ -13,6 +13,7 @@ fparkan-inspection = { path = "../../crates/fparkan-inspection", version = "0.1.
fparkan-path = { path = "../../crates/fparkan-path", version = "0.1.0" }
fparkan-resource = { path = "../../crates/fparkan-resource", version = "0.1.0" }
fparkan-runtime = { path = "../../crates/fparkan-runtime", version = "0.1.0" }
fparkan-script = { path = "../../crates/fparkan-script", version = "0.1.0" }
fparkan-vfs = { path = "../../crates/fparkan-vfs", version = "0.1.0" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
+63 -1
View File
@@ -48,6 +48,7 @@ const MISSION_INSPECT_SCHEMA: &str = "fparkan-mission-inspect-v1";
const TERRAIN_INSPECT_SCHEMA: &str = "fparkan-terrain-inspect-v1";
const MODEL_INSPECT_SCHEMA: &str = "fparkan-model-inspect-v1";
const WEAR_INSPECT_SCHEMA: &str = "fparkan-wear-inspect-v1";
const SCRIPT_INSPECT_SCHEMA: &str = "fparkan-script-inspect-v1";
#[derive(Serialize)]
struct ArchiveInspectOutput<'a> {
@@ -226,6 +227,17 @@ struct PrototypeGraphEdgeInspectOutput {
resource_raw_hex: Option<String>,
}
#[derive(Serialize)]
struct ScriptInspectOutput<'a> {
schema_version: &'static str,
path: &'a str,
opcode_handler_count: u32,
events: usize,
instructions: usize,
references: usize,
trailing_bytes: usize,
}
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let result = run(&args);
@@ -290,10 +302,50 @@ fn run(args: &[String]) -> Result<(), String> {
let rest = strip_format_json(rest)?;
inspect_model(&rest)
}
[domain, command, rest @ ..] if domain == "script" && command == "inspect" => {
let rest = strip_format_json(rest)?;
inspect_script(&rest)
}
_ => Err(usage()),
}
}
fn inspect_script(args: &[String]) -> Result<(), String> {
let path = parse_file_path(args, "script inspect")?;
let bytes = std::fs::read(&path).map_err(|err| format!("{}: {err}", path.display()))?;
let package =
fparkan_script::decode(&bytes).map_err(|err| format!("{}: {err}", path.display()))?;
let display_path = path.display().to_string();
println!("{}", script_inspect_json(&display_path, &package)?);
Ok(())
}
fn script_inspect_json(
path: &str,
package: &fparkan_script::ScriptPackage,
) -> Result<String, String> {
let instructions = package
.events
.iter()
.map(|event| event.instructions.len())
.sum();
let references = package
.events
.iter()
.flat_map(|event| &event.instructions)
.map(|instruction| instruction.references.len())
.sum();
serialize_json(&ScriptInspectOutput {
schema_version: SCRIPT_INSPECT_SCHEMA,
path,
opcode_handler_count: package.opcode_handler_count,
events: package.events.len(),
instructions,
references,
trailing_bytes: package.trailing_bytes.len(),
})
}
fn exit_code(result: &Result<(), String>) -> i32 {
if result.is_ok() {
0
@@ -769,7 +821,7 @@ fn prototype_graph_requiredness_label(
}
fn usage() -> String {
"usage: fparkan corpus discover|validate --root <path> [--format json] | archive inspect <file> [--format json] | terrain inspect <Land.msh> [--format json] | wear inspect --root <path> --archive <archive> --resource <wear.wea> [--format json] | model inspect --root <path> --archive <archive> --resource <model.msh> [--format json] | prototype inspect --root <path> --key <key> [--format json] | mission graph|inspect --root <path> --mission <path> [--format json]".to_string()
"usage: fparkan corpus discover|validate --root <path> [--format json] | archive inspect <file> [--format json] | terrain inspect <Land.msh> [--format json] | wear inspect --root <path> --archive <archive> --resource <wear.wea> [--format json] | model inspect --root <path> --archive <archive> --resource <model.msh> [--format json] | script inspect <file> [--format json] | prototype inspect --root <path> --key <key> [--format json] | mission graph|inspect --root <path> --mission <path> [--format json]".to_string()
}
#[cfg(test)]
@@ -798,6 +850,16 @@ mod tests {
);
}
#[test]
fn script_inspect_json_has_canonical_field_order() {
let package =
fparkan_script::decode(&[73, 0, 0, 0, 0, 0, 0, 0]).expect("minimal script package");
assert_eq!(
script_inspect_json("script.scr", &package),
Ok("{\"schema_version\":\"fparkan-script-inspect-v1\",\"path\":\"script.scr\",\"opcode_handler_count\":73,\"events\":0,\"instructions\":0,\"references\":0,\"trailing_bytes\":0}".to_string())
);
}
#[test]
fn archive_json_has_schema_version() {
let json = archive_inspect_json("archive.lib", "NRes", 3, Some(true))