Make non Player entities attackable
This commit is contained in:
parent
8d2ca8e404
commit
79ad1c40f3
@ -15,10 +15,22 @@ struct DamageTypeEntry {
|
||||
pub struct DamageTypeData {
|
||||
death_message_type: Option<DeathMessageType>,
|
||||
exhaustion: f32,
|
||||
effects: Option<DamageEffects>,
|
||||
message_id: String,
|
||||
scaling: DamageScaling,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DamageEffects {
|
||||
Hurt,
|
||||
Thorns,
|
||||
Drowning,
|
||||
Burning,
|
||||
Poking,
|
||||
Freezing,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum DamageScaling {
|
||||
@ -59,6 +71,14 @@ pub(crate) fn build() -> TokenStream {
|
||||
None => quote! { None },
|
||||
};
|
||||
|
||||
let effects = match &data.effects {
|
||||
Some(msg) => {
|
||||
let msg_ident = Ident::new(&format!("{:?}", msg), proc_macro2::Span::call_site());
|
||||
quote! { Some(DamageEffects::#msg_ident) }
|
||||
}
|
||||
None => quote! { None },
|
||||
};
|
||||
|
||||
let exhaustion = data.exhaustion;
|
||||
let message_id = &data.message_id;
|
||||
let scaling_ident = Ident::new(
|
||||
@ -72,6 +92,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub const #const_ident: DamageType = DamageType {
|
||||
death_message_type: #death_message_type,
|
||||
exhaustion: #exhaustion,
|
||||
effects: #effects,
|
||||
message_id: #message_id,
|
||||
scaling: #scaling,
|
||||
id: #id_lit,
|
||||
@ -93,6 +114,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
pub struct DamageType {
|
||||
pub death_message_type: Option<DeathMessageType>,
|
||||
pub exhaustion: f32,
|
||||
pub effects: Option<DamageEffects>,
|
||||
pub message_id: &'static str,
|
||||
pub scaling: DamageScaling,
|
||||
pub id: u32,
|
||||
@ -105,6 +127,16 @@ pub(crate) fn build() -> TokenStream {
|
||||
IntentionalGameDesign,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum DamageEffects {
|
||||
Hurt,
|
||||
Thorns,
|
||||
Drowning,
|
||||
Burning,
|
||||
Poking,
|
||||
Freezing,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum DamageScaling {
|
||||
Never,
|
||||
|
||||
@ -417,7 +417,7 @@ impl Cache2D {
|
||||
pub fn new(input_index: usize, min_value: f64, max_value: f64) -> Self {
|
||||
Self {
|
||||
input_index,
|
||||
// I know this is because theres is definately world coords that are this marker, but this
|
||||
// I know this is because theres is definitely world coords that are this marker, but this
|
||||
// is how vanilla does it, so I'm going to for pairity
|
||||
last_sample_column: chunk_pos::MARKER,
|
||||
last_sample_result: Default::default(),
|
||||
|
||||
@ -61,23 +61,18 @@ impl AttackType {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_knockback(
|
||||
attacker_entity: &Entity,
|
||||
victim: &Player,
|
||||
victim_entity: &Entity,
|
||||
strength: f64,
|
||||
) {
|
||||
let yaw = attacker_entity.yaw.load();
|
||||
pub async fn handle_knockback(attacker: &Entity, world: &World, victim: &Entity, strength: f64) {
|
||||
let yaw = attacker.yaw.load();
|
||||
|
||||
let saved_velo = victim_entity.velocity.load();
|
||||
victim_entity.knockback(
|
||||
let saved_velo = victim.velocity.load();
|
||||
victim.knockback(
|
||||
strength * 0.5,
|
||||
f64::from((yaw.to_radians()).sin()),
|
||||
f64::from(-(yaw.to_radians()).cos()),
|
||||
);
|
||||
|
||||
let entity_id = VarInt(victim_entity.entity_id);
|
||||
let victim_velocity = victim_entity.velocity.load();
|
||||
let entity_id = VarInt(victim.entity_id);
|
||||
let victim_velocity = victim.velocity.load();
|
||||
|
||||
let packet = &CEntityVelocity::new(
|
||||
&entity_id,
|
||||
@ -85,13 +80,11 @@ pub async fn handle_knockback(
|
||||
victim_velocity.y,
|
||||
victim_velocity.z,
|
||||
);
|
||||
let velocity = attacker_entity.velocity.load();
|
||||
attacker_entity
|
||||
.velocity
|
||||
.store(velocity.multiply(0.6, 1.0, 0.6));
|
||||
let velocity = attacker.velocity.load();
|
||||
attacker.velocity.store(velocity.multiply(0.6, 1.0, 0.6));
|
||||
|
||||
victim_entity.velocity.store(saved_velo);
|
||||
victim.client.send_packet(packet).await;
|
||||
victim.velocity.store(saved_velo);
|
||||
world.broadcast_packet_all(packet).await;
|
||||
}
|
||||
|
||||
pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: &Vector3<f64>) {
|
||||
|
||||
@ -30,7 +30,7 @@ impl ItemEntity {
|
||||
}
|
||||
pub async fn send_meta_packet(&self) {
|
||||
self.entity
|
||||
.send_meta_data(Metadata::new(8, MetaDataType::ItemStack, self.item.clone()))
|
||||
.send_meta_data(Metadata::new(8, MetaDataType::ItemStack, &self.item))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ use super::{
|
||||
combat::{self, player_attack_sound, AttackType},
|
||||
hunger::HungerManager,
|
||||
item::ItemEntity,
|
||||
Entity, EntityId, NBTStorage,
|
||||
Entity, EntityBase, EntityId, NBTStorage,
|
||||
};
|
||||
use crate::{
|
||||
command::{client_suggestions, dispatcher::CommandDispatcher},
|
||||
@ -271,9 +271,10 @@ impl Player {
|
||||
//self.world().level.list_cached();
|
||||
}
|
||||
|
||||
pub async fn attack(&self, victim: &Arc<Self>) {
|
||||
pub async fn attack(&self, victim: Arc<dyn EntityBase>) {
|
||||
let world = self.world();
|
||||
let victim_entity = &victim.living_entity.entity;
|
||||
let victim_entity = victim.get_entity();
|
||||
let victim_living_entity = victim.get_living_entity();
|
||||
let attacker_entity = &self.living_entity.entity;
|
||||
let config = &ADVANCED_CONFIG.pvp;
|
||||
|
||||
@ -321,17 +322,17 @@ impl Player {
|
||||
|
||||
let pos = victim_entity.pos.load();
|
||||
|
||||
if (config.protect_creative && victim.gamemode.load() == GameMode::Creative)
|
||||
|| !victim.living_entity.check_damage(damage as f32)
|
||||
{
|
||||
world
|
||||
.play_sound(
|
||||
Sound::EntityPlayerAttackNodamage,
|
||||
SoundCategory::Players,
|
||||
&pos,
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
if let Some(living) = victim_living_entity {
|
||||
if !living.check_damage(damage as f32) {
|
||||
world
|
||||
.play_sound(
|
||||
Sound::EntityPlayerAttackNodamage,
|
||||
SoundCategory::Players,
|
||||
&pos,
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
world
|
||||
@ -346,10 +347,11 @@ impl Player {
|
||||
damage *= 1.5;
|
||||
}
|
||||
|
||||
victim
|
||||
.living_entity
|
||||
.damage(damage as f32, DamageType::PLAYER_ATTACK)
|
||||
.await;
|
||||
if let Some(living) = victim_living_entity {
|
||||
living
|
||||
.damage(damage as f32, DamageType::PLAYER_ATTACK)
|
||||
.await;
|
||||
}
|
||||
|
||||
let mut knockback_strength = 1.0;
|
||||
match attack_type {
|
||||
@ -361,7 +363,7 @@ impl Player {
|
||||
};
|
||||
|
||||
if config.knockback {
|
||||
combat::handle_knockback(attacker_entity, victim, victim_entity, knockback_strength)
|
||||
combat::handle_knockback(attacker_entity, world, victim_entity, knockback_strength)
|
||||
.await;
|
||||
}
|
||||
|
||||
@ -913,6 +915,17 @@ impl NBTStorage for Player {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl EntityBase for Player {
|
||||
fn get_entity(&self) -> &Entity {
|
||||
&self.living_entity.entity
|
||||
}
|
||||
|
||||
fn get_living_entity(&self) -> Option<&LivingEntity> {
|
||||
Some(&self.living_entity)
|
||||
}
|
||||
}
|
||||
|
||||
impl Player {
|
||||
pub async fn process_packets(self: &Arc<Self>, server: &Arc<Server>) {
|
||||
let mut packets = self.client.client_packets_queue.lock().await;
|
||||
|
||||
@ -13,8 +13,10 @@ use crate::{
|
||||
world::chunker,
|
||||
};
|
||||
use pumpkin_config::ADVANCED_CONFIG;
|
||||
use pumpkin_data::entity::{entity_from_egg, EntityPose, EntityType};
|
||||
use pumpkin_data::entity::{entity_from_egg, EntityType};
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::sound::Sound;
|
||||
use pumpkin_data::sound::SoundCategory;
|
||||
use pumpkin_data::world::CHAT;
|
||||
use pumpkin_inventory::player::PlayerInventory;
|
||||
use pumpkin_inventory::InventoryError;
|
||||
@ -741,27 +743,40 @@ impl Player {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: set as camera entity when specator
|
||||
|
||||
let world = &entity.world;
|
||||
let player_victim = world.get_player_by_id(entity_id.0).await;
|
||||
let entity_victim = world.get_entity_by_id(entity_id.0).await;
|
||||
if entity_id.0 == self.entity_id() {
|
||||
// this can't be triggered from a non-modded client.
|
||||
self.kick(TextComponent::translate(
|
||||
"multiplayer.disconnect.invalid_entity_attacked",
|
||||
[].into(),
|
||||
))
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
if let Some(player_victim) = player_victim {
|
||||
if player_victim.living_entity.health.load() <= 0.0 {
|
||||
// you can trigger this from a non-modded / innocent client client,
|
||||
// so we shouldn't kick the player
|
||||
return;
|
||||
}
|
||||
self.attack(&player_victim).await;
|
||||
} else if let Some(entity_victim) = entity_victim {
|
||||
// Checks if victim is a living entity
|
||||
if let Some(entity_victim) = entity_victim.get_living_entity() {
|
||||
if entity_victim.health.load() <= 0.0 {
|
||||
return;
|
||||
}
|
||||
entity_victim.entity.set_pose(EntityPose::Dying).await;
|
||||
entity_victim.kill().await;
|
||||
world.clone().remove_entity(&entity_victim.entity).await;
|
||||
if config.protect_creative
|
||||
&& player_victim.gamemode.load() == GameMode::Creative
|
||||
{
|
||||
world
|
||||
.play_sound(
|
||||
Sound::EntityPlayerAttackNodamage,
|
||||
SoundCategory::Players,
|
||||
&player_victim.position(),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
// TODO: block entities should be checked here (signs)
|
||||
self.attack(player_victim).await;
|
||||
} else if let Some(entity_victim) = world.get_entity_by_id(entity_id.0).await {
|
||||
self.attack(entity_victim).await;
|
||||
} else {
|
||||
log::error!(
|
||||
"Player id {} interacted with entity id {} which was not found.",
|
||||
@ -775,12 +790,6 @@ impl Player {
|
||||
.await;
|
||||
return;
|
||||
};
|
||||
|
||||
if entity_id.0 == self.entity_id() {
|
||||
// this, however, can't be triggered from a non-modded client.
|
||||
self.kick(TextComponent::text("You can't attack yourself"))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
ActionType::Interact | ActionType::InteractAt => {
|
||||
log::debug!("todo");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user