Add Basic Combat
This commit is contained in:
parent
03cc991bfd
commit
6459aef027
24
pumpkin-protocol/src/client/play/c_entity_velocity.rs
Normal file
24
pumpkin-protocol/src/client/play/c_entity_velocity.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::VarInt;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[packet(0x5A)]
|
||||||
|
pub struct CEntityVelocity<'a> {
|
||||||
|
entitiy_id: &'a VarInt,
|
||||||
|
velocity_x: i16,
|
||||||
|
velocity_y: i16,
|
||||||
|
velocity_z: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CEntityVelocity<'a> {
|
||||||
|
pub fn new(entitiy_id: &'a VarInt, velocity_x: f32, velocity_y: f32, velocity_z: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
entitiy_id,
|
||||||
|
velocity_x: (velocity_x.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
velocity_y: (velocity_y.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
velocity_z: (velocity_z.clamp(-3.9, 3.9) * 8000.0) as i16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,13 +5,13 @@ use crate::VarInt;
|
|||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[packet(0x24)]
|
#[packet(0x24)]
|
||||||
pub struct CHurtAnimation {
|
pub struct CHurtAnimation<'a> {
|
||||||
entitiy_id: VarInt,
|
entitiy_id: &'a VarInt,
|
||||||
yaw: f32,
|
yaw: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CHurtAnimation {
|
impl<'a> CHurtAnimation<'a> {
|
||||||
pub fn new(entitiy_id: VarInt, yaw: f32) -> Self {
|
pub fn new(entitiy_id: &'a VarInt, yaw: f32) -> Self {
|
||||||
Self { entitiy_id, yaw }
|
Self { entitiy_id, yaw }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ mod c_chunk_data;
|
|||||||
mod c_disguised_chat_message;
|
mod c_disguised_chat_message;
|
||||||
mod c_entity_animation;
|
mod c_entity_animation;
|
||||||
mod c_entity_metadata;
|
mod c_entity_metadata;
|
||||||
|
mod c_entity_velocity;
|
||||||
mod c_game_event;
|
mod c_game_event;
|
||||||
mod c_head_rot;
|
mod c_head_rot;
|
||||||
mod c_hurt_animation;
|
mod c_hurt_animation;
|
||||||
@ -34,6 +35,7 @@ pub use c_chunk_data::*;
|
|||||||
pub use c_disguised_chat_message::*;
|
pub use c_disguised_chat_message::*;
|
||||||
pub use c_entity_animation::*;
|
pub use c_entity_animation::*;
|
||||||
pub use c_entity_metadata::*;
|
pub use c_entity_metadata::*;
|
||||||
|
pub use c_entity_velocity::*;
|
||||||
pub use c_game_event::*;
|
pub use c_game_event::*;
|
||||||
pub use c_head_rot::*;
|
pub use c_head_rot::*;
|
||||||
pub use c_hurt_animation::*;
|
pub use c_hurt_animation::*;
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
pub struct RadialIterator {
|
pub struct RadialIterator {
|
||||||
radius: i32,
|
radius: i32,
|
||||||
direction: usize,
|
direction: usize,
|
||||||
|
|||||||
@ -161,6 +161,13 @@ impl Client {
|
|||||||
self.send_packet(&CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into()));
|
self.send_packet(&CSyncPlayerPostion::new(x, y, z, yaw, pitch, 0, id.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_health(&mut self, health: f32, food: i32, food_saturation: f32) {
|
||||||
|
let player = self.player.as_mut().unwrap();
|
||||||
|
player.health = health;
|
||||||
|
player.food = food;
|
||||||
|
player.food_saturation = food_saturation;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_gamemode(&mut self, gamemode: GameMode) {
|
pub fn set_gamemode(&mut self, gamemode: GameMode) {
|
||||||
let player = self.player.as_mut().unwrap();
|
let player = self.player.as_mut().unwrap();
|
||||||
player.gamemode = gamemode;
|
player.gamemode = gamemode;
|
||||||
|
|||||||
@ -3,8 +3,8 @@ use pumpkin_entity::EntityId;
|
|||||||
use pumpkin_inventory::WindowType;
|
use pumpkin_inventory::WindowType;
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
client::play::{
|
client::play::{
|
||||||
Animation, CEntityAnimation, CHeadRot, CHurtAnimation, COpenScreen, CUpdateEntityPos,
|
Animation, CEntityAnimation, CEntityVelocity, CHeadRot, CHurtAnimation, COpenScreen,
|
||||||
CUpdateEntityPosRot, CUpdateEntityRot,
|
CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot,
|
||||||
},
|
},
|
||||||
server::play::{
|
server::play::{
|
||||||
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
|
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
|
||||||
@ -114,8 +114,8 @@ impl Client {
|
|||||||
entity.x = Self::clamp_horizontal(position_rotation.x);
|
entity.x = Self::clamp_horizontal(position_rotation.x);
|
||||||
entity.y = Self::clamp_vertical(position_rotation.feet_y);
|
entity.y = Self::clamp_vertical(position_rotation.feet_y);
|
||||||
entity.z = Self::clamp_horizontal(position_rotation.z);
|
entity.z = Self::clamp_horizontal(position_rotation.z);
|
||||||
entity.yaw = wrap_degrees(position_rotation.yaw);
|
entity.yaw = wrap_degrees(position_rotation.yaw).clamp(-90.0, 90.0) % 360.0;
|
||||||
entity.pitch = wrap_degrees(position_rotation.pitch);
|
entity.pitch = wrap_degrees(position_rotation.pitch) % 360.0;
|
||||||
|
|
||||||
// send new position to all other players
|
// send new position to all other players
|
||||||
let on_ground = player.on_ground;
|
let on_ground = player.on_ground;
|
||||||
@ -149,8 +149,8 @@ impl Client {
|
|||||||
}
|
}
|
||||||
let player = self.player.as_mut().unwrap();
|
let player = self.player.as_mut().unwrap();
|
||||||
let entity = &mut player.entity;
|
let entity = &mut player.entity;
|
||||||
entity.yaw = wrap_degrees(rotation.yaw);
|
entity.yaw = wrap_degrees(rotation.yaw).clamp(-90.0, 90.0) % 360.0;
|
||||||
entity.pitch = wrap_degrees(rotation.pitch);
|
entity.pitch = wrap_degrees(rotation.pitch) % 360.0;
|
||||||
// send new position to all other players
|
// send new position to all other players
|
||||||
let on_ground = player.on_ground;
|
let on_ground = player.on_ground;
|
||||||
let entity_id = entity.entity_id;
|
let entity_id = entity.entity_id;
|
||||||
@ -195,7 +195,10 @@ impl Client {
|
|||||||
};
|
};
|
||||||
let player = self.player.as_mut().unwrap();
|
let player = self.player.as_mut().unwrap();
|
||||||
let id = player.entity_id();
|
let id = player.entity_id();
|
||||||
server.broadcast_packet_expect(self, &CEntityAnimation::new(id.into(), animation as u8))
|
server.broadcast_packet_expect(
|
||||||
|
&[&self.token],
|
||||||
|
&CEntityAnimation::new(id.into(), animation as u8),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) {
|
pub fn handle_chat_message(&mut self, server: &mut Server, chat_message: SChatMessage) {
|
||||||
@ -264,21 +267,50 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) {
|
pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) {
|
||||||
|
let attacker_player = self.player.as_ref().unwrap();
|
||||||
|
let entity_id = interact.entity_id;
|
||||||
// TODO: do validation and stuff
|
// TODO: do validation and stuff
|
||||||
let config = &server.advanced_config.pvp;
|
let config = &server.advanced_config.pvp;
|
||||||
if config.enabled {
|
if config.enabled {
|
||||||
let attacked_client = server.get_by_entityid(self, interact.entity_id.0 as EntityId);
|
let attacked_client = server.get_by_entityid(self, entity_id.0 as EntityId);
|
||||||
if let Some(client) = attacked_client {
|
if let Some(mut client) = attacked_client {
|
||||||
if config.protect_creative
|
let token = client.token.clone();
|
||||||
&& client.player.as_ref().unwrap().gamemode == GameMode::Creative
|
let player = client.player.as_mut().unwrap();
|
||||||
{
|
let velo = player.velocity;
|
||||||
|
if config.protect_creative && player.gamemode == GameMode::Creative {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
drop(client);
|
if config.knockback {
|
||||||
|
let pitch = attacker_player.entity.pitch;
|
||||||
|
let strength = 1.0;
|
||||||
|
player.knockback(
|
||||||
|
strength * 0.5,
|
||||||
|
(pitch * 0.017453292).sin() as f64,
|
||||||
|
-(pitch * 0.017453292).cos() as f64,
|
||||||
|
);
|
||||||
|
let packet = &CEntityVelocity::new(
|
||||||
|
&entity_id,
|
||||||
|
player.velocity.x as f32,
|
||||||
|
player.velocity.y as f32,
|
||||||
|
player.velocity.z as f32,
|
||||||
|
);
|
||||||
|
player.velocity = velo;
|
||||||
|
client.send_packet(packet);
|
||||||
|
// attacker_player.velocity = attacker_player.velocity.multiply(0.6, 1.0, 0.6);
|
||||||
|
}
|
||||||
if config.hurt_animation {
|
if config.hurt_animation {
|
||||||
// TODO
|
// TODO
|
||||||
server.broadcast_packet(self, &CHurtAnimation::new(interact.entity_id, 10.0))
|
// thats how we prevent borrow errors :c
|
||||||
|
let packet = &CHurtAnimation::new(&entity_id, 10.0);
|
||||||
|
self.send_packet(packet);
|
||||||
|
client.send_packet(packet);
|
||||||
|
server.broadcast_packet_expect(
|
||||||
|
&[self.token.as_ref(), token.as_ref()],
|
||||||
|
&CHurtAnimation::new(&entity_id, 10.0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.kick("Interacted with invalid entitiy id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,13 +32,14 @@ impl<'a> Command<'a> for GamemodeCommand {
|
|||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// try to parse from number
|
// try to parse from number
|
||||||
if let Ok(i) = mode_str.parse::<u8>() { if let Some(mode) = GameMode::from_u8(i) {
|
if let Ok(i) = mode_str.parse::<u8>() {
|
||||||
player.set_gamemode(mode);
|
if let Some(mode) = GameMode::from_u8(i) {
|
||||||
player.send_system_message(
|
player.set_gamemode(mode);
|
||||||
format!("Set own game mode to {:?}", mode).into(),
|
player
|
||||||
);
|
.send_system_message(format!("Set own game mode to {:?}", mode).into());
|
||||||
return;
|
return;
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
player.send_system_message(
|
player.send_system_message(
|
||||||
TextComponent::from("Invalid gamemode")
|
TextComponent::from("Invalid gamemode")
|
||||||
|
|||||||
@ -65,6 +65,8 @@ pub struct PVPConfig {
|
|||||||
pub hurt_animation: bool,
|
pub hurt_animation: bool,
|
||||||
/// Should players in creative be protected against PVP
|
/// Should players in creative be protected against PVP
|
||||||
pub protect_creative: bool,
|
pub protect_creative: bool,
|
||||||
|
/// Has PVP Knockback?
|
||||||
|
pub knockback: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PVPConfig {
|
impl Default for PVPConfig {
|
||||||
@ -73,6 +75,7 @@ impl Default for PVPConfig {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
hurt_animation: true,
|
hurt_animation: true,
|
||||||
protect_creative: true,
|
protect_creative: true,
|
||||||
|
knockback: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,10 +5,16 @@ use pumpkin_entity::{entity_type::EntityType, Entity, EntityId};
|
|||||||
use pumpkin_protocol::VarInt;
|
use pumpkin_protocol::VarInt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::util::vec3::Vec3;
|
||||||
|
|
||||||
pub struct Player {
|
pub struct Player {
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
// current gamemode
|
// current gamemode
|
||||||
pub gamemode: GameMode,
|
pub gamemode: GameMode,
|
||||||
|
// TODO: prbly should put this into an Living Entitiy or something
|
||||||
|
pub health: f32,
|
||||||
|
pub food: i32,
|
||||||
|
pub food_saturation: f32,
|
||||||
|
|
||||||
// Client side value, Should be not trusted
|
// Client side value, Should be not trusted
|
||||||
pub on_ground: bool,
|
pub on_ground: bool,
|
||||||
@ -16,6 +22,8 @@ pub struct Player {
|
|||||||
pub sneaking: bool,
|
pub sneaking: bool,
|
||||||
pub sprinting: bool,
|
pub sprinting: bool,
|
||||||
|
|
||||||
|
pub velocity: Vec3,
|
||||||
|
|
||||||
// Current awaiting teleport id, None if did not teleport
|
// Current awaiting teleport id, None if did not teleport
|
||||||
pub awaiting_teleport: Option<VarInt>,
|
pub awaiting_teleport: Option<VarInt>,
|
||||||
}
|
}
|
||||||
@ -28,6 +36,11 @@ impl Player {
|
|||||||
awaiting_teleport: None,
|
awaiting_teleport: None,
|
||||||
sneaking: false,
|
sneaking: false,
|
||||||
sprinting: false,
|
sprinting: false,
|
||||||
|
// TODO: Load this from previous instance
|
||||||
|
health: 20.0,
|
||||||
|
food: 20,
|
||||||
|
food_saturation: 20.0,
|
||||||
|
velocity: Vec3::new(0.0, 0.0, 0.0),
|
||||||
gamemode,
|
gamemode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,6 +48,28 @@ impl Player {
|
|||||||
pub fn entity_id(&self) -> EntityId {
|
pub fn entity_id(&self) -> EntityId {
|
||||||
self.entity.entity_id
|
self.entity.entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn knockback(&mut self, y: f64, x: f64, z: f64) {
|
||||||
|
// This has some vanilla magic
|
||||||
|
let mut x = x;
|
||||||
|
let mut z = z;
|
||||||
|
while x * x + z * z < 9.999999747378752E-6 {
|
||||||
|
x = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
||||||
|
z = (rand::random::<f64>() - rand::random::<f64>()) * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
let var8 = Vec3::new(x, 0.0, z).normalize() * y;
|
||||||
|
let var7 = self.velocity;
|
||||||
|
self.velocity = Vec3::new(
|
||||||
|
var7.x / 2.0 - var8.x,
|
||||||
|
if self.on_ground {
|
||||||
|
(var7.y / 2.0 + x).min(0.4)
|
||||||
|
} else {
|
||||||
|
var7.y
|
||||||
|
},
|
||||||
|
var7.z / 2.0 - var8.z,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromPrimitive)]
|
#[derive(FromPrimitive)]
|
||||||
|
|||||||
@ -134,8 +134,11 @@ impl Server {
|
|||||||
if client.is_player() {
|
if client.is_player() {
|
||||||
let id = client.player.as_ref().unwrap().entity_id();
|
let id = client.player.as_ref().unwrap().entity_id();
|
||||||
let uuid = client.gameprofile.as_ref().unwrap().id;
|
let uuid = client.gameprofile.as_ref().unwrap().id;
|
||||||
self.broadcast_packet_expect(&client, &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]));
|
self.broadcast_packet_expect(
|
||||||
self.broadcast_packet_expect(&client, &CRemoveEntities::new(&[id.into()]))
|
&[&client.token],
|
||||||
|
&CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]),
|
||||||
|
);
|
||||||
|
self.broadcast_packet_expect(&[&client.token], &CRemoveEntities::new(&[id.into()]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +235,7 @@ impl Server {
|
|||||||
|
|
||||||
// spawn player for every client
|
// spawn player for every client
|
||||||
self.broadcast_packet_expect(
|
self.broadcast_packet_expect(
|
||||||
client,
|
&[&client.token],
|
||||||
// TODO: add velo
|
// TODO: add velo
|
||||||
&CSpawnEntity::new(
|
&CSpawnEntity::new(
|
||||||
entity_id.into(),
|
entity_id.into(),
|
||||||
@ -316,11 +319,15 @@ impl Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcast_packet_expect<P>(&self, from: &Client, packet: &P)
|
pub fn broadcast_packet_expect<P>(&self, from: &[&Token], packet: &P)
|
||||||
where
|
where
|
||||||
P: ClientPacket,
|
P: ClientPacket,
|
||||||
{
|
{
|
||||||
for (_, client) in self.current_clients.iter().filter(|c| c.0 != &from.token) {
|
for (_, client) in self
|
||||||
|
.current_clients
|
||||||
|
.iter()
|
||||||
|
.filter(|c| !from.contains(&c.0.as_ref()))
|
||||||
|
{
|
||||||
// Check if client is a player
|
// Check if client is a player
|
||||||
let mut client = client.borrow_mut();
|
let mut client = client.borrow_mut();
|
||||||
if client.is_player() {
|
if client.is_player() {
|
||||||
@ -339,7 +346,7 @@ impl Server {
|
|||||||
"./world".parse().unwrap(),
|
"./world".parse().unwrap(),
|
||||||
);
|
);
|
||||||
level
|
level
|
||||||
.read_chunks(RadialIterator::new(2).collect(), sender)
|
.read_chunks(RadialIterator::new(7).collect(), sender)
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
pub mod math;
|
pub mod math;
|
||||||
|
pub mod vec3;
|
||||||
|
|||||||
79
pumpkin/src/util/vec3.rs
Normal file
79
pumpkin/src/util/vec3.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use std::ops::{Mul, Neg};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct Vec3 {
|
||||||
|
pub x: f64,
|
||||||
|
pub y: f64,
|
||||||
|
pub z: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vec3 {
|
||||||
|
pub fn new(x: f64, y: f64, z: f64) -> Self {
|
||||||
|
Vec3 { x, y, z }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn length(&self) -> f64 {
|
||||||
|
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalize(&self) -> Self {
|
||||||
|
let length = self.length();
|
||||||
|
Vec3 {
|
||||||
|
x: self.x / length,
|
||||||
|
y: self.y / length,
|
||||||
|
z: self.z / length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&self, other: &Vec3) -> Self {
|
||||||
|
Vec3 {
|
||||||
|
x: self.x + other.x,
|
||||||
|
y: self.y + other.y,
|
||||||
|
z: self.z + other.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub(&self, other: &Vec3) -> Self {
|
||||||
|
Vec3 {
|
||||||
|
x: self.x - other.x,
|
||||||
|
y: self.y - other.y,
|
||||||
|
z: self.z - other.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiply(self, x: f64, y: f64, z: f64) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x * x,
|
||||||
|
y: self.y * y,
|
||||||
|
z: self.z * z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul(self, scalar: f64) -> Self {
|
||||||
|
Vec3 {
|
||||||
|
x: self.x * scalar,
|
||||||
|
y: self.y * scalar,
|
||||||
|
z: self.z * scalar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f64> for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, scalar: f64) -> Self {
|
||||||
|
self.mul(scalar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg for Vec3 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self {
|
||||||
|
Vec3 {
|
||||||
|
x: -self.x,
|
||||||
|
y: -self.y,
|
||||||
|
z: -self.z,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user