Skip to content

Commit

Permalink
Add Basic Combat
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Aug 14, 2024
1 parent 03cc991 commit 6459aef
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 32 deletions.
24 changes: 24 additions & 0 deletions pumpkin-protocol/src/client/play/c_entity_velocity.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
8 changes: 4 additions & 4 deletions pumpkin-protocol/src/client/play/c_hurt_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ use crate::VarInt;

#[derive(Serialize)]
#[packet(0x24)]
pub struct CHurtAnimation {
entitiy_id: VarInt,
pub struct CHurtAnimation<'a> {
entitiy_id: &'a VarInt,
yaw: f32,
}

impl CHurtAnimation {
pub fn new(entitiy_id: VarInt, yaw: f32) -> Self {
impl<'a> CHurtAnimation<'a> {
pub fn new(entitiy_id: &'a VarInt, yaw: f32) -> Self {
Self { entitiy_id, yaw }
}
}
2 changes: 2 additions & 0 deletions pumpkin-protocol/src/client/play/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod c_chunk_data;
mod c_disguised_chat_message;
mod c_entity_animation;
mod c_entity_metadata;
mod c_entity_velocity;
mod c_game_event;
mod c_head_rot;
mod c_hurt_animation;
Expand Down Expand Up @@ -34,6 +35,7 @@ pub use c_chunk_data::*;
pub use c_disguised_chat_message::*;
pub use c_entity_animation::*;
pub use c_entity_metadata::*;
pub use c_entity_velocity::*;
pub use c_game_event::*;
pub use c_head_rot::*;
pub use c_hurt_animation::*;
Expand Down
1 change: 0 additions & 1 deletion pumpkin-world/src/radial_chunk_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

pub struct RadialIterator {
radius: i32,
direction: usize,
Expand Down
7 changes: 7 additions & 0 deletions pumpkin/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ impl Client {
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) {
let player = self.player.as_mut().unwrap();
player.gamemode = gamemode;
Expand Down
60 changes: 46 additions & 14 deletions pumpkin/src/client/player_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use pumpkin_entity::EntityId;
use pumpkin_inventory::WindowType;
use pumpkin_protocol::{
client::play::{
Animation, CEntityAnimation, CHeadRot, CHurtAnimation, COpenScreen, CUpdateEntityPos,
CUpdateEntityPosRot, CUpdateEntityRot,
Animation, CEntityAnimation, CEntityVelocity, CHeadRot, CHurtAnimation, COpenScreen,
CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot,
},
server::play::{
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
Expand Down Expand Up @@ -114,8 +114,8 @@ impl Client {
entity.x = Self::clamp_horizontal(position_rotation.x);
entity.y = Self::clamp_vertical(position_rotation.feet_y);
entity.z = Self::clamp_horizontal(position_rotation.z);
entity.yaw = wrap_degrees(position_rotation.yaw);
entity.pitch = wrap_degrees(position_rotation.pitch);
entity.yaw = wrap_degrees(position_rotation.yaw).clamp(-90.0, 90.0) % 360.0;
entity.pitch = wrap_degrees(position_rotation.pitch) % 360.0;

// send new position to all other players
let on_ground = player.on_ground;
Expand Down Expand Up @@ -149,8 +149,8 @@ impl Client {
}
let player = self.player.as_mut().unwrap();
let entity = &mut player.entity;
entity.yaw = wrap_degrees(rotation.yaw);
entity.pitch = wrap_degrees(rotation.pitch);
entity.yaw = wrap_degrees(rotation.yaw).clamp(-90.0, 90.0) % 360.0;
entity.pitch = wrap_degrees(rotation.pitch) % 360.0;
// send new position to all other players
let on_ground = player.on_ground;
let entity_id = entity.entity_id;
Expand Down Expand Up @@ -195,7 +195,10 @@ impl Client {
};
let player = self.player.as_mut().unwrap();
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) {
Expand Down Expand Up @@ -264,21 +267,50 @@ impl Client {
}

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
let config = &server.advanced_config.pvp;
if config.enabled {
let attacked_client = server.get_by_entityid(self, interact.entity_id.0 as EntityId);
if let Some(client) = attacked_client {
if config.protect_creative
&& client.player.as_ref().unwrap().gamemode == GameMode::Creative
{
let attacked_client = server.get_by_entityid(self, entity_id.0 as EntityId);
if let Some(mut client) = attacked_client {
let token = client.token.clone();
let player = client.player.as_mut().unwrap();
let velo = player.velocity;
if config.protect_creative && player.gamemode == GameMode::Creative {
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 {
// 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")
}
}
}
Expand Down
15 changes: 8 additions & 7 deletions pumpkin/src/commands/gamemode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ impl<'a> Command<'a> for GamemodeCommand {
}
Err(_) => {
// try to parse from number
if let Ok(i) = mode_str.parse::<u8>() { if let Some(mode) = GameMode::from_u8(i) {
player.set_gamemode(mode);
player.send_system_message(
format!("Set own game mode to {:?}", mode).into(),
);
return;
} }
if let Ok(i) = mode_str.parse::<u8>() {
if let Some(mode) = GameMode::from_u8(i) {
player.set_gamemode(mode);
player
.send_system_message(format!("Set own game mode to {:?}", mode).into());
return;
}
}

player.send_system_message(
TextComponent::from("Invalid gamemode")
Expand Down
3 changes: 3 additions & 0 deletions pumpkin/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub struct PVPConfig {
pub hurt_animation: bool,
/// Should players in creative be protected against PVP
pub protect_creative: bool,
/// Has PVP Knockback?
pub knockback: bool,
}

impl Default for PVPConfig {
Expand All @@ -73,6 +75,7 @@ impl Default for PVPConfig {
enabled: true,
hurt_animation: true,
protect_creative: true,
knockback: true,
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ use pumpkin_entity::{entity_type::EntityType, Entity, EntityId};
use pumpkin_protocol::VarInt;
use serde::{Deserialize, Serialize};

use crate::util::vec3::Vec3;

pub struct Player {
pub entity: Entity,
// current 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
pub on_ground: bool,

pub sneaking: bool,
pub sprinting: bool,

pub velocity: Vec3,

// Current awaiting teleport id, None if did not teleport
pub awaiting_teleport: Option<VarInt>,
}
Expand All @@ -28,13 +36,40 @@ impl Player {
awaiting_teleport: None,
sneaking: 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,
}
}

pub fn entity_id(&self) -> EntityId {
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)]
Expand Down
19 changes: 13 additions & 6 deletions pumpkin/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,11 @@ impl Server {
if client.is_player() {
let id = client.player.as_ref().unwrap().entity_id();
let uuid = client.gameprofile.as_ref().unwrap().id;
self.broadcast_packet_expect(&client, &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]));
self.broadcast_packet_expect(&client, &CRemoveEntities::new(&[id.into()]))
self.broadcast_packet_expect(
&[&client.token],
&CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]),
);
self.broadcast_packet_expect(&[&client.token], &CRemoveEntities::new(&[id.into()]))
}
}

Expand Down Expand Up @@ -232,7 +235,7 @@ impl Server {

// spawn player for every client
self.broadcast_packet_expect(
client,
&[&client.token],
// TODO: add velo
&CSpawnEntity::new(
entity_id.into(),
Expand Down Expand Up @@ -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
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
let mut client = client.borrow_mut();
if client.is_player() {
Expand All @@ -339,7 +346,7 @@ impl Server {
"./world".parse().unwrap(),
);
level
.read_chunks(RadialIterator::new(2).collect(), sender)
.read_chunks(RadialIterator::new(7).collect(), sender)
.await;
});

Expand Down
1 change: 1 addition & 0 deletions pumpkin/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod math;
pub mod vec3;
Loading

0 comments on commit 6459aef

Please sign in to comment.