Add: Basic Combat

This commit is contained in:
Snowiiii 2024-08-13 09:16:00 +02:00
parent c2bde2f73e
commit 9fc86e260b
15 changed files with 163 additions and 55 deletions

View File

@ -0,0 +1,17 @@
use pumpkin_macros::packet;
use serde::Serialize;
use crate::VarInt;
#[derive(Serialize)]
#[packet(0x24)]
pub struct CHurtAnimation {
entitiy_id: VarInt,
yaw: f32,
}
impl CHurtAnimation {
pub fn new(entitiy_id: VarInt, yaw: f32) -> Self {
Self { entitiy_id, yaw }
}
}

View File

@ -7,6 +7,7 @@ mod c_entity_animation;
mod c_entity_metadata; mod c_entity_metadata;
mod c_game_event; mod c_game_event;
mod c_head_rot; mod c_head_rot;
mod c_hurt_animation;
mod c_login; mod c_login;
mod c_open_screen; mod c_open_screen;
mod c_play_disconnect; mod c_play_disconnect;
@ -35,6 +36,7 @@ pub use c_entity_animation::*;
pub use c_entity_metadata::*; pub use c_entity_metadata::*;
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_login::*; pub use c_login::*;
pub use c_open_screen::*; pub use c_open_screen::*;
pub use c_play_disconnect::*; pub use c_play_disconnect::*;

View File

@ -0,0 +1,25 @@
use pumpkin_macros::packet;
use serde::Deserialize;
use crate::{ServerPacket, VarInt};
#[packet(0x16)]
pub struct SInteract {
pub entity_id: VarInt,
pub typ: VarInt,
pub target_x: Option<f32>,
// don't ask me why, adding more values does not work :c
}
// TODO
impl ServerPacket for SInteract {
fn read(
bytebuf: &mut crate::bytebuf::ByteBuffer,
) -> Result<Self, crate::bytebuf::DeserializerError> {
Ok(Self {
entity_id: bytebuf.get_var_int(),
typ: bytebuf.get_var_int(),
target_x: bytebuf.get_option(|v| v.get_f32()),
})
}
}

View File

@ -1,4 +1,5 @@
mod c_client_information; mod c_client_information;
mod c_interact;
mod s_chat_command; mod s_chat_command;
mod s_chat_message; mod s_chat_message;
mod s_confirm_teleport; mod s_confirm_teleport;
@ -9,6 +10,7 @@ mod s_player_rotation;
mod s_swing_arm; mod s_swing_arm;
pub use c_client_information::*; pub use c_client_information::*;
pub use c_interact::*;
pub use s_chat_command::*; pub use s_chat_command::*;
pub use s_chat_message::*; pub use s_chat_message::*;
pub use s_confirm_teleport::*; pub use s_confirm_teleport::*;

View File

@ -16,6 +16,7 @@ pub struct SChatMessage {
// acknowledged: BitSet, // acknowledged: BitSet,
} }
// TODO
impl ServerPacket for SChatMessage { impl ServerPacket for SChatMessage {
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> { fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
Ok(Self { Ok(Self {

View File

@ -4,7 +4,7 @@ use lazy_static::lazy_static;
use crate::world::WorldError; use crate::world::WorldError;
const BLOCKS_JSON: &'static str = include_str!("../blocks.json"); const BLOCKS_JSON: &str = include_str!("../blocks.json");
#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] #[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)]
struct BlockDefinition { struct BlockDefinition {

View File

@ -25,10 +25,9 @@
// } // }
// } // }
use std::{collections::HashMap, io::Write}; use std::collections::HashMap;
use fastnbt::LongArray; use fastnbt::LongArray;
use itertools::Itertools;
use crate::{world::WorldError, WORLD_HEIGHT}; use crate::{world::WorldError, WORLD_HEIGHT};
@ -157,7 +156,7 @@ impl ChunkData {
// } // }
// dbg!("{}", blocks.iter().filter(|v| **v == 2005).collect_vec().len()); // dbg!("{}", blocks.iter().filter(|v| **v == 2005).collect_vec().len());
Ok(ChunkData { Ok(ChunkData {
blocks: blocks, blocks,
position: at, position: at,
heightmaps: chunk_data.heightmaps, heightmaps: chunk_data.heightmaps,
}) })

View File

@ -1,15 +1,15 @@
use std::{collections::VecDeque, future, io::Read, path::PathBuf, sync::Arc}; use std::{io::Read, path::PathBuf, sync::Arc};
use flate2::bufread::ZlibDecoder; use flate2::bufread::ZlibDecoder;
use itertools::Itertools; use itertools::Itertools;
use thiserror::Error; use thiserror::Error;
use tokio::{ use tokio::{
fs::File, fs::File,
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncSeekExt},
sync::Mutex, sync::Mutex,
}; };
use crate::{chunk::ChunkData, dimension::Dimension}; use crate::chunk::ChunkData;
pub struct Level { pub struct Level {
root_folder: PathBuf, root_folder: PathBuf,

View File

@ -27,8 +27,8 @@ use pumpkin_protocol::{
handshake::SHandShake, handshake::SHandShake,
login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart},
play::{ play::{
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SPlayerCommand, SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSwingArm, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSwingArm,
}, },
status::{SPingRequest, SStatusRequest}, status::{SPingRequest, SStatusRequest},
}, },
@ -159,6 +159,8 @@ impl Client {
} }
pub fn set_gamemode(&mut self, gamemode: GameMode) { pub fn set_gamemode(&mut self, gamemode: GameMode) {
let player = self.player.as_mut().unwrap();
player.gamemode = gamemode;
self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap())); self.send_packet(&CGameEvent::new(3, gamemode.to_f32().unwrap()));
} }
@ -282,6 +284,9 @@ impl Client {
server, server,
SClientInformationPlay::read(bytebuf).unwrap(), SClientInformationPlay::read(bytebuf).unwrap(),
), ),
SInteract::PACKET_ID => {
self.handle_interact(server, SInteract::read(bytebuf).unwrap());
}
_ => log::error!("Failed to handle player packet id {}", packet.id.0), _ => log::error!("Failed to handle player packet id {}", packet.id.0),
} }
} }

View File

@ -1,13 +1,14 @@
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
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, COpenScreen, CUpdateEntityPos, CUpdateEntityPosRot, Animation, CEntityAnimation, CHeadRot, CHurtAnimation, COpenScreen, CUpdateEntityPos,
CUpdateEntityRot, CUpdateEntityPosRot, CUpdateEntityRot,
}, },
server::play::{ server::play::{
SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SPlayerCommand, SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract,
SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSwingArm, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, SPlayerRotation, SSwingArm,
}, },
VarInt, VarInt,
}; };
@ -15,7 +16,7 @@ use pumpkin_text::TextComponent;
use crate::{ use crate::{
commands::{handle_command, CommandSender}, commands::{handle_command, CommandSender},
entity::player::{ChatMode, Hand}, entity::player::{ChatMode, GameMode, Hand},
server::Server, server::Server,
util::math::wrap_degrees, util::math::wrap_degrees,
}; };
@ -256,4 +257,24 @@ impl Client {
server_listing: client_information.server_listing, server_listing: client_information.server_listing,
}); });
} }
pub fn handle_interact(&mut self, server: &mut Server, interact: SInteract) {
// 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
{
return;
}
drop(client);
if config.hurt_animation {
// todo
server.broadcast_packet(self, &CHurtAnimation::new(interact.entity_id, 10.0))
}
}
}
}
} }

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::client::authentication::ProfileAction; use crate::client::authentication::ProfileAction;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Authentication { pub struct AuthenticationConfig {
/// Whether to use Mojang authentication. /// Whether to use Mojang authentication.
pub enabled: bool, pub enabled: bool,
@ -81,7 +81,7 @@ impl Default for TextureTypes {
} }
} }
impl Default for Authentication { impl Default for AuthenticationConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: true, enabled: true,

View File

@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use auth_config::Authentication; use auth_config::AuthenticationConfig;
use resource_pack::ResourcePack; use resource_pack::ResourcePackConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{entity::player::GameMode, server::Difficulty}; use crate::{entity::player::GameMode, server::Difficulty};
@ -17,11 +17,12 @@ const CURRENT_BASE_VERSION: &str = "1.0.0";
/// This also allows you get some Performance or Resource boosts. /// This also allows you get some Performance or Resource boosts.
/// Important: The Configuration should match Vanilla by default /// Important: The Configuration should match Vanilla by default
pub struct AdvancedConfiguration { pub struct AdvancedConfiguration {
pub commands: Commands, pub commands: CommandsConfig,
pub authentication: Authentication, pub authentication: AuthenticationConfig,
pub packet_compression: Compression, pub packet_compression: CompressionConfig,
pub resource_pack: ResourcePack, pub resource_pack: ResourcePackConfig,
pub rcon: RCONConfig, pub rcon: RCONConfig,
pub pvp: PVPConfig,
} }
#[derive(Deserialize, Serialize, Clone)] #[derive(Deserialize, Serialize, Clone)]
@ -44,26 +45,52 @@ impl Default for RCONConfig {
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct Commands { pub struct CommandsConfig {
/// Are commands from the Console accepted ? /// Are commands from the Console accepted ?
pub use_console: bool, pub use_console: bool,
// TODO: commands... // TODO: commands...
} }
impl Default for CommandsConfig {
fn default() -> Self {
Self { use_console: true }
}
}
#[derive(Deserialize, Serialize)]
pub struct PVPConfig {
/// Is PVP enabled ?
pub enabled: bool,
/// Do we want to have the Red hurt animation & fov bobbing
pub hurt_animation: bool,
/// Should players in creative be protected against PVP
pub protect_creative: bool,
}
impl Default for PVPConfig {
fn default() -> Self {
Self {
enabled: true,
hurt_animation: true,
protect_creative: true,
}
}
}
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
// Packet compression // Packet compression
pub struct Compression { pub struct CompressionConfig {
// Is compression enabled ? /// Is compression enabled ?
pub enabled: bool, pub enabled: bool,
// The compression threshold used when compression is enabled /// The compression threshold used when compression is enabled
pub compression_threshold: u32, pub compression_threshold: u32,
// A value between 0..9 /// A value between 0..9
// 1 = Optimize for the best speed of encoding. /// 1 = Optimize for the best speed of encoding.
// 9 = Optimize for the size of data being encoded. /// 9 = Optimize for the size of data being encoded.
pub compression_level: u32, pub compression_level: u32,
} }
impl Default for Compression { impl Default for CompressionConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: true, enabled: true,
@ -73,21 +100,16 @@ impl Default for Compression {
} }
} }
impl Default for Commands {
fn default() -> Self {
Self { use_console: true }
}
}
/// Important: The Configuration should match Vanilla by default /// Important: The Configuration should match Vanilla by default
impl Default for AdvancedConfiguration { impl Default for AdvancedConfiguration {
fn default() -> Self { fn default() -> Self {
Self { Self {
authentication: Authentication::default(), authentication: AuthenticationConfig::default(),
commands: Commands::default(), commands: CommandsConfig::default(),
packet_compression: Compression::default(), packet_compression: CompressionConfig::default(),
resource_pack: ResourcePack::default(), resource_pack: ResourcePackConfig::default(),
rcon: RCONConfig::default(), rcon: RCONConfig::default(),
pvp: PVPConfig::default(),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct ResourcePack { pub struct ResourcePackConfig {
pub enabled: bool, pub enabled: bool,
/// The path to the resource pack. /// The path to the resource pack.
pub resource_pack_url: String, pub resource_pack_url: String,
@ -13,7 +13,7 @@ pub struct ResourcePack {
pub force: bool, pub force: bool,
} }
impl ResourcePack { impl ResourcePackConfig {
pub fn validate(&self) { pub fn validate(&self) {
assert_eq!( assert_eq!(
!self.resource_pack_url.is_empty(), !self.resource_pack_url.is_empty(),
@ -27,7 +27,7 @@ impl ResourcePack {
} }
} }
impl Default for ResourcePack { impl Default for ResourcePackConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: false, enabled: false,

View File

@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize};
pub struct Player { pub struct Player {
pub entity: Entity, pub entity: Entity,
// current gamemode
pub gamemode: GameMode,
// Client side value, Should be not trusted // Client side value, Should be not trusted
pub on_ground: bool, pub on_ground: bool,
@ -19,13 +21,14 @@ pub struct Player {
} }
impl Player { impl Player {
pub fn new(entity_id: EntityId) -> Self { pub fn new(entity_id: EntityId, gamemode: GameMode) -> Self {
Self { Self {
entity: Entity::new(entity_id, EntityType::Player), entity: Entity::new(entity_id, EntityType::Player),
on_ground: false, on_ground: false,
awaiting_teleport: None, awaiting_teleport: None,
sneaking: false, sneaking: false,
sprinting: false, sprinting: false,
gamemode,
} }
} }

View File

@ -1,5 +1,5 @@
use std::{ use std::{
cell::RefCell, cell::{RefCell, RefMut},
collections::HashMap, collections::HashMap,
io::Cursor, io::Cursor,
rc::Rc, rc::Rc,
@ -23,7 +23,7 @@ use pumpkin_protocol::{
}, },
}, },
uuid::UUID, uuid::UUID,
BitSet, ClientPacket, Players, Sample, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL, ClientPacket, Players, Sample, StatusResponse, VarInt, Version, CURRENT_MC_PROTOCOL,
}; };
use pumpkin_world::dimension::Dimension; use pumpkin_world::dimension::Dimension;
@ -146,8 +146,12 @@ impl Server {
pub async fn spawn_player(&mut self, client: &mut Client) { pub async fn spawn_player(&mut self, client: &mut Client) {
// This code follows the vanilla packet order // This code follows the vanilla packet order
let entity_id = self.new_entity_id(); let entity_id = self.new_entity_id();
let gamemode = match self.base_config.default_gamemode {
GameMode::Undefined => GameMode::Survival,
game_mode => game_mode,
};
log::debug!("spawning player, entity id {}", entity_id); log::debug!("spawning player, entity id {}", entity_id);
let player = Player::new(entity_id); let player = Player::new(entity_id, gamemode);
client.player = Some(player); client.player = Some(player);
// login packet for our new player // login packet for our new player
@ -164,12 +168,7 @@ impl Server {
0.into(), 0.into(),
"minecraft:overworld", "minecraft:overworld",
0, // seed 0, // seed
match self.base_config.default_gamemode { gamemode.to_u8().unwrap(),
GameMode::Undefined => GameMode::Survival,
game_mode => game_mode,
}
.to_u8()
.unwrap(),
self.base_config.default_gamemode.to_i8().unwrap(), self.base_config.default_gamemode.to_i8().unwrap(),
false, false,
false, false,
@ -291,8 +290,20 @@ impl Server {
Server::spawn_test_chunk(client).await; Server::spawn_test_chunk(client).await;
} }
/// TODO: This definitly should be in world
pub fn get_by_entityid(&self, from: &Client, id: EntityId) -> Option<RefMut<Client>> {
for (_, client) in self.current_clients.iter().filter(|c| c.0 != &from.token) {
// Check if client is a player
let client = client.borrow_mut();
if client.is_player() && client.player.as_ref().unwrap().entity_id() == id {
return Some(client);
}
}
None
}
/// Sends a Packet to all Players /// Sends a Packet to all Players
pub fn broadcast_packet<P>(&mut self, from: &mut Client, packet: &P) pub fn broadcast_packet<P>(&self, from: &mut Client, packet: &P)
where where
P: ClientPacket, P: ClientPacket,
{ {
@ -308,7 +319,7 @@ impl Server {
} }
} }
pub fn broadcast_packet_expect<P>(&mut self, from: &mut Client, packet: &P) pub fn broadcast_packet_expect<P>(&self, from: &Client, packet: &P)
where where
P: ClientPacket, P: ClientPacket,
{ {