diff --git a/src/bot.rs b/src/bot.rs index a434a9c..9873d26 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -595,15 +595,7 @@ impl TestBot { let current = active.slots.get(&slot); let desired = slots.get(&slot); if active.owner.is_none() || current != desired { - let slot_name = slot_to_minecraft_name(slot); - let command = match desired { - Some(item) => format!( - "item replace entity flintmc_testbot {} with {} {}", - slot_name, item.id, item.count - ), - None => format!("item replace entity flintmc_testbot {} with air", slot_name), - }; - self.send_command(&command)?; + self.send_command(&item_replace_command(slot, desired))?; } } @@ -777,7 +769,20 @@ impl TestBot { } } -pub fn slot_to_minecraft_name(slot: PlayerSlot) -> &'static str { +pub fn item_replace_command(slot: PlayerSlot, item: Option<&Item>) -> String { + let slot_name = slot_to_minecraft_name(slot); + match item { + Some(item) => format!( + "item replace entity flintmc_testbot {} with {} {}", + slot_name, + item.to_command(), + item.count + ), + None => format!("item replace entity flintmc_testbot {} with air", slot_name), + } +} + +fn slot_to_minecraft_name(slot: PlayerSlot) -> &'static str { match slot { PlayerSlot::Hotbar1 => "hotbar.0", PlayerSlot::Hotbar2 => "hotbar.1", diff --git a/src/executor/adapter.rs b/src/executor/adapter.rs index bc295e7..75cd0ed 100644 --- a/src/executor/adapter.rs +++ b/src/executor/adapter.rs @@ -1,4 +1,4 @@ -use crate::bot::{TestBot, slot_to_minecraft_name}; +use crate::bot::{TestBot, item_replace_command}; use crate::executor::block; use crate::executor::tick; use anyhow::Result; @@ -222,6 +222,9 @@ impl FlintWorld for MinecraftWorld { return Ok(Vec::new()); }; let selector = Self::entity_selector(entity); + if query_entity_count(&self.bot, &selector)? == 0 { + return Ok(Vec::new()); + } let values = query_entity_numbers(&self.bot, &selector, "Pos")?; let pos = values.get(..3).map(|pos| { [ @@ -583,15 +586,8 @@ impl MinecraftPlayer { } else { self.inventory.remove(&slot); } - let slot_name = slot_to_minecraft_name(slot); - let command = match item { - Some(item) => format!( - "item replace entity flintmc_testbot {} with {} {}", - slot_name, item.id, item.count - ), - None => format!("item replace entity flintmc_testbot {} with air", slot_name), - }; - self.bot.send_command_synced(&command)?; + self.bot + .send_command_synced(&item_replace_command(slot, item))?; self.bot.wait_for_inventory(&self.inventory)?; self.record_state(); Ok(()) diff --git a/src/main.rs b/src/main.rs index f063351..ae56451 100644 --- a/src/main.rs +++ b/src/main.rs @@ -353,6 +353,27 @@ fn main() -> Result<()> { return run_interactive_mode(&args, server, &mut executor, &mut test_loader); } + // Parse every file before connecting so a bad file reports all errors up front + let mut parsed_tests = Vec::with_capacity(test_files.len()); + let mut load_errors = 0; + for test_file in test_files { + match TestSpec::from_file(&test_file, false) { + Ok(test) => parsed_tests.push((test, test_file)), + Err(e) => { + load_errors += 1; + eprintln!( + "{} Failed to load test {}: {}", + "Error:".red().bold(), + test_file.display(), + e + ); + } + } + } + if load_errors > 0 { + anyhow::bail!("{load_errors} test file(s) failed to load"); + } + if verbose { println!("{} Connecting to {}...", "→".blue(), server); } @@ -370,8 +391,8 @@ fn main() -> Result<()> { } // Load all tests and run in chunks - let total_tests = test_files.len(); - let chunks: Vec<_> = test_files.chunks(CHUNK_SIZE).collect(); + let total_tests = parsed_tests.len(); + let chunks: Vec<_> = parsed_tests.chunks(CHUNK_SIZE).collect(); let total_chunks = chunks.len(); if verbose { @@ -401,23 +422,10 @@ fn main() -> Result<()> { } let mut tests_with_offsets = Vec::new(); - let mut chunk_specs = Vec::new(); - for test_file in chunk.iter() { - match TestSpec::from_file(test_file, false) { - Ok(test) => { - test_specs_map.insert(test.name.clone(), (test.clone(), test_file.clone())); - chunk_specs.push(test); - } - Err(e) => { - eprintln!( - "{} Failed to load test {}: {}", - "Error:".red().bold(), - test_file.display(), - e - ); - std::process::exit(1); - } - } + let mut chunk_specs = Vec::with_capacity(chunk.len()); + for (test, test_file) in chunk.iter() { + test_specs_map.insert(test.name.clone(), (test.clone(), test_file.clone())); + chunk_specs.push(test.clone()); } let config_batches = group_tests_by_world_config(chunk_specs);