Refactor Entity
This commit is contained in:
parent
cd25387a4b
commit
2ee9710f93
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -1916,9 +1916,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "pumpkin-entity"
|
name = "pumpkin-entity"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"pumpkin-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pumpkin-inventory"
|
name = "pumpkin-inventory"
|
||||||
|
|||||||
@ -4,4 +4,3 @@ version.workspace = true
|
|||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-core = { path = "../pumpkin-core"}
|
|
||||||
@ -1,63 +1,4 @@
|
|||||||
use entity_type::EntityType;
|
|
||||||
use pose::EntityPose;
|
|
||||||
use pumpkin_core::math::{
|
|
||||||
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod entity_type;
|
pub mod entity_type;
|
||||||
pub mod pose;
|
pub mod pose;
|
||||||
|
|
||||||
pub type EntityId = i32;
|
pub type EntityId = i32;
|
||||||
|
|
||||||
pub struct Entity {
|
|
||||||
pub entity_id: EntityId,
|
|
||||||
pub entity_type: EntityType,
|
|
||||||
pub pos: Vector3<f64>,
|
|
||||||
pub block_pos: WorldPosition,
|
|
||||||
pub chunk_pos: Vector2<i32>,
|
|
||||||
|
|
||||||
pub yaw: f32,
|
|
||||||
pub head_yaw: f32,
|
|
||||||
pub pitch: f32,
|
|
||||||
// TODO: Change this in diffrent poses
|
|
||||||
pub standing_eye_height: f32,
|
|
||||||
pub pose: EntityPose,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Entity {
|
|
||||||
pub fn new(entity_id: EntityId, entity_type: EntityType, standing_eye_height: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
entity_id,
|
|
||||||
entity_type,
|
|
||||||
pos: Vector3::new(0.0, 0.0, 0.0),
|
|
||||||
block_pos: WorldPosition(Vector3::new(0, 0, 0)),
|
|
||||||
chunk_pos: Vector2::new(0, 0),
|
|
||||||
yaw: 0.0,
|
|
||||||
head_yaw: 0.0,
|
|
||||||
pitch: 0.0,
|
|
||||||
standing_eye_height,
|
|
||||||
pose: EntityPose::Standing,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_pos(&mut self, x: f64, y: f64, z: f64) {
|
|
||||||
if self.pos.x != x || self.pos.y != y || self.pos.z != z {
|
|
||||||
self.pos = Vector3::new(x, y, z);
|
|
||||||
let i = x.floor() as i32;
|
|
||||||
let j = y.floor() as i32;
|
|
||||||
let k = z.floor() as i32;
|
|
||||||
|
|
||||||
let block_pos = self.block_pos.0;
|
|
||||||
if i != block_pos.x || j != block_pos.y || k != block_pos.z {
|
|
||||||
self.block_pos = WorldPosition(Vector3::new(i, j, k));
|
|
||||||
|
|
||||||
if get_section_cord(i) != self.chunk_pos.x
|
|
||||||
|| get_section_cord(k) != self.chunk_pos.z
|
|
||||||
{
|
|
||||||
self.chunk_pos =
|
|
||||||
Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -5,11 +5,11 @@ use serde::Serialize;
|
|||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[packet(0x1D)]
|
#[packet(0x1D)]
|
||||||
pub struct CPlayDisconnect<'a> {
|
pub struct CPlayDisconnect<'a> {
|
||||||
reason: TextComponent<'a>,
|
reason: &'a TextComponent<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CPlayDisconnect<'a> {
|
impl<'a> CPlayDisconnect<'a> {
|
||||||
pub fn new(reason: TextComponent<'a>) -> Self {
|
pub fn new(reason: &'a TextComponent<'a>) -> Self {
|
||||||
Self { reason }
|
Self { reason }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -323,7 +323,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
// So we can also kick on errors, but generally should use Player::kick
|
// So we can also kick on errors, but generally should use Player::kick
|
||||||
ConnectionState::Play => {
|
ConnectionState::Play => {
|
||||||
self.try_send_packet(&CPlayDisconnect::new(TextComponent::text(reason)))
|
self.try_send_packet(&CPlayDisconnect::new(&TextComponent::text(reason)))
|
||||||
.unwrap_or_else(|_| self.close());
|
.unwrap_or_else(|_| self.close());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
@ -82,15 +82,27 @@ impl Player {
|
|||||||
Self::clamp_vertical(position.feet_y),
|
Self::clamp_vertical(position.feet_y),
|
||||||
Self::clamp_horizontal(position.z),
|
Self::clamp_horizontal(position.z),
|
||||||
);
|
);
|
||||||
// TODO: teleport when moving > 8 block
|
entity.on_ground = position.ground;
|
||||||
|
let on_ground = entity.on_ground;
|
||||||
// send new position to all other players
|
|
||||||
let on_ground = self.on_ground;
|
|
||||||
let entity_id = entity.entity_id;
|
let entity_id = entity.entity_id;
|
||||||
let (x, y, z) = entity.pos.into();
|
let (x, y, z) = entity.pos.into();
|
||||||
let (lastx, lasty, lastz) = self.last_position.into();
|
let (lastx, lasty, lastz) = self.last_position.into();
|
||||||
let world = self.world.clone();
|
let world = self.world.clone();
|
||||||
let world = world.lock().await;
|
let world = world.lock().await;
|
||||||
|
|
||||||
|
// let delta = Vector3::new(x - lastx, y - lasty, z - lastz);
|
||||||
|
// let velocity = self.velocity;
|
||||||
|
|
||||||
|
// // Player is falling down fast, we should account for that
|
||||||
|
// let max_speed = if self.fall_flying { 300.0 } else { 100.0 };
|
||||||
|
|
||||||
|
// teleport when more than 8 blocks (i guess 8 blocks)
|
||||||
|
// TODO: REPLACE * 2.0 by movement packets. see vanilla for details
|
||||||
|
// if delta.length_squared() - velocity.length_squared() > max_speed * 2.0 {
|
||||||
|
// self.teleport(x, y, z, self.entity.yaw, self.entity.pitch);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// send new position to all other players
|
||||||
world.broadcast_packet(
|
world.broadcast_packet(
|
||||||
&[self.client.token],
|
&[self.client.token],
|
||||||
&CUpdateEntityPos::new(
|
&CUpdateEntityPos::new(
|
||||||
@ -128,11 +140,11 @@ impl Player {
|
|||||||
Self::clamp_vertical(position_rotation.feet_y),
|
Self::clamp_vertical(position_rotation.feet_y),
|
||||||
Self::clamp_horizontal(position_rotation.z),
|
Self::clamp_horizontal(position_rotation.z),
|
||||||
);
|
);
|
||||||
|
entity.on_ground = position_rotation.ground;
|
||||||
entity.yaw = wrap_degrees(position_rotation.yaw) % 360.0;
|
entity.yaw = wrap_degrees(position_rotation.yaw) % 360.0;
|
||||||
entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0;
|
entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0;
|
||||||
|
|
||||||
// send new position to all other players
|
let on_ground = entity.on_ground;
|
||||||
let on_ground = self.on_ground;
|
|
||||||
let entity_id = entity.entity_id;
|
let entity_id = entity.entity_id;
|
||||||
let (x, y, z) = entity.pos.into();
|
let (x, y, z) = entity.pos.into();
|
||||||
let (lastx, lasty, lastz) = self.last_position.into();
|
let (lastx, lasty, lastz) = self.last_position.into();
|
||||||
@ -142,6 +154,20 @@ impl Player {
|
|||||||
let world = self.world.clone();
|
let world = self.world.clone();
|
||||||
let world = world.lock().await;
|
let world = world.lock().await;
|
||||||
|
|
||||||
|
// let delta = Vector3::new(x - lastx, y - lasty, z - lastz);
|
||||||
|
// let velocity = self.velocity;
|
||||||
|
|
||||||
|
// // Player is falling down fast, we should account for that
|
||||||
|
// let max_speed = if self.fall_flying { 300.0 } else { 100.0 };
|
||||||
|
|
||||||
|
// // teleport when more than 8 blocks (i guess 8 blocks)
|
||||||
|
// // TODO: REPLACE * 2.0 by movement packets. see vanilla for details
|
||||||
|
// if delta.length_squared() - velocity.length_squared() > max_speed * 2.0 {
|
||||||
|
// self.teleport(x, y, z, yaw, pitch);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// send new position to all other players
|
||||||
|
|
||||||
world.broadcast_packet(
|
world.broadcast_packet(
|
||||||
&[self.client.token],
|
&[self.client.token],
|
||||||
&CUpdateEntityPosRot::new(
|
&CUpdateEntityPosRot::new(
|
||||||
@ -168,10 +194,11 @@ impl Player {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let entity = &mut self.entity;
|
let entity = &mut self.entity;
|
||||||
|
entity.on_ground = rotation.ground;
|
||||||
entity.yaw = wrap_degrees(rotation.yaw) % 360.0;
|
entity.yaw = wrap_degrees(rotation.yaw) % 360.0;
|
||||||
entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0;
|
entity.pitch = wrap_degrees(rotation.pitch).clamp(-90.0, 90.0) % 360.0;
|
||||||
// send new position to all other players
|
// send new position to all other players
|
||||||
let on_ground = self.on_ground;
|
let on_ground = entity.on_ground;
|
||||||
let entity_id = entity.entity_id;
|
let entity_id = entity.entity_id;
|
||||||
let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0);
|
let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0);
|
||||||
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
|
let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0);
|
||||||
@ -191,7 +218,7 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_player_ground(&mut self, _server: &mut Server, ground: SSetPlayerGround) {
|
pub fn handle_player_ground(&mut self, _server: &mut Server, ground: SSetPlayerGround) {
|
||||||
self.on_ground = ground.on_ground;
|
self.entity.on_ground = ground.on_ground;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) {
|
pub async fn handle_player_command(&mut self, _server: &mut Server, command: SPlayerCommand) {
|
||||||
@ -202,30 +229,45 @@ impl Player {
|
|||||||
if let Some(action) = Action::from_i32(command.action.0) {
|
if let Some(action) = Action::from_i32(command.action.0) {
|
||||||
match action {
|
match action {
|
||||||
pumpkin_protocol::server::play::Action::StartSneaking => {
|
pumpkin_protocol::server::play::Action::StartSneaking => {
|
||||||
if !self.sneaking {
|
if !self.entity.sneaking {
|
||||||
self.set_sneaking(true).await
|
self.entity
|
||||||
|
.set_sneaking(&mut self.client, self.world.clone(), true)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StopSneaking => {
|
pumpkin_protocol::server::play::Action::StopSneaking => {
|
||||||
if self.sneaking {
|
if self.entity.sneaking {
|
||||||
self.set_sneaking(false).await
|
self.entity
|
||||||
|
.set_sneaking(&mut self.client, self.world.clone(), false)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
|
pumpkin_protocol::server::play::Action::LeaveBed => todo!(),
|
||||||
pumpkin_protocol::server::play::Action::StartSprinting => {
|
pumpkin_protocol::server::play::Action::StartSprinting => {
|
||||||
if !self.sprinting {
|
if !self.entity.sprinting {
|
||||||
self.set_sprinting(true).await
|
self.entity
|
||||||
|
.set_sprinting(&mut self.client, self.world.clone(), true)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StopSprinting => {
|
pumpkin_protocol::server::play::Action::StopSprinting => {
|
||||||
if self.sprinting {
|
if self.entity.sprinting {
|
||||||
self.set_sprinting(false).await
|
self.entity
|
||||||
|
.set_sprinting(&mut self.client, self.world.clone(), false)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pumpkin_protocol::server::play::Action::StartHorseJump => todo!(),
|
pumpkin_protocol::server::play::Action::StartHorseJump => todo!(),
|
||||||
pumpkin_protocol::server::play::Action::StopHorseJump => todo!(),
|
pumpkin_protocol::server::play::Action::StopHorseJump => todo!(),
|
||||||
pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(),
|
pumpkin_protocol::server::play::Action::OpenVehicleInventory => todo!(),
|
||||||
pumpkin_protocol::server::play::Action::StartFlyingElytra => {} // TODO
|
pumpkin_protocol::server::play::Action::StartFlyingElytra => {
|
||||||
|
let fall_flying = self.entity.check_fall_flying();
|
||||||
|
if self.entity.fall_flying != fall_flying {
|
||||||
|
self.entity
|
||||||
|
.set_fall_flying(&mut self.client, self.world.clone(), fall_flying)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
} // TODO
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.kick(TextComponent::text("Invalid player command"))
|
self.kick(TextComponent::text("Invalid player command"))
|
||||||
@ -320,8 +362,10 @@ impl Player {
|
|||||||
|
|
||||||
pub async fn handle_interact(&mut self, _: &mut Server, interact: SInteract) {
|
pub async fn handle_interact(&mut self, _: &mut Server, interact: SInteract) {
|
||||||
let sneaking = interact.sneaking;
|
let sneaking = interact.sneaking;
|
||||||
if self.sneaking != sneaking {
|
if self.entity.sneaking != sneaking {
|
||||||
self.set_sneaking(sneaking).await;
|
self.entity
|
||||||
|
.set_sneaking(&mut self.client, self.world.clone(), sneaking)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
match ActionType::from_i32(interact.typ.0) {
|
match ActionType::from_i32(interact.typ.0) {
|
||||||
Some(action) => match action {
|
Some(action) => match action {
|
||||||
@ -335,27 +379,27 @@ impl Player {
|
|||||||
let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId);
|
let attacked_player = world.get_by_entityid(self, entity_id.0 as EntityId);
|
||||||
if let Some(mut player) = attacked_player {
|
if let Some(mut player) = attacked_player {
|
||||||
let token = player.client.token;
|
let token = player.client.token;
|
||||||
let velo = player.velocity;
|
let velo = player.entity.velocity;
|
||||||
if config.protect_creative && player.gamemode == GameMode::Creative {
|
if config.protect_creative && player.gamemode == GameMode::Creative {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if config.knockback {
|
if config.knockback {
|
||||||
let yaw = self.entity.yaw;
|
let yaw = self.entity.yaw;
|
||||||
let strength = 1.0;
|
let strength = 1.0;
|
||||||
player.knockback(
|
player.entity.knockback(
|
||||||
strength * 0.5,
|
strength * 0.5,
|
||||||
(yaw * (PI / 180.0)).sin() as f64,
|
(yaw * (PI / 180.0)).sin() as f64,
|
||||||
-(yaw * (PI / 180.0)).cos() as f64,
|
-(yaw * (PI / 180.0)).cos() as f64,
|
||||||
);
|
);
|
||||||
let packet = &CEntityVelocity::new(
|
let packet = &CEntityVelocity::new(
|
||||||
&entity_id,
|
&entity_id,
|
||||||
player.velocity.x as f32,
|
velo.x as f32,
|
||||||
player.velocity.y as f32,
|
velo.y as f32,
|
||||||
player.velocity.z as f32,
|
velo.z as f32,
|
||||||
);
|
);
|
||||||
self.velocity = self.velocity.multiply(0.6, 1.0, 0.6);
|
self.entity.velocity = self.entity.velocity.multiply(0.6, 1.0, 0.6);
|
||||||
|
|
||||||
player.velocity = velo;
|
player.entity.velocity = velo;
|
||||||
player.client.send_packet(packet);
|
player.client.send_packet(packet);
|
||||||
}
|
}
|
||||||
if config.hurt_animation {
|
if config.hurt_animation {
|
||||||
|
|||||||
@ -1 +1,195 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use pumpkin_core::math::{
|
||||||
|
get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3,
|
||||||
|
};
|
||||||
|
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, EntityId};
|
||||||
|
use pumpkin_protocol::{
|
||||||
|
client::play::{CSetEntityMetadata, Metadata},
|
||||||
|
VarInt,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{client::Client, world::World};
|
||||||
|
|
||||||
pub mod player;
|
pub mod player;
|
||||||
|
|
||||||
|
pub struct Entity {
|
||||||
|
pub entity_id: EntityId,
|
||||||
|
pub entity_type: EntityType,
|
||||||
|
pub pos: Vector3<f64>,
|
||||||
|
pub block_pos: WorldPosition,
|
||||||
|
pub chunk_pos: Vector2<i32>,
|
||||||
|
|
||||||
|
pub sneaking: bool,
|
||||||
|
pub sprinting: bool,
|
||||||
|
pub fall_flying: bool,
|
||||||
|
pub velocity: Vector3<f64>,
|
||||||
|
|
||||||
|
// Should be not trusted
|
||||||
|
pub on_ground: bool,
|
||||||
|
|
||||||
|
pub yaw: f32,
|
||||||
|
pub head_yaw: f32,
|
||||||
|
pub pitch: f32,
|
||||||
|
// TODO: Change this in diffrent poses
|
||||||
|
pub standing_eye_height: f32,
|
||||||
|
pub pose: EntityPose,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove client: &mut Client, world: Arc<tokio::sync::Mutex<World>> bs
|
||||||
|
impl Entity {
|
||||||
|
pub fn new(entity_id: EntityId, entity_type: EntityType, standing_eye_height: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
entity_id,
|
||||||
|
entity_type,
|
||||||
|
on_ground: false,
|
||||||
|
pos: Vector3::new(0.0, 0.0, 0.0),
|
||||||
|
block_pos: WorldPosition(Vector3::new(0, 0, 0)),
|
||||||
|
chunk_pos: Vector2::new(0, 0),
|
||||||
|
sneaking: false,
|
||||||
|
sprinting: false,
|
||||||
|
fall_flying: false,
|
||||||
|
yaw: 0.0,
|
||||||
|
head_yaw: 0.0,
|
||||||
|
pitch: 0.0,
|
||||||
|
velocity: Vector3::new(0.0, 0.0, 0.0),
|
||||||
|
standing_eye_height,
|
||||||
|
pose: EntityPose::Standing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pos(&mut self, x: f64, y: f64, z: f64) {
|
||||||
|
if self.pos.x != x || self.pos.y != y || self.pos.z != z {
|
||||||
|
self.pos = Vector3::new(x, y, z);
|
||||||
|
let i = x.floor() as i32;
|
||||||
|
let j = y.floor() as i32;
|
||||||
|
let k = z.floor() as i32;
|
||||||
|
|
||||||
|
let block_pos = self.block_pos.0;
|
||||||
|
if i != block_pos.x || j != block_pos.y || k != block_pos.z {
|
||||||
|
self.block_pos = WorldPosition(Vector3::new(i, j, k));
|
||||||
|
|
||||||
|
if get_section_cord(i) != self.chunk_pos.x
|
||||||
|
|| get_section_cord(k) != self.chunk_pos.z
|
||||||
|
{
|
||||||
|
self.chunk_pos =
|
||||||
|
Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn knockback(&mut self, strength: f64, x: f64, z: f64) {
|
||||||
|
// This has some vanilla magic
|
||||||
|
let mut x = x;
|
||||||
|
let mut z = z;
|
||||||
|
while x * x + z * z < 1.0E-5 {
|
||||||
|
x = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
||||||
|
z = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
let var8 = Vector3::new(x, 0.0, z).normalize() * strength;
|
||||||
|
let var7 = self.velocity;
|
||||||
|
self.velocity = Vector3::new(
|
||||||
|
var7.x / 2.0 - var8.x,
|
||||||
|
if self.on_ground {
|
||||||
|
(var7.y / 2.0 + strength).min(0.4)
|
||||||
|
} else {
|
||||||
|
var7.y
|
||||||
|
},
|
||||||
|
var7.z / 2.0 - var8.z,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_sneaking(
|
||||||
|
&mut self,
|
||||||
|
client: &mut Client,
|
||||||
|
world: Arc<tokio::sync::Mutex<World>>,
|
||||||
|
sneaking: bool,
|
||||||
|
) {
|
||||||
|
assert!(self.sneaking != sneaking);
|
||||||
|
self.sneaking = sneaking;
|
||||||
|
self.set_flag(client, world, Self::SNEAKING_FLAG_INDEX, sneaking)
|
||||||
|
.await;
|
||||||
|
// if sneaking {
|
||||||
|
// self.set_pose(EntityPose::Crouching).await;
|
||||||
|
// } else {
|
||||||
|
// self.set_pose(EntityPose::Standing).await;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_sprinting(
|
||||||
|
&mut self,
|
||||||
|
client: &mut Client,
|
||||||
|
world: Arc<tokio::sync::Mutex<World>>,
|
||||||
|
sprinting: bool,
|
||||||
|
) {
|
||||||
|
assert!(self.sprinting != sprinting);
|
||||||
|
self.sprinting = sprinting;
|
||||||
|
self.set_flag(client, world, Self::SPRINTING_FLAG_INDEX, sprinting)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_fall_flying(&self) -> bool {
|
||||||
|
!self.on_ground
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_fall_flying(
|
||||||
|
&mut self,
|
||||||
|
client: &mut Client,
|
||||||
|
world: Arc<tokio::sync::Mutex<World>>,
|
||||||
|
fall_flying: bool,
|
||||||
|
) {
|
||||||
|
assert!(self.fall_flying != fall_flying);
|
||||||
|
self.fall_flying = fall_flying;
|
||||||
|
self.set_flag(client, world, Self::FALL_FLYING_FLAG_INDEX, fall_flying)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ON_FIRE_FLAG_INDEX: u32 = 0;
|
||||||
|
pub const SNEAKING_FLAG_INDEX: u32 = 1;
|
||||||
|
pub const SPRINTING_FLAG_INDEX: u32 = 3;
|
||||||
|
pub const SWIMMING_FLAG_INDEX: u32 = 4;
|
||||||
|
pub const INVISIBLE_FLAG_INDEX: u32 = 5;
|
||||||
|
pub const GLOWING_FLAG_INDEX: u32 = 6;
|
||||||
|
pub const FALL_FLYING_FLAG_INDEX: u32 = 7;
|
||||||
|
async fn set_flag(
|
||||||
|
&mut self,
|
||||||
|
client: &mut Client,
|
||||||
|
world: Arc<tokio::sync::Mutex<World>>,
|
||||||
|
index: u32,
|
||||||
|
value: bool,
|
||||||
|
) {
|
||||||
|
let mut b = 0i8;
|
||||||
|
if value {
|
||||||
|
b |= 1 << index;
|
||||||
|
} else {
|
||||||
|
b &= !(1 << index);
|
||||||
|
}
|
||||||
|
let packet = CSetEntityMetadata::new(self.entity_id.into(), Metadata::new(0, 0.into(), b));
|
||||||
|
client.send_packet(&packet);
|
||||||
|
world
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.broadcast_packet(&[client.token], &packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_pose(
|
||||||
|
&mut self,
|
||||||
|
client: &mut Client,
|
||||||
|
world: Arc<tokio::sync::Mutex<World>>,
|
||||||
|
pose: EntityPose,
|
||||||
|
) {
|
||||||
|
self.pose = pose;
|
||||||
|
let pose = self.pose as i32;
|
||||||
|
let packet = CSetEntityMetadata::<VarInt>::new(
|
||||||
|
self.entity_id.into(),
|
||||||
|
Metadata::new(6, 20.into(), (pose).into()),
|
||||||
|
);
|
||||||
|
client.send_packet(&packet);
|
||||||
|
world
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.broadcast_packet(&[client.token], &packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -7,13 +7,13 @@ use pumpkin_core::{
|
|||||||
text::TextComponent,
|
text::TextComponent,
|
||||||
GameMode,
|
GameMode,
|
||||||
};
|
};
|
||||||
use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, Entity, EntityId};
|
use pumpkin_entity::{entity_type::EntityType, EntityId};
|
||||||
use pumpkin_inventory::player::PlayerInventory;
|
use pumpkin_inventory::player::PlayerInventory;
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
bytebuf::{packet_id::Packet, DeserializerError},
|
bytebuf::{packet_id::Packet, DeserializerError},
|
||||||
client::play::{
|
client::play::{
|
||||||
CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSetEntityMetadata,
|
CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSyncPlayerPosition,
|
||||||
CSyncPlayerPosition, CSystemChatMessage, Metadata, PlayerAction,
|
CSystemChatMessage, PlayerAction,
|
||||||
},
|
},
|
||||||
server::play::{
|
server::play::{
|
||||||
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
|
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
|
||||||
@ -30,6 +30,8 @@ use crate::{
|
|||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::Entity;
|
||||||
|
|
||||||
pub struct PlayerAbilities {
|
pub struct PlayerAbilities {
|
||||||
pub invulnerable: bool,
|
pub invulnerable: bool,
|
||||||
pub flying: bool,
|
pub flying: bool,
|
||||||
@ -53,9 +55,10 @@ impl Default for PlayerAbilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
|
pub entity: Entity,
|
||||||
|
|
||||||
pub gameprofile: GameProfile,
|
pub gameprofile: GameProfile,
|
||||||
pub client: Client,
|
pub client: Client,
|
||||||
pub entity: Entity,
|
|
||||||
pub config: PlayerConfig,
|
pub config: PlayerConfig,
|
||||||
// TODO: Put this into entity
|
// TODO: Put this into entity
|
||||||
pub world: Arc<tokio::sync::Mutex<World>>,
|
pub world: Arc<tokio::sync::Mutex<World>>,
|
||||||
@ -68,20 +71,11 @@ pub struct Player {
|
|||||||
pub inventory: PlayerInventory,
|
pub inventory: PlayerInventory,
|
||||||
/// send `send_abilties_update` when changed
|
/// send `send_abilties_update` when changed
|
||||||
pub abilities: PlayerAbilities,
|
pub abilities: PlayerAbilities,
|
||||||
|
|
||||||
pub last_position: Vector3<f64>,
|
pub last_position: Vector3<f64>,
|
||||||
// Client side value, Should be not trusted
|
|
||||||
pub on_ground: bool,
|
|
||||||
|
|
||||||
pub sneaking: bool,
|
|
||||||
pub sprinting: bool,
|
|
||||||
|
|
||||||
// TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done
|
// TODO: This is currently unused, We have to calculate the block breaking speed our own and then break the block our own if its done
|
||||||
pub current_block_destroy_stage: u8,
|
pub current_block_destroy_stage: u8,
|
||||||
|
|
||||||
// TODO: prbly should put this into an Living Entitiy or something
|
|
||||||
pub velocity: Vector3<f64>,
|
|
||||||
|
|
||||||
pub teleport_id_count: i32,
|
pub teleport_id_count: i32,
|
||||||
// Current awaiting teleport id and location, None if did not teleport
|
// Current awaiting teleport id and location, None if did not teleport
|
||||||
pub awaiting_teleport: Option<(VarInt, Vector3<f64>)>,
|
pub awaiting_teleport: Option<(VarInt, Vector3<f64>)>,
|
||||||
@ -110,21 +104,17 @@ impl Player {
|
|||||||
};
|
};
|
||||||
let config = client.config.clone().unwrap_or_default();
|
let config = client.config.clone().unwrap_or_default();
|
||||||
Self {
|
Self {
|
||||||
|
entity: Entity::new(entity_id, EntityType::Player, 1.62),
|
||||||
config,
|
config,
|
||||||
gameprofile,
|
gameprofile,
|
||||||
client,
|
client,
|
||||||
entity: Entity::new(entity_id, EntityType::Player, 1.62),
|
|
||||||
world,
|
world,
|
||||||
on_ground: false,
|
|
||||||
awaiting_teleport: None,
|
awaiting_teleport: None,
|
||||||
sneaking: false,
|
|
||||||
sprinting: false,
|
|
||||||
// TODO: Load this from previous instance
|
// TODO: Load this from previous instance
|
||||||
health: 20.0,
|
health: 20.0,
|
||||||
food: 20,
|
food: 20,
|
||||||
food_saturation: 20.0,
|
food_saturation: 20.0,
|
||||||
current_block_destroy_stage: 0,
|
current_block_destroy_stage: 0,
|
||||||
velocity: Vector3::new(0.0, 0.0, 0.0),
|
|
||||||
inventory: PlayerInventory::new(),
|
inventory: PlayerInventory::new(),
|
||||||
teleport_id_count: 0,
|
teleport_id_count: 0,
|
||||||
abilities: PlayerAbilities::default(),
|
abilities: PlayerAbilities::default(),
|
||||||
@ -144,28 +134,6 @@ impl Player {
|
|||||||
self.entity.entity_id
|
self.entity.entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn knockback(&mut self, strength: f64, x: f64, z: f64) {
|
|
||||||
// This has some vanilla magic
|
|
||||||
let mut x = x;
|
|
||||||
let mut z = z;
|
|
||||||
while x * x + z * z < 1.0E-5 {
|
|
||||||
x = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
|
||||||
z = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
|
||||||
}
|
|
||||||
|
|
||||||
let var8 = Vector3::new(x, 0.0, z).normalize() * strength;
|
|
||||||
let var7 = self.velocity;
|
|
||||||
self.velocity = Vector3::new(
|
|
||||||
var7.x / 2.0 - var8.x,
|
|
||||||
if self.on_ground {
|
|
||||||
(var7.y / 2.0 + strength).min(0.4)
|
|
||||||
} else {
|
|
||||||
var7.y
|
|
||||||
},
|
|
||||||
var7.z / 2.0 - var8.z,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_abilties_update(&mut self) {
|
pub fn send_abilties_update(&mut self) {
|
||||||
let mut b = 0i8;
|
let mut b = 0i8;
|
||||||
let abilities = &self.abilities;
|
let abilities = &self.abilities;
|
||||||
@ -189,60 +157,6 @@ impl Player {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_sneaking(&mut self, sneaking: bool) {
|
|
||||||
assert!(self.sneaking != sneaking);
|
|
||||||
self.sneaking = sneaking;
|
|
||||||
self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await;
|
|
||||||
// if sneaking {
|
|
||||||
// self.set_pose(EntityPose::Crouching).await;
|
|
||||||
// } else {
|
|
||||||
// self.set_pose(EntityPose::Standing).await;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn set_sprinting(&mut self, sprinting: bool) {
|
|
||||||
assert!(self.sprinting != sprinting);
|
|
||||||
self.sprinting = sprinting;
|
|
||||||
self.set_flag(Self::SPRINTING_FLAG_INDEX, sprinting).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const ON_FIRE_FLAG_INDEX: u32 = 0;
|
|
||||||
pub const SNEAKING_FLAG_INDEX: u32 = 1;
|
|
||||||
pub const SPRINTING_FLAG_INDEX: u32 = 3;
|
|
||||||
pub const SWIMMING_FLAG_INDEX: u32 = 4;
|
|
||||||
pub const INVISIBLE_FLAG_INDEX: u32 = 5;
|
|
||||||
pub const GLOWING_FLAG_INDEX: u32 = 6;
|
|
||||||
pub const FALL_FLYING_FLAG_INDEX: u32 = 7;
|
|
||||||
async fn set_flag(&mut self, index: u32, value: bool) {
|
|
||||||
let mut b = 0i8;
|
|
||||||
if value {
|
|
||||||
b |= 1 << index;
|
|
||||||
} else {
|
|
||||||
b &= !(1 << index);
|
|
||||||
}
|
|
||||||
let packet =
|
|
||||||
CSetEntityMetadata::new(self.entity_id().into(), Metadata::new(0, 0.into(), b));
|
|
||||||
self.client.send_packet(&packet);
|
|
||||||
self.world
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.broadcast_packet(&[self.client.token], &packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn set_pose(&mut self, pose: EntityPose) {
|
|
||||||
self.entity.pose = pose;
|
|
||||||
let pose = self.entity.pose as i32;
|
|
||||||
let packet = CSetEntityMetadata::<VarInt>::new(
|
|
||||||
self.entity_id().into(),
|
|
||||||
Metadata::new(6, 20.into(), (pose).into()),
|
|
||||||
);
|
|
||||||
self.client.send_packet(&packet);
|
|
||||||
self.world
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.broadcast_packet(&[self.client.token], &packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) {
|
pub fn teleport(&mut self, x: f64, y: f64, z: f64, yaw: f32, pitch: f32) {
|
||||||
// this is the ultra special magic code used to create the teleport id
|
// this is the ultra special magic code used to create the teleport id
|
||||||
self.teleport_id_count += 1;
|
self.teleport_id_count += 1;
|
||||||
@ -251,7 +165,6 @@ impl Player {
|
|||||||
}
|
}
|
||||||
let entity = &mut self.entity;
|
let entity = &mut self.entity;
|
||||||
entity.set_pos(x, y, z);
|
entity.set_pos(x, y, z);
|
||||||
self.last_position = entity.pos;
|
|
||||||
entity.yaw = yaw;
|
entity.yaw = yaw;
|
||||||
entity.pitch = pitch;
|
entity.pitch = pitch;
|
||||||
self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z)));
|
self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z)));
|
||||||
@ -287,11 +200,16 @@ impl Player {
|
|||||||
/// Kicks the Client with a reason depending on the connection state
|
/// Kicks the Client with a reason depending on the connection state
|
||||||
pub fn kick(&mut self, reason: TextComponent) {
|
pub fn kick(&mut self, reason: TextComponent) {
|
||||||
assert!(self.client.connection_state == ConnectionState::Play);
|
assert!(self.client.connection_state == ConnectionState::Play);
|
||||||
dbg!(&reason);
|
assert!(!self.client.closed);
|
||||||
self.client
|
|
||||||
.try_send_packet(&CPlayDisconnect::new(reason))
|
|
||||||
.unwrap_or_else(|_| self.client.close());
|
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.try_send_packet(&CPlayDisconnect::new(&reason))
|
||||||
|
.unwrap_or_else(|_| self.client.close());
|
||||||
|
log::info!(
|
||||||
|
"Kicked {} for {}",
|
||||||
|
self.gameprofile.name,
|
||||||
|
reason.to_pretty_console()
|
||||||
|
);
|
||||||
self.client.close()
|
self.client.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -158,9 +158,6 @@ impl World {
|
|||||||
.client
|
.client
|
||||||
.send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries));
|
.send_packet(&CPlayerInfoUpdate::new(0x01 | 0x08, &entries));
|
||||||
|
|
||||||
// Start waiting for level chunks
|
|
||||||
player.client.send_packet(&CGameEvent::new(13, 0.0));
|
|
||||||
|
|
||||||
let gameprofile = &player.gameprofile;
|
let gameprofile = &player.gameprofile;
|
||||||
|
|
||||||
// spawn player for every client
|
// spawn player for every client
|
||||||
@ -216,6 +213,9 @@ impl World {
|
|||||||
self.broadcast_packet(&[player.client.token], &packet)
|
self.broadcast_packet(&[player.client.token], &packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start waiting for level chunks
|
||||||
|
player.client.send_packet(&CGameEvent::new(13, 0.0));
|
||||||
|
|
||||||
// Spawn in inital chunks
|
// Spawn in inital chunks
|
||||||
player_chunker::player_join(self, player).await;
|
player_chunker::player_join(self, player).await;
|
||||||
}
|
}
|
||||||
@ -231,8 +231,9 @@ impl World {
|
|||||||
|
|
||||||
let level = self.level.clone();
|
let level = self.level.clone();
|
||||||
let closed = client.closed;
|
let closed = client.closed;
|
||||||
tokio::spawn(async move {
|
let chunks = Arc::new(chunks);
|
||||||
level.lock().unwrap().fetch_chunks(&chunks, sender, closed);
|
tokio::task::spawn_blocking(move || {
|
||||||
|
level.lock().unwrap().fetch_chunks(&chunks, sender, closed)
|
||||||
});
|
});
|
||||||
|
|
||||||
while let Some(chunk_data) = chunk_receiver.recv().await {
|
while let Some(chunk_data) = chunk_receiver.recv().await {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user