rgpre/import/rgm/
script_step.rs1#[derive(Debug, PartialEq, Eq)]
5pub struct LiteralScriptStep {
6 pub next: usize,
8 pub operation: LiteralScriptOperation,
10}
11
12#[derive(Debug, PartialEq, Eq)]
14pub enum LiteralScriptOperation {
15 Task {
17 function_id: u16,
18 arguments: Vec<i32>,
19 },
20 End { target: u32 },
22}
23
24pub fn decode_literal_script_step(code: &[u8], offset: usize) -> Result<LiteralScriptStep, String> {
27 let mut cursor = offset;
28 let mut read = |count: usize| {
29 let end = cursor
30 .checked_add(count)
31 .ok_or_else(|| format!("script instruction {offset}: operand offset overflow"))?;
32 let bytes = code
33 .get(cursor..end)
34 .ok_or_else(|| format!("script instruction {offset}: truncated operand at {cursor}"))?;
35 cursor = end;
36 Ok::<_, String>(bytes)
37 };
38 let opcode = read(1)?[0];
39 let operation = match opcode {
40 0 => {
41 let bytes = read(2)?;
42 let function_id = u16::from_le_bytes([bytes[0], bytes[1]]);
43 let count = if function_id == 0 { 0 } else { read(1)?[0] };
44 let mut arguments = Vec::with_capacity(usize::from(count));
45 for _ in 0..count {
46 let operand = read(1)?[0];
47 if !matches!(operand, 7 | 22) {
48 return Err(format!(
49 "script instruction {offset}: nonliteral task operand {operand} unsupported"
50 ));
51 }
52 let bytes = read(4)?;
53 arguments.push(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]));
54 }
55 LiteralScriptOperation::Task {
56 function_id,
57 arguments,
58 }
59 }
60 5 => {
61 let bytes = read(4)?;
62 LiteralScriptOperation::End {
63 target: u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
64 }
65 }
66 _ => {
67 return Err(format!(
68 "script instruction {offset}: opcode {opcode} unsupported by literal task decoder"
69 ));
70 }
71 };
72 Ok(LiteralScriptStep {
73 next: cursor,
74 operation,
75 })
76}