steel_core/command/builtins/
setblock.rs1use super::super::{
4 brigadier::{CommandNodeBuilder, CommandSyntaxError},
5 execution::{
6 CommandSource, SteelArgumentType, SteelCommandContext, SteelCommandRuntime, argument,
7 literal, placement_flags,
8 },
9 registration::CommandRegistration,
10};
11use super::execute::loaded_block_position;
12use steel_registry::blocks::block_state_ext::BlockStateExt;
13use steel_utils::Identifier;
14use steel_utils::translations::{COMMANDS_SETBLOCK_FAILED, COMMANDS_SETBLOCK_SUCCESS};
15use text_components::TextComponent;
16
17enum SetBlockMode {
19 Destroy,
21 Keep,
23 Replace,
25 Strict,
27}
28
29pub(super) fn registration() -> CommandRegistration<CommandSource> {
30 CommandRegistration::new(Identifier::vanilla_static("setblock"), |_| command())
31}
32
33fn command() -> CommandNodeBuilder<CommandSource, SteelCommandRuntime> {
34 literal("setblock").then(
35 argument("pos", SteelArgumentType::block_pos()).then(
36 argument("block", SteelArgumentType::block_state())
37 .executes(|c| set_block(c, SetBlockMode::Replace))
38 .then(literal("destroy").executes(|c| set_block(c, SetBlockMode::Destroy)))
39 .then(literal("keep").executes(|c| set_block(c, SetBlockMode::Keep)))
40 .then(literal("replace").executes(|c| set_block(c, SetBlockMode::Replace)))
41 .then(literal("strict").executes(|c| set_block(c, SetBlockMode::Strict))),
42 ),
43 )
44}
45
46fn set_block(
48 context: &SteelCommandContext<CommandSource>,
49 mode: SetBlockMode,
50) -> Result<i32, CommandSyntaxError> {
51 let block_pos = loaded_block_position(context, "pos")?;
52 let block = context.block_input("block")?;
53 let level = context.source().world();
54
55 if matches!(mode, SetBlockMode::Keep) && !level.get_block_state(block_pos).is_air() {
56 return Ok(set_block_failed(context.source()));
57 }
58
59 let place_needed = if matches!(mode, SetBlockMode::Destroy) {
60 level.destroy_block(block_pos, true);
61
62 !block.state().is_air() || !level.get_block_state(block_pos).is_air()
63 } else {
64 true
65 };
66
67 let strict = matches!(mode, SetBlockMode::Strict);
68 let old_state = level.get_block_state(block_pos);
69
70 if place_needed && !block.place(level, block_pos, placement_flags(strict))? {
71 return Ok(set_block_failed(context.source()));
72 }
73
74 if !strict {
75 level.update_neighbors_on_block_set(block_pos, old_state);
76 }
77
78 context.source().send_success(
79 &COMMANDS_SETBLOCK_SUCCESS
80 .message([
81 TextComponent::plain(format!("{}", block_pos.x())),
82 TextComponent::plain(format!("{}", block_pos.y())),
83 TextComponent::plain(format!("{}", block_pos.z())),
84 ])
85 .component(),
86 true,
87 );
88
89 Ok(1)
90}
91
92fn set_block_failed(source: &CommandSource) -> i32 {
93 source.send_failure(COMMANDS_SETBLOCK_FAILED.msg().component());
94
95 0
96}