From 9fbaee04d67a268bc5fec1c3277afb4bf000dea8 Mon Sep 17 00:00:00 2001 From: qwixck <90417400+qwixck@users.noreply.github.com> Date: Mon, 19 May 2025 18:15:51 +0300 Subject: [PATCH] Add more console support for some commands (#821) * add console command support * refactor * fix: fixed an rare attempt to subtract with overflow case --- pumpkin/src/command/commands/particle.rs | 58 ++++++++++++++++-------- pumpkin/src/command/commands/setblock.rs | 17 ++++--- pumpkin/src/command/commands/summon.rs | 55 +++++++++++----------- pumpkin/src/command/commands/weather.rs | 14 ++++-- pumpkin/src/world/portal/mod.rs | 6 ++- 5 files changed, 90 insertions(+), 60 deletions(-) diff --git a/pumpkin/src/command/commands/particle.rs b/pumpkin/src/command/commands/particle.rs index e1af1d636..a2013cbac 100644 --- a/pumpkin/src/command/commands/particle.rs +++ b/pumpkin/src/command/commands/particle.rs @@ -27,7 +27,7 @@ impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender, - _server: &crate::server::Server, + server: &crate::server::Server, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { let particle = ParticleArgumentConsumer::find_arg(args, ARG_NAME)?; @@ -36,26 +36,44 @@ impl CommandExecutor for Executor { let speed = BoundedNumArgumentConsumer::::find_arg(args, ARG_SPEED); let count = BoundedNumArgumentConsumer::::find_arg(args, ARG_COUNT); - // TODO: Make this work in console - if let Some(player) = sender.as_player() { - let pos = pos.unwrap_or(player.living_entity.entity.pos.load()); - let delta = delta.unwrap_or(Vector3::new(0.0, 0.0, 0.0)); - let delta: Vector3 = Vector3::new(delta.x as f32, delta.y as f32, delta.z as f32); - let speed = speed.unwrap_or(Ok(0.0))?; - let count = count.unwrap_or(Ok(0))?; + let delta = delta.unwrap_or(Vector3::new(0.0, 0.0, 0.0)); + let delta: Vector3 = Vector3::new(delta.x as f32, delta.y as f32, delta.z as f32); + let speed = speed.unwrap_or(Ok(0.0))?; + let count = count.unwrap_or(Ok(0))?; + let (world, pos) = match sender { + CommandSender::Console | CommandSender::Rcon(_) => { + let guard = server.worlds.read().await; + let world = guard + .first() + .cloned() + .ok_or(CommandError::InvalidRequirement)?; + let info = &world.level_info; + // default position for spawning a player, in this case for particle + let pos = pos.unwrap_or(Vector3::new( + f64::from(info.spawn_x), + f64::from(info.spawn_y) + 1.0, + f64::from(info.spawn_z), + )); - player - .world() - .await - .spawn_particle(pos, delta, speed, count, *particle) - .await; - sender - .send_message(TextComponent::translate( - "commands.particle.success", - [TextComponent::text(format!("{particle:?}"))], - )) - .await; - } + (world, pos) + } + CommandSender::Player(player) => { + let pos = pos.unwrap_or(player.living_entity.entity.pos.load()); + + (player.world().await, pos) + } + }; + + world + .spawn_particle(pos, delta, speed, count, *particle) + .await; + + sender + .send_message(TextComponent::translate( + "commands.particle.success", + [TextComponent::text(format!("{particle:?}"))], + )) + .await; Ok(()) } diff --git a/pumpkin/src/command/commands/setblock.rs b/pumpkin/src/command/commands/setblock.rs index eb3e89d5b..526ddff69 100644 --- a/pumpkin/src/command/commands/setblock.rs +++ b/pumpkin/src/command/commands/setblock.rs @@ -35,19 +35,24 @@ impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender, - _server: &crate::server::Server, + 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 world = match sender { + CommandSender::Console | CommandSender::Rcon(_) => { + let guard = server.worlds.read().await; + guard + .first() + .cloned() + .ok_or(CommandError::InvalidRequirement)? + } + CommandSender::Player(player) => player.world().await, + }; let success = match mode { Mode::Destroy => { world diff --git a/pumpkin/src/command/commands/summon.rs b/pumpkin/src/command/commands/summon.rs index 704da6607..183853d5d 100644 --- a/pumpkin/src/command/commands/summon.rs +++ b/pumpkin/src/command/commands/summon.rs @@ -32,39 +32,38 @@ impl CommandExecutor for Executor { ) -> Result<(), CommandError> { let entity = SummonableEntitiesArgumentConsumer::find_arg(args, ARG_ENTITY)?; let pos = Position3DArgumentConsumer::find_arg(args, ARG_POS); - - match sender { + let (world, pos) = match sender { CommandSender::Console | CommandSender::Rcon(_) => { - if let Some(world) = server.worlds.read().await.first() { - let info = &world.level_info; - // default position for spawning a player, in this case for mob - let pos = pos.unwrap_or(Vector3::new( - f64::from(info.spawn_x), - f64::from(info.spawn_y) + 1.0, - f64::from(info.spawn_z), - )); - let mob = mob::from_type(entity, pos, world).await; - world.spawn_entity(mob).await; - sender - .send_message(TextComponent::translate( - "commands.summon.success", - [TextComponent::text(format!("{entity:?}"))], - )) - .await; - } + let guard = server.worlds.read().await; + let world = guard + .first() + .cloned() + .ok_or(CommandError::InvalidRequirement)?; + let info = &world.level_info; + // default position for spawning a player, in this case for mob + let pos = pos.unwrap_or(Vector3::new( + f64::from(info.spawn_x), + f64::from(info.spawn_y) + 1.0, + f64::from(info.spawn_z), + )); + + (world, pos) } CommandSender::Player(player) => { let pos = pos.unwrap_or(player.living_entity.entity.pos.load()); - let mob = mob::from_type(entity, pos, &player.world().await).await; - player.world().await.spawn_entity(mob).await; - sender - .send_message(TextComponent::translate( - "commands.summon.success", - [TextComponent::text(format!("{entity:?}"))], - )) - .await; + + (player.world().await, pos) } - } + }; + let mob = mob::from_type(entity, pos, &world).await; + world.spawn_entity(mob).await; + + sender + .send_message(TextComponent::translate( + "commands.summon.success", + [TextComponent::text(format!("{entity:?}"))], + )) + .await; Ok(()) } diff --git a/pumpkin/src/command/commands/weather.rs b/pumpkin/src/command/commands/weather.rs index 336aa4883..37e2e6244 100644 --- a/pumpkin/src/command/commands/weather.rs +++ b/pumpkin/src/command/commands/weather.rs @@ -27,14 +27,18 @@ impl CommandExecutor for Executor { async fn execute<'a>( &self, sender: &mut CommandSender, - _server: &crate::server::Server, + server: &crate::server::Server, args: &ConsumedArgs<'a>, ) -> Result<(), CommandError> { - let world = sender - .world() - .await - .ok_or(CommandError::InvalidRequirement)?; let duration = TimeArgumentConsumer::find_arg(args, ARG_DURATION).unwrap_or(6000); + let world = { + let guard = server.worlds.read().await; + + guard + .first() + .cloned() + .ok_or(CommandError::InvalidRequirement)? + }; let mut weather = world.weather.lock().await; match self.mode { diff --git a/pumpkin/src/world/portal/mod.rs b/pumpkin/src/world/portal/mod.rs index 2a6b6af12..4d23c0439 100644 --- a/pumpkin/src/world/portal/mod.rs +++ b/pumpkin/src/world/portal/mod.rs @@ -31,7 +31,11 @@ impl PortalManager { self.ticks_in_portal += 1; self.ticks_in_portal >= self.portal_delay } else { - self.ticks_in_portal -= 4; + if self.ticks_in_portal < 4 { + self.ticks_in_portal = 0; + } else { + self.ticks_in_portal -= 4; + } false } }