diff --git a/Cargo.lock b/Cargo.lock index e68269d..9ff29f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1429,11 +1429,8 @@ dependencies = [ "clap_complete", "colored", "flint-core", - "futures", "parking_lot", - "serde", "serde_json", - "thiserror 2.0.17", "tokio", "tracing", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 72a18c7..2753645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,15 +7,12 @@ license = "MIT" [dependencies] azalea = { git = "https://github.com/azalea-rs/azalea", rev = "1accbac" } tokio = { version = "1.48", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow = "1.0" -thiserror = "2.0" clap = { version = "4.5", features = ["derive"] } colored = "3.0" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } parking_lot = "0.12" -futures = "0.3" flint-core = { git = "https://github.com/FlintTestMC/flint-core", rev = "b04ad23" } clap_complete = "4.5.65" diff --git a/src/executor/block.rs b/src/executor/block.rs index ec69d2d..6f5f866 100644 --- a/src/executor/block.rs +++ b/src/executor/block.rs @@ -106,7 +106,7 @@ pub fn make_block(block_str: &str) -> Block { if let Some((k, v)) = pair.split_once('=') { properties.insert( k.trim().to_string(), - serde_json::Value::String(v.trim().to_string()), + serde_json::Value::String(v.strip_prefix('_').unwrap_or(v).trim().to_string()), ); } } diff --git a/src/executor/handlers.rs b/src/executor/handlers.rs index d7189c1..9e6efc1 100644 --- a/src/executor/handlers.rs +++ b/src/executor/handlers.rs @@ -26,7 +26,7 @@ pub fn parse_command(message: &str) -> Option<(String, Vec)> { return None; }; - let parts: Vec<&str> = command_str.trim().split_whitespace().collect(); + let parts: Vec<&str> = command_str.split_whitespace().collect(); if parts.is_empty() { return None; } @@ -64,6 +64,14 @@ impl TestExecutor { self.bot .send_command("say Recorder actions: !assert , !assert_changes") .await?; + self.bot + .send_command( + "say Recorder actions: !pos1 , !pos - Allow to use assert for a 3d area", + ) + .await?; + self.bot + .send_command("say Recorder actions: !sprint - ticks this ticks and asserts after each tick") + .await?; self.bot .send_command("say !stop - Exit interactive mode") .await?; @@ -361,6 +369,16 @@ impl TestExecutor { Ok(()) } + pub(super) fn handle_pos1(&mut self, args: &[String]) { + if args.is_empty() { + self.pos1 = None; + return; + } + let x = args[0].parse::().unwrap_or(0); + let y = args[1].parse::().unwrap_or(0); + let z = args[2].parse::().unwrap_or(0); + self.pos1 = Some([x, y, z]); + } pub(super) async fn handle_record_assert(&mut self, args: &[String]) -> Result<()> { let _recorder = match self.recorder.as_mut() { @@ -378,28 +396,47 @@ impl TestExecutor { let y = args[1].parse::().unwrap_or(0); let z = args[2].parse::().unwrap_or(0); let block_pos = [x, y, z]; - - // Get block at position - if let Some(block_str) = self.bot.get_block(block_pos).await? { - let block_id = block::extract_block_id(&block_str); - let recorder = self.recorder.as_mut().unwrap(); - recorder.add_assertion(block_pos, &block_id); - - self.bot - .send_command(&format!( - "say Added assert at [{}, {}, {}] = {}", - block_pos[0], block_pos[1], block_pos[2], block_id - )) - .await?; + let mut blocks = Vec::new(); + if let Some(pos1) = self.pos1 { + let min_x = block_pos[0].min(pos1[0]); + let max_x = block_pos[0].max(pos1[0]); + let min_y = block_pos[1].min(pos1[1]); + let max_y = block_pos[1].max(pos1[1]); + let min_z = block_pos[2].min(pos1[2]); + let max_z = block_pos[2].max(pos1[2]); + + for x in min_x..=max_x { + for y in min_y..=max_y { + for z in min_z..=max_z { + blocks.push([x, y, z]); + } + } + } } else { - self.bot - .send_command(&format!( - "say No block found at [{}, {}, {}]", - block_pos[0], block_pos[1], block_pos[2] - )) - .await?; + blocks.push(block_pos) } + // Get block at position + for pos in blocks { + if let Some(block_str) = self.bot.get_block(pos).await? { + let block_id = block::extract_block_id(&block_str); + let recorder = self.recorder.as_mut().unwrap(); + recorder.add_assertion(pos, &block_id); + self.bot + .send_command(&format!( + "say Added assert at [{}, {}, {}] = {}", + pos[0], pos[1], pos[2], block_id + )) + .await?; + } else { + self.bot + .send_command(&format!( + "say No block found at [{}, {}, {}]", + pos[0], pos[1], pos[2] + )) + .await?; + } + } Ok(()) } @@ -552,4 +589,13 @@ impl TestExecutor { } Ok(()) } + + pub(super) async fn handle_record_sprint(&mut self, ticks: u32) -> Result<()> { + for _ in 0..ticks { + self.handle_record_tick().await?; + self.handle_record_assert(&self.last_assert_pos.clone()) + .await?; + } + Ok(()) + } } diff --git a/src/executor/mod.rs b/src/executor/mod.rs index 358f34a..184c92a 100644 --- a/src/executor/mod.rs +++ b/src/executor/mod.rs @@ -14,7 +14,6 @@ use flint_core::results::{ActionOutcome, AssertFailure, TestResult}; use flint_core::test_spec::{TestSpec, TimelineEntry}; use flint_core::timeline::TimelineAggregate; use std::io::Write; - pub use tick::{COMMAND_DELAY_MS, MIN_RETRY_DELAY_MS}; // Timing constants @@ -39,6 +38,8 @@ pub struct TestExecutor { verbose: bool, quiet: bool, fail_fast: bool, + pos1: Option<[i32; 3]>, + last_assert_pos: Vec, } impl Default for TestExecutor { @@ -50,6 +51,8 @@ impl Default for TestExecutor { verbose: false, quiet: false, fail_fast: false, + pos1: None, + last_assert_pos: vec![], } } } @@ -217,6 +220,16 @@ impl TestExecutor { self.handle_record_tick().await?; } + "!pos1" | "!pos" => { + if (!args.is_empty() && args.len() < 3) || args.len() > 3 { + self.bot + .send_command("say Usage: !assert ") + .await?; + continue; + } + self.handle_pos1(&args); + } + "!assert" => { if args.len() < 3 { self.bot @@ -224,8 +237,27 @@ impl TestExecutor { .await?; continue; } + self.last_assert_pos = args.clone(); self.handle_record_assert(&args).await?; } + "!sprint" => { + if args.len() != 1 { + self.bot.send_command("say Usage: !sprint ").await?; + continue; + } + let ticks = args[0].parse::().unwrap_or(1); + if ticks == 0 { + self.bot + .send_command("say Sprint ticks must be greater than 0") + .await?; + continue; + } + if self.last_assert_pos.is_empty() { + self.bot.send_command("say Please assert a position first, which should be used for each string (can be also a 3d area)").await?; + continue; + } + self.handle_record_sprint(ticks).await?; + } "!save" => { if self.handle_record_save().await? { diff --git a/src/executor/recorder/bounding_box.rs b/src/executor/recorder/bounding_box.rs index 241c2d0..082cfe8 100644 --- a/src/executor/recorder/bounding_box.rs +++ b/src/executor/recorder/bounding_box.rs @@ -17,7 +17,7 @@ impl BoundingBox { /// Expand the bounding box to include a position pub fn expand(&mut self, pos: [i32; 3]) { - for i in 0..3 { + for (i, _) in pos.iter().enumerate() { self.min[i] = self.min[i].min(pos[i]); self.max[i] = self.max[i].max(pos[i]); }