Pumpkin/pumpkin/src/command/commands/teleport.rs
2025-04-03 18:24:19 +02:00

268 lines
8.6 KiB
Rust

use async_trait::async_trait;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_util::text::TextComponent;
use crate::command::CommandError;
use crate::command::args::ConsumedArgs;
use crate::command::args::FindArg;
use crate::command::args::entities::EntitiesArgumentConsumer;
use crate::command::args::entity::EntityArgumentConsumer;
use crate::command::args::position_3d::Position3DArgumentConsumer;
use crate::command::args::rotation::RotationArgumentConsumer;
use crate::command::tree::CommandTree;
use crate::command::tree::builder::{argument, literal};
use crate::command::{CommandExecutor, CommandSender};
const NAMES: [&str; 2] = ["teleport", "tp"];
const DESCRIPTION: &str = "Teleports entities, including players."; // todo
/// position
const ARG_LOCATION: &str = "location";
/// single entity
const ARG_DESTINATION: &str = "destination";
/// multiple entities
const ARG_TARGETS: &str = "targets";
/// rotation: yaw/pitch
const ARG_ROTATION: &str = "rotation";
/// single entity
const ARG_FACING_ENTITY: &str = "facingEntity";
/// position
const ARG_FACING_LOCATION: &str = "facingLocation";
fn yaw_pitch_facing_position(
looking_from: &Vector3<f64>,
looking_towards: &Vector3<f64>,
) -> (f32, f32) {
let direction_vector = (looking_towards.sub(looking_from)).normalize();
let yaw_radians = -direction_vector.x.atan2(direction_vector.z);
let pitch_radians = (-direction_vector.y).asin();
let yaw_degrees = yaw_radians.to_degrees();
let pitch_degrees = pitch_radians.to_degrees();
(yaw_degrees as f32, pitch_degrees as f32)
}
struct EntitiesToEntityExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToEntityExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
let pos = destination.living_entity.entity.pos.load();
for target in targets {
let yaw = target.living_entity.entity.yaw.load();
let pitch = target.living_entity.entity.pitch.load();
target.living_entity.entity.teleport(pos, yaw, pitch).await;
}
Ok(())
}
}
struct EntitiesToPosFacingPosExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosFacingPosExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
let facing_pos = Position3DArgumentConsumer::find_arg(args, ARG_FACING_LOCATION)?;
let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_pos);
for target in targets {
target.living_entity.entity.teleport(pos, yaw, pitch).await;
}
Ok(())
}
}
struct EntitiesToPosFacingEntityExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosFacingEntityExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
let facing_entity = &EntityArgumentConsumer::find_arg(args, ARG_FACING_ENTITY)?
.living_entity
.entity;
let (yaw, pitch) = yaw_pitch_facing_position(&pos, &facing_entity.pos.load());
for target in targets {
target.living_entity.entity.teleport(pos, yaw, pitch).await;
}
Ok(())
}
}
struct EntitiesToPosWithRotationExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosWithRotationExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
let (yaw, pitch) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?;
for target in targets {
target.living_entity.entity.teleport(pos, yaw, pitch).await;
}
Ok(())
}
}
struct EntitiesToPosExecutor;
#[async_trait]
impl CommandExecutor for EntitiesToPosExecutor {
async fn execute<'a>(
&self,
_sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let targets = EntitiesArgumentConsumer::find_arg(args, ARG_TARGETS)?;
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
for target in targets {
let yaw = target.living_entity.entity.yaw.load();
let pitch = target.living_entity.entity.pitch.load();
target.living_entity.entity.teleport(pos, yaw, pitch).await;
}
Ok(())
}
}
struct SelfToEntityExecutor;
#[async_trait]
impl CommandExecutor for SelfToEntityExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
let destination = EntityArgumentConsumer::find_arg(args, ARG_DESTINATION)?;
let pos = destination.living_entity.entity.pos.load();
match sender {
CommandSender::Player(player) => {
let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load();
player.living_entity.entity.teleport(pos, yaw, pitch).await;
}
_ => {
sender
.send_message(TextComponent::translate("permissions.requires.player", []))
.await;
}
}
Ok(())
}
}
struct SelfToPosExecutor;
#[async_trait]
impl CommandExecutor for SelfToPosExecutor {
async fn execute<'a>(
&self,
sender: &mut CommandSender,
_server: &crate::server::Server,
args: &ConsumedArgs<'a>,
) -> Result<(), CommandError> {
match sender {
CommandSender::Player(player) => {
let pos = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
let yaw = player.living_entity.entity.yaw.load();
let pitch = player.living_entity.entity.pitch.load();
player.living_entity.entity.teleport(pos, yaw, pitch).await;
}
_ => {
sender
.send_message(TextComponent::translate("permissions.requires.player", []))
.await;
}
}
Ok(())
}
}
pub fn init_command_tree() -> CommandTree {
CommandTree::new(NAMES, DESCRIPTION)
.then(argument(ARG_LOCATION, Position3DArgumentConsumer).execute(SelfToPosExecutor))
.then(argument(ARG_DESTINATION, EntityArgumentConsumer).execute(SelfToEntityExecutor))
.then(
argument(ARG_TARGETS, EntitiesArgumentConsumer)
.then(
argument(ARG_LOCATION, Position3DArgumentConsumer)
.execute(EntitiesToPosExecutor)
.then(
argument(ARG_ROTATION, RotationArgumentConsumer)
.execute(EntitiesToPosWithRotationExecutor),
)
.then(
literal("facing")
.then(
literal("entity").then(
argument(ARG_FACING_ENTITY, EntityArgumentConsumer)
.execute(EntitiesToPosFacingEntityExecutor),
),
)
.then(
argument(ARG_FACING_LOCATION, Position3DArgumentConsumer)
.execute(EntitiesToPosFacingPosExecutor),
),
),
)
.then(
argument(ARG_DESTINATION, EntityArgumentConsumer)
.execute(EntitiesToEntityExecutor),
),
)
}