From a6efe7ec7a253440ee4d5636d0ca0a8dc6ccf8cf Mon Sep 17 00:00:00 2001 From: SomeYellowGuy <30015613+SomeYellowGuy@users.noreply.github.com> Date: Fri, 27 Mar 2026 03:15:33 +0530 Subject: [PATCH] feat(command): reimplement `/seed` (#1919) * reimplemented /seed * used `send_feedback` instead --- pumpkin-util/src/text/mod.rs | 9 +++ pumpkin/src/command/commands/mod.rs | 9 +-- pumpkin/src/command/commands/seed.rs | 94 +++++++++++++++------------- 3 files changed, 60 insertions(+), 52 deletions(-) diff --git a/pumpkin-util/src/text/mod.rs b/pumpkin-util/src/text/mod.rs index 8b136de36..dd80389fa 100644 --- a/pumpkin-util/src/text/mod.rs +++ b/pumpkin-util/src/text/mod.rs @@ -735,6 +735,15 @@ impl TextComponent { self } + /// Wraps a component in square brackets. + /// + /// # Returns + /// The new component. + #[must_use] + pub fn wrap_in_square_brackets(self) -> Self { + Self::translate("chat.square_brackets", [self]) + } + /// Makes the text bold. /// /// # Returns diff --git a/pumpkin/src/command/commands/mod.rs b/pumpkin/src/command/commands/mod.rs index d2a5773cc..71f2cc57d 100644 --- a/pumpkin/src/command/commands/mod.rs +++ b/pumpkin/src/command/commands/mod.rs @@ -92,7 +92,6 @@ pub async fn default_dispatcher( dispatcher.register(enchant::init_command_tree(), "minecraft:command.enchant"); dispatcher.register(clear::init_command_tree(), "minecraft:command.clear"); dispatcher.register(setblock::init_command_tree(), "minecraft:command.setblock"); - dispatcher.register(seed::init_command_tree(), "minecraft:command.seed"); dispatcher.register(tps::init_command_tree(), "pumpkin:command.tps"); dispatcher.register(fill::init_command_tree(), "minecraft:command.fill"); dispatcher.register( @@ -165,6 +164,7 @@ pub async fn default_dispatcher( }; help::register(&mut dispatcher, registry); + seed::register(&mut dispatcher, registry); dispatcher } @@ -274,13 +274,6 @@ fn register_level_2_permissions(registry: &mut PermissionRegistry) { PermissionDefault::Op(PermissionLvl::Two), )) .unwrap(); - registry - .register_permission(Permission::new( - "minecraft:command.seed", - "Displays the world seed", - PermissionDefault::Op(PermissionLvl::Two), - )) - .unwrap(); registry .register_permission(Permission::new( "minecraft:command.fill", diff --git a/pumpkin/src/command/commands/seed.rs b/pumpkin/src/command/commands/seed.rs index 04cbd0682..b02e1dc91 100644 --- a/pumpkin/src/command/commands/seed.rs +++ b/pumpkin/src/command/commands/seed.rs @@ -1,62 +1,68 @@ -use crate::command::CommandResult; -use crate::command::{ - CommandError, CommandExecutor, CommandSender, args::ConsumedArgs, tree::CommandTree, -}; +use crate::command::argument_builder::{ArgumentBuilder, command}; +use crate::command::context::command_context::CommandContext; +use crate::command::node::dispatcher::CommandDispatcher; +use crate::command::node::{CommandExecutor, CommandExecutorResult}; +use pumpkin_data::translation::{CHAT_COPY_CLICK, COMMANDS_SEED_SUCCESS}; +use pumpkin_util::PermissionLvl; +use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry}; use pumpkin_util::text::click::ClickEvent; use pumpkin_util::text::hover::HoverEvent; use pumpkin_util::text::{TextComponent, color::NamedColor}; use std::borrow::Cow; -const NAMES: [&str; 1] = ["seed"]; - const DESCRIPTION: &str = "Displays the world seed."; +const PERMISSION: &str = "minecraft:command.seed"; -struct Executor; +struct SeedCommandExecutor; -impl CommandExecutor for Executor { - fn execute<'a>( - &'a self, - sender: &'a CommandSender, - server: &'a crate::server::Server, - _args: &'a ConsumedArgs<'a>, - ) -> CommandResult<'a> { +fn create_copy_on_click_text(content: String) -> TextComponent { + TextComponent::translate( + COMMANDS_SEED_SUCCESS, + [TextComponent::wrap_in_square_brackets( + TextComponent::text(content.clone()) + .hover_event(HoverEvent::show_text(TextComponent::translate( + CHAT_COPY_CLICK, + [], + ))) + .click_event(ClickEvent::CopyToClipboard { + value: Cow::from(content), + }) + .color_named(NamedColor::Green), + )], + ) +} + +impl CommandExecutor for SeedCommandExecutor { + fn execute<'a>(&'a self, context: &'a CommandContext) -> CommandExecutorResult<'a> { Box::pin(async move { - let seed = match sender { - CommandSender::Player(player) => { - player.living_entity.entity.world.load().level.seed.0 - } - // TODO: Maybe ask player for world, or get the current world - _ => match server.worlds.load().first() { - Some(world) => world.level.seed.0, - None => { - return Err(CommandError::CommandFailed(TextComponent::text( - "Unable to get Seed", - ))); - } - }, - } as i64; + let seed = context.world().level.seed.0; let seed_string = seed.to_string(); - sender - .send_message(TextComponent::translate( - "commands.seed.success", - [TextComponent::text(seed_string.clone()) - .hover_event(HoverEvent::show_text(TextComponent::translate( - Cow::from("chat.copy.click"), - [], - ))) - .click_event(ClickEvent::CopyToClipboard { - value: Cow::from(seed_string), - }) - .color_named(NamedColor::Green)], - )) + context + .source + .send_feedback(create_copy_on_click_text(seed_string), false) .await; - Ok(seed.clamp(i32::MIN as i64, i32::MAX as i64) as i32) + Ok(seed as i32) }) } } -pub fn init_command_tree() -> CommandTree { - CommandTree::new(NAMES, DESCRIPTION).execute(Executor) +pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) { + registry + .register_permission(Permission::new( + PERMISSION, + DESCRIPTION, + // For integrated servers, the permission level is 0, + // but Pumpkin is always a dedicated server. For dedicated servers, + // /seed is limited to level 2. + PermissionDefault::Op(PermissionLvl::Two), + )) + .expect("Permission should have registered successfully"); + + dispatcher.register( + command("seed", DESCRIPTION) + .requires(PERMISSION) + .executes(SeedCommandExecutor), + ); }