add play sound command
Its simple and there are many arguments missing but its works
This commit is contained in:
parent
daf3b29bb2
commit
6c78567a83
@ -1,14 +1,27 @@
|
|||||||
|
use heck::ToPascalCase;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
use crate::array_to_tokenstream;
|
use crate::{array_to_tokenstream, ident};
|
||||||
|
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
println!("cargo:rerun-if-changed=../assets/sounds.json");
|
println!("cargo:rerun-if-changed=../assets/sounds.json");
|
||||||
|
|
||||||
let sound: Vec<String> = serde_json::from_str(include_str!("../../assets/sounds.json"))
|
let sound: Vec<String> = serde_json::from_str(include_str!("../../assets/sounds.json"))
|
||||||
.expect("Failed to parse sounds.json");
|
.expect("Failed to parse sounds.json");
|
||||||
let variants = array_to_tokenstream(sound);
|
let variants = array_to_tokenstream(sound.clone());
|
||||||
|
|
||||||
|
let type_from_name = &sound
|
||||||
|
.iter()
|
||||||
|
.map(|sound| {
|
||||||
|
let id = &sound;
|
||||||
|
let name = ident(sound.to_pascal_case());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#id => Some(Self::#name),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<TokenStream>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
@ -16,5 +29,14 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
pub enum Sound {
|
pub enum Sound {
|
||||||
#variants
|
#variants
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sound {
|
||||||
|
pub fn from_name(name: &str) -> Option<Self> {
|
||||||
|
match name {
|
||||||
|
#type_from_name
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
pumpkin/src/command/args/arg_sound.rs
Normal file
74
pumpkin/src/command/args/arg_sound.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::sound::Sound;
|
||||||
|
use pumpkin_protocol::client::play::{
|
||||||
|
CommandSuggestion, ProtoCmdArgParser, ProtoCmdArgSuggestionType,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{command::dispatcher::CommandError, server::Server};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
super::{
|
||||||
|
args::{ArgumentConsumer, RawArgs},
|
||||||
|
CommandSender,
|
||||||
|
},
|
||||||
|
Arg, DefaultNameArgConsumer, FindArg, GetClientSideArgParser,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) struct SoundArgumentConsumer;
|
||||||
|
|
||||||
|
impl GetClientSideArgParser for SoundArgumentConsumer {
|
||||||
|
fn get_client_side_parser(&self) -> ProtoCmdArgParser {
|
||||||
|
ProtoCmdArgParser::ResourceLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_client_side_suggestion_type_override(&self) -> Option<ProtoCmdArgSuggestionType> {
|
||||||
|
Some(ProtoCmdArgSuggestionType::AvailableSounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ArgumentConsumer for SoundArgumentConsumer {
|
||||||
|
async fn consume<'a>(
|
||||||
|
&'a self,
|
||||||
|
_sender: &CommandSender<'a>,
|
||||||
|
_server: &'a Server,
|
||||||
|
args: &mut RawArgs<'a>,
|
||||||
|
) -> Option<Arg<'a>> {
|
||||||
|
let s = args.pop()?;
|
||||||
|
Some(Arg::Block(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn suggest<'a>(
|
||||||
|
&'a self,
|
||||||
|
_sender: &CommandSender<'a>,
|
||||||
|
_server: &'a Server,
|
||||||
|
_input: &'a str,
|
||||||
|
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultNameArgConsumer for SoundArgumentConsumer {
|
||||||
|
fn default_name(&self) -> String {
|
||||||
|
"available_sounds".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FindArg<'a> for SoundArgumentConsumer {
|
||||||
|
type Data = Sound;
|
||||||
|
|
||||||
|
fn find_arg(args: &'a super::ConsumedArgs, name: &str) -> Result<Self::Data, CommandError> {
|
||||||
|
match args.get(name) {
|
||||||
|
Some(Arg::Block(name)) => Sound::from_name(&name.replace("minecraft:", ""))
|
||||||
|
.map_or_else(
|
||||||
|
|| {
|
||||||
|
Err(CommandError::GeneralCommandIssue(format!(
|
||||||
|
"Sound {name} does not exist."
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
Result::Ok,
|
||||||
|
),
|
||||||
|
_ => Err(CommandError::InvalidConsumption(Some(name.to_string()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,7 @@ pub(crate) mod arg_position_block;
|
|||||||
pub(crate) mod arg_resource_location;
|
pub(crate) mod arg_resource_location;
|
||||||
pub(crate) mod arg_rotation;
|
pub(crate) mod arg_rotation;
|
||||||
pub(crate) mod arg_simple;
|
pub(crate) mod arg_simple;
|
||||||
|
pub(crate) mod arg_sound;
|
||||||
pub(crate) mod arg_textcomponent;
|
pub(crate) mod arg_textcomponent;
|
||||||
mod coordinate;
|
mod coordinate;
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ use CommandError::InvalidConsumption;
|
|||||||
|
|
||||||
const NAMES: [&str; 1] = ["deop"];
|
const NAMES: [&str; 1] = ["deop"];
|
||||||
const DESCRIPTION: &str = "Revokes operator status from a player.";
|
const DESCRIPTION: &str = "Revokes operator status from a player.";
|
||||||
const ARG_TARGET: &str = "player";
|
const ARG_TARGETS: &str = "targets";
|
||||||
|
|
||||||
struct DeopExecutor;
|
struct DeopExecutor;
|
||||||
|
|
||||||
@ -27,38 +27,37 @@ impl CommandExecutor for DeopExecutor {
|
|||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let mut config = OPERATOR_CONFIG.write().await;
|
let mut config = OPERATOR_CONFIG.write().await;
|
||||||
|
|
||||||
let Some(Arg::Players(targets)) = args.get(&ARG_TARGET) else {
|
let Some(Arg::Players(targets)) = args.get(&ARG_TARGETS) else {
|
||||||
return Err(InvalidConsumption(Some(ARG_TARGET.into())));
|
return Err(InvalidConsumption(Some(ARG_TARGETS.into())));
|
||||||
};
|
};
|
||||||
|
|
||||||
// from the command tree, the command can only be executed with one player
|
for player in targets {
|
||||||
let player = &targets[0];
|
if let Some(op_index) = config
|
||||||
|
.ops
|
||||||
|
.iter()
|
||||||
|
.position(|o| o.uuid == player.gameprofile.id)
|
||||||
|
{
|
||||||
|
config.ops.remove(op_index);
|
||||||
|
}
|
||||||
|
config.save();
|
||||||
|
|
||||||
if let Some(op_index) = config
|
player
|
||||||
.ops
|
.set_permission_lvl(
|
||||||
.iter()
|
pumpkin_util::PermissionLvl::Zero,
|
||||||
.position(|o| o.uuid == player.gameprofile.id)
|
&server.command_dispatcher,
|
||||||
{
|
)
|
||||||
config.ops.remove(op_index);
|
.await;
|
||||||
|
|
||||||
|
let player_name = &player.gameprofile.name;
|
||||||
|
let msg =
|
||||||
|
TextComponent::translate("commands.deop.success", [player_name.clone().into()]);
|
||||||
|
sender.send_message(msg).await;
|
||||||
}
|
}
|
||||||
config.save();
|
|
||||||
|
|
||||||
player
|
|
||||||
.set_permission_lvl(
|
|
||||||
pumpkin_util::PermissionLvl::Zero,
|
|
||||||
&server.command_dispatcher,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let player_name = &player.gameprofile.name;
|
|
||||||
let msg = TextComponent::translate("commands.deop.success", [player_name.clone().into()]);
|
|
||||||
sender.send_message(msg).await;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_command_tree() -> CommandTree {
|
pub fn init_command_tree() -> CommandTree {
|
||||||
CommandTree::new(NAMES, DESCRIPTION)
|
CommandTree::new(NAMES, DESCRIPTION)
|
||||||
.with_child(argument(ARG_TARGET, PlayersArgumentConsumer).execute(DeopExecutor))
|
.with_child(argument(ARG_TARGETS, PlayersArgumentConsumer).execute(DeopExecutor))
|
||||||
}
|
}
|
||||||
|
|||||||
49
pumpkin/src/command/commands/cmd_playsound.rs
Normal file
49
pumpkin/src/command/commands/cmd_playsound.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::sound::SoundCategory;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
|
use crate::command::{
|
||||||
|
args::{arg_sound::SoundArgumentConsumer, ConsumedArgs, FindArg},
|
||||||
|
tree::CommandTree,
|
||||||
|
tree_builder::argument,
|
||||||
|
CommandError, CommandExecutor, CommandSender,
|
||||||
|
};
|
||||||
|
const NAMES: [&str; 1] = ["playsound"];
|
||||||
|
|
||||||
|
const DESCRIPTION: &str = "Plays a sound at a position.";
|
||||||
|
|
||||||
|
const ARG_SOUND: &str = "sound";
|
||||||
|
|
||||||
|
struct SoundExecutor;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl CommandExecutor for SoundExecutor {
|
||||||
|
async fn execute<'a>(
|
||||||
|
&self,
|
||||||
|
sender: &mut CommandSender<'a>,
|
||||||
|
_server: &crate::server::Server,
|
||||||
|
args: &ConsumedArgs<'a>,
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let sound = SoundArgumentConsumer::find_arg(args, ARG_SOUND)?;
|
||||||
|
|
||||||
|
if let Some(player) = sender.as_player() {
|
||||||
|
let seed = thread_rng().gen::<f64>();
|
||||||
|
player
|
||||||
|
.play_sound(
|
||||||
|
sound as u16,
|
||||||
|
SoundCategory::Master,
|
||||||
|
&player.living_entity.entity.pos.load(),
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
seed,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_command_tree() -> CommandTree {
|
||||||
|
CommandTree::new(NAMES, DESCRIPTION)
|
||||||
|
.with_child(argument(ARG_SOUND, SoundArgumentConsumer).execute(SoundExecutor))
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ const NAMES: [&str; 1] = ["setblock"];
|
|||||||
const DESCRIPTION: &str = "Place a block.";
|
const DESCRIPTION: &str = "Place a block.";
|
||||||
|
|
||||||
const ARG_BLOCK: &str = "block";
|
const ARG_BLOCK: &str = "block";
|
||||||
const ARG_BLOCK_POS: &str = "position";
|
const ARG_BLOCK_POS: &str = "pos";
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub mod cmd_kill;
|
|||||||
pub mod cmd_list;
|
pub mod cmd_list;
|
||||||
pub mod cmd_me;
|
pub mod cmd_me;
|
||||||
pub mod cmd_op;
|
pub mod cmd_op;
|
||||||
|
pub mod cmd_playsound;
|
||||||
pub mod cmd_pumpkin;
|
pub mod cmd_pumpkin;
|
||||||
pub mod cmd_say;
|
pub mod cmd_say;
|
||||||
pub mod cmd_seed;
|
pub mod cmd_seed;
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use args::ConsumedArgs;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use commands::{
|
use commands::{
|
||||||
cmd_clear, cmd_deop, cmd_fill, cmd_gamemode, cmd_give, cmd_help, cmd_kick, cmd_kill, cmd_list,
|
cmd_clear, cmd_deop, cmd_fill, cmd_gamemode, cmd_give, cmd_help, cmd_kick, cmd_kill, cmd_list,
|
||||||
cmd_me, cmd_op, cmd_pumpkin, cmd_say, cmd_setblock, cmd_stop, cmd_teleport, cmd_time,
|
cmd_me, cmd_op, cmd_playsound, cmd_pumpkin, cmd_say, cmd_setblock, cmd_stop, cmd_teleport,
|
||||||
cmd_worldborder,
|
cmd_time, cmd_worldborder,
|
||||||
};
|
};
|
||||||
use dispatcher::CommandError;
|
use dispatcher::CommandError;
|
||||||
use pumpkin_util::math::vector3::Vector3;
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
@ -133,6 +133,7 @@ pub fn default_dispatcher() -> CommandDispatcher {
|
|||||||
dispatcher.register(cmd_op::init_command_tree(), PermissionLvl::Three);
|
dispatcher.register(cmd_op::init_command_tree(), PermissionLvl::Three);
|
||||||
dispatcher.register(cmd_deop::init_command_tree(), PermissionLvl::Three);
|
dispatcher.register(cmd_deop::init_command_tree(), PermissionLvl::Three);
|
||||||
dispatcher.register(cmd_me::init_command_tree(), PermissionLvl::Zero);
|
dispatcher.register(cmd_me::init_command_tree(), PermissionLvl::Zero);
|
||||||
|
dispatcher.register(cmd_playsound::init_command_tree(), PermissionLvl::Two);
|
||||||
|
|
||||||
dispatcher
|
dispatcher
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user