feat(command): add dialog command
This commit is contained in:
parent
a877d16aeb
commit
75d1bc5a88
@ -2,7 +2,26 @@ use pumpkin_util::text::TextComponent;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DialogNBT<'a>(pub &'a Dialog);
|
||||
pub struct DialogNBT<'a>(pub DialogNBTSource<'a>);
|
||||
|
||||
impl<'a> DialogNBT<'a> {
|
||||
#[must_use]
|
||||
pub const fn from_dialog(dialog: &'a Dialog) -> Self {
|
||||
Self(DialogNBTSource::Struct(dialog))
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn from_nbt(compound: &'a pumpkin_nbt::compound::NbtCompound) -> Self {
|
||||
Self(DialogNBTSource::Nbt(compound))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DialogNBTSource<'a> {
|
||||
Struct(&'a Dialog),
|
||||
Nbt(&'a pumpkin_nbt::compound::NbtCompound),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Dialog {
|
||||
|
||||
57
pumpkin/src/command/argument_types/dialog.rs
Normal file
57
pumpkin/src/command/argument_types/dialog.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_util::identifier::Identifier;
|
||||
|
||||
use crate::command::{
|
||||
argument_types::{
|
||||
FromStringReader,
|
||||
argument_type::{ArgumentType, JavaClientArgumentType},
|
||||
nbt::NbtCompoundArgumentType,
|
||||
},
|
||||
context::command_context::CommandContext,
|
||||
errors::command_syntax_error::CommandSyntaxError,
|
||||
string_reader::StringReader,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum DialogArg {
|
||||
Id(Identifier),
|
||||
Nbt(NbtCompound),
|
||||
}
|
||||
|
||||
pub struct DialogArgumentType;
|
||||
|
||||
impl ArgumentType for DialogArgumentType {
|
||||
type Item = DialogArg;
|
||||
|
||||
fn parse(&self, reader: &mut StringReader) -> Result<Self::Item, CommandSyntaxError> {
|
||||
if reader.peek() == Some('{') {
|
||||
let compound = NbtCompoundArgumentType.parse(reader)?;
|
||||
Ok(DialogArg::Nbt(compound))
|
||||
} else {
|
||||
let id = Identifier::from_reader(reader)?;
|
||||
Ok(DialogArg::Id(id))
|
||||
}
|
||||
}
|
||||
|
||||
fn client_side_parser(&'_ self) -> JavaClientArgumentType {
|
||||
JavaClientArgumentType::Dialog
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<String> {
|
||||
examples!(
|
||||
"minecraft:server_links",
|
||||
"custom:my_dialog",
|
||||
"{type:\"minecraft:notice\",title:\"Hello\"}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl DialogArgumentType {
|
||||
/// Returns the parsed [`DialogArg`] from the name of the argument.
|
||||
pub fn get<'a>(
|
||||
context: &'a CommandContext,
|
||||
name: &'_ str,
|
||||
) -> Result<&'a DialogArg, CommandSyntaxError> {
|
||||
context.get_argument(name)
|
||||
}
|
||||
}
|
||||
@ -221,6 +221,7 @@ pub mod attribute;
|
||||
pub mod block;
|
||||
pub mod coordinates;
|
||||
pub mod core;
|
||||
pub mod dialog;
|
||||
pub mod entity;
|
||||
pub mod entity_anchor;
|
||||
pub mod entity_selector;
|
||||
|
||||
110
pumpkin/src/command/commands/dialog.rs
Normal file
110
pumpkin/src/command/commands/dialog.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use crate::command::argument_builder::{ArgumentBuilder, argument, command, literal};
|
||||
use crate::command::argument_types::dialog::{DialogArg, DialogArgumentType};
|
||||
use crate::command::argument_types::entity::EntityArgumentType;
|
||||
use crate::command::context::command_context::CommandContext;
|
||||
use crate::command::errors::error_types::LiteralCommandErrorType;
|
||||
use crate::command::node::dispatcher::CommandDispatcher;
|
||||
use crate::command::node::{CommandExecutor, CommandExecutorResult};
|
||||
use pumpkin_protocol::IdOr;
|
||||
use pumpkin_protocol::java::client::dialog::DialogNBT;
|
||||
use pumpkin_protocol::java::client::play::{CPlayClearDialog, CPlayShowDialog};
|
||||
use pumpkin_util::PermissionLvl;
|
||||
use pumpkin_util::permission::{Permission, PermissionDefault, PermissionRegistry};
|
||||
use pumpkin_util::text::TextComponent;
|
||||
|
||||
const DESCRIPTION: &str = "Manages player dialog screens.";
|
||||
const PERMISSION: &str = "minecraft:command.dialog";
|
||||
|
||||
const ARG_TARGETS: &str = "targets";
|
||||
const ARG_DIALOG: &str = "dialog";
|
||||
|
||||
struct DialogClearExecutor;
|
||||
|
||||
impl CommandExecutor for DialogClearExecutor {
|
||||
fn execute<'a>(&'a self, context: &'a CommandContext) -> CommandExecutorResult<'a> {
|
||||
Box::pin(async move {
|
||||
let targets = EntityArgumentType::get_players(context, ARG_TARGETS).await?;
|
||||
|
||||
let count = targets.len();
|
||||
let packet = CPlayClearDialog::new();
|
||||
for player in &targets {
|
||||
player.client.send_packet_now(&packet).await;
|
||||
}
|
||||
|
||||
let msg = if count == 1 {
|
||||
TextComponent::text(format!(
|
||||
"Cleared dialog for {}",
|
||||
targets[0].gameprofile.name
|
||||
))
|
||||
} else {
|
||||
TextComponent::text(format!("Cleared dialogs for {count} players"))
|
||||
};
|
||||
context.source.send_feedback(msg, true).await;
|
||||
|
||||
Ok(count as i32)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static REGISTRY_ERROR: LiteralCommandErrorType = LiteralCommandErrorType::new(
|
||||
"Registry-defined dialogs are not yet supported. Please specify the dialog inline using SNBT.",
|
||||
);
|
||||
|
||||
struct DialogShowExecutor;
|
||||
|
||||
impl CommandExecutor for DialogShowExecutor {
|
||||
fn execute<'a>(&'a self, context: &'a CommandContext) -> CommandExecutorResult<'a> {
|
||||
Box::pin(async move {
|
||||
let targets = EntityArgumentType::get_players(context, ARG_TARGETS).await?;
|
||||
let dialog_arg = DialogArgumentType::get(context, ARG_DIALOG)?;
|
||||
|
||||
match dialog_arg {
|
||||
DialogArg::Nbt(compound) => {
|
||||
let count = targets.len();
|
||||
let dialog_nbt = DialogNBT::from_nbt(compound);
|
||||
let packet = CPlayShowDialog::new(IdOr::Value(dialog_nbt));
|
||||
|
||||
for player in &targets {
|
||||
player.client.send_packet_now(&packet).await;
|
||||
}
|
||||
|
||||
let msg = if count == 1 {
|
||||
TextComponent::text(format!(
|
||||
"Showed dialog to {}",
|
||||
targets[0].gameprofile.name
|
||||
))
|
||||
} else {
|
||||
TextComponent::text(format!("Showed dialog to {count} players"))
|
||||
};
|
||||
context.source.send_feedback(msg, true).await;
|
||||
|
||||
Ok(count as i32)
|
||||
}
|
||||
DialogArg::Id(_id) => Err(REGISTRY_ERROR.create_without_context()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(dispatcher: &mut CommandDispatcher, registry: &mut PermissionRegistry) {
|
||||
registry.register_permission_or_panic(Permission::new(
|
||||
PERMISSION,
|
||||
DESCRIPTION,
|
||||
PermissionDefault::Op(PermissionLvl::Two),
|
||||
));
|
||||
|
||||
dispatcher.register(
|
||||
command("dialog", DESCRIPTION)
|
||||
.requires(PERMISSION)
|
||||
.then(literal("clear").then(
|
||||
argument(ARG_TARGETS, EntityArgumentType::Players).executes(DialogClearExecutor),
|
||||
))
|
||||
.then(
|
||||
literal("show").then(
|
||||
argument(ARG_TARGETS, EntityArgumentType::Players).then(
|
||||
argument(ARG_DIALOG, DialogArgumentType).executes(DialogShowExecutor),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -18,6 +18,7 @@ mod damage;
|
||||
mod data;
|
||||
pub mod defaultgamemode;
|
||||
mod deop;
|
||||
mod dialog;
|
||||
mod difficulty;
|
||||
mod effect;
|
||||
mod enchant;
|
||||
@ -165,6 +166,7 @@ pub async fn default_dispatcher(
|
||||
|
||||
banlist::register(&mut dispatcher, registry);
|
||||
difficulty::register(&mut dispatcher, registry);
|
||||
dialog::register(&mut dispatcher, registry);
|
||||
help::register(&mut dispatcher, registry);
|
||||
kill::register(&mut dispatcher, registry);
|
||||
op::register(&mut dispatcher, registry);
|
||||
|
||||
@ -1763,7 +1763,9 @@ impl pumpkin::plugin::player::HostJavaPlayer for PluginHostState {
|
||||
client
|
||||
.send_packet_now(
|
||||
&pumpkin_protocol::java::client::config::CConfigShowDialog::new(
|
||||
pumpkin_protocol::IdOr::Value(DialogNBT(&protocol_dialog)),
|
||||
pumpkin_protocol::IdOr::Value(DialogNBT::from_dialog(
|
||||
&protocol_dialog,
|
||||
)),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
@ -1772,7 +1774,9 @@ impl pumpkin::plugin::player::HostJavaPlayer for PluginHostState {
|
||||
client
|
||||
.send_packet_now(
|
||||
&pumpkin_protocol::java::client::play::CPlayShowDialog::new(
|
||||
pumpkin_protocol::IdOr::Value(DialogNBT(&protocol_dialog)),
|
||||
pumpkin_protocol::IdOr::Value(DialogNBT::from_dialog(
|
||||
&protocol_dialog,
|
||||
)),
|
||||
),
|
||||
)
|
||||
.await;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user