Pumpkin/pumpkin/src/command/commands/setblock.rs
Alexander Medvedev be44ccc8df Don't require server when spawning a entity
Makes it much simpler
2025-03-02 16:05:31 +01:00

100 lines
3.1 KiB
Rust

use async_trait::async_trait;
use pumpkin_util::text::TextComponent;
use crate::command::args::block::BlockArgumentConsumer;
use crate::command::args::position_block::BlockPosArgumentConsumer;
use crate::command::args::{ConsumedArgs, FindArg};
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandError, CommandExecutor, CommandSender};
const NAMES: [&str; 1] = ["setblock"];
const DESCRIPTION: &str = "Place a block.";
const ARG_BLOCK: &str = "block";
const ARG_BLOCK_POS: &str = "pos";
#[derive(Clone, Copy)]
enum Mode {
/// with particles + item drops
Destroy,
/// only replaces air
Keep,
/// default; without particles
Replace,
}
struct Executor(Mode);
#[async_trait]
impl CommandExecutor for Executor {
async fn execute<'a>(
&self,
sender: &mut CommandSender<'a>,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let block = BlockArgumentConsumer::find_arg(args, ARG_BLOCK)?;
let block_state_id = block.default_state_id;
let pos = BlockPosArgumentConsumer::find_arg(args, ARG_BLOCK_POS)?;
let mode = self.0;
// TODO: allow console to use the command (seed sender.world)
let world = sender
.world()
.await
.ok_or(CommandError::InvalidRequirement)?;
let success = match mode {
Mode::Destroy => {
world.clone().break_block(&pos, None, false).await;
world.set_block_state(&pos, block_state_id).await;
true
}
Mode::Replace => {
world.set_block_state(&pos, block_state_id).await;
true
}
Mode::Keep => match world.get_block_state(&pos).await {
Ok(old_state) if old_state.air => {
world.set_block_state(&pos, block_state_id).await;
true
}
Ok(_) => false,
Err(e) => return Err(CommandError::OtherPumpkin(e.into())),
},
};
sender
.send_message(if success {
TextComponent::translate(
"commands.setblock.success",
[
TextComponent::text(pos.0.x.to_string()),
TextComponent::text(pos.0.y.to_string()),
TextComponent::text(pos.0.z.to_string()),
],
)
} else {
TextComponent::translate("commands.setblock.failed", [])
})
.await;
Ok(())
}
}
pub fn init_command_tree() -> CommandTree {
CommandTree::new(NAMES, DESCRIPTION).then(
argument(ARG_BLOCK_POS, BlockPosArgumentConsumer).then(
argument(ARG_BLOCK, BlockArgumentConsumer)
.then(literal("replace").execute(Executor(Mode::Replace)))
.then(literal("destroy").execute(Executor(Mode::Destroy)))
.then(literal("keep").execute(Executor(Mode::Keep)))
.execute(Executor(Mode::Replace)),
),
)
}