Skip to content

Commit

Permalink
Added Basic Attack Modifiers (#383)
Browse files Browse the repository at this point in the history
* Added basic attack modifiers
  • Loading branch information
OfficialKris authored Dec 8, 2024
1 parent d0d0f35 commit 4d5b7ac
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 17 deletions.
21 changes: 21 additions & 0 deletions pumpkin-world/src/item/item_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,30 @@ pub struct ItemComponents {
pub max_stack_size: u8,
#[serde(rename = "minecraft:jukebox_playable")]
pub jukebox_playable: Option<JukeboxPlayable>,
#[serde(rename = "minecraft:damage")]
pub damage: Option<u16>,
#[serde(rename = "minecraft:max_damage")]
pub max_damage: Option<u16>,
#[serde(rename = "minecraft:attribute_modifiers")]
pub attribute_modifiers: Option<AttributeModifiers>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct JukeboxPlayable {
pub song: String,
}

#[derive(Deserialize, Clone, Debug)]
pub struct AttributeModifiers {
pub modifiers: Vec<Modifier>,
}

#[derive(Deserialize, Clone, Debug)]
pub struct Modifier {
#[serde(rename = "type")]
pub type_val: String,
pub id: String,
pub amount: f64,
pub operation: String,
pub slot: String,
}
74 changes: 57 additions & 17 deletions pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::{

use crossbeam::atomic::AtomicCell;
use num_derive::{FromPrimitive, ToPrimitive};
use pumpkin_config::ADVANCED_CONFIG;
use num_traits::Pow;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_core::{
math::{
boundingbox::{BoundingBox, BoundingBoxSize},
Expand Down Expand Up @@ -42,7 +43,10 @@ use pumpkin_protocol::{
client::play::{CSetEntityMetadata, Metadata},
server::play::{SClickContainer, SKeepAlive},
};
use pumpkin_world::{cylindrical_chunk_iterator::Cylindrical, item::ItemStack};
use pumpkin_world::{
cylindrical_chunk_iterator::Cylindrical,
item::{item_registry::get_item_by_id, ItemStack},
};
use tokio::sync::{Mutex, Notify};

use super::Entity;
Expand Down Expand Up @@ -228,16 +232,54 @@ impl Player {
let attacker_entity = &self.living_entity.entity;
let config = &ADVANCED_CONFIG.pvp;

let pos = victim_entity.pos.load();
let inventory = self.inventory().lock().await;
let item_slot = inventory.held_item();

let base_damage = 1.0;
let base_attack_speed = 4.0;

let mut damage_multiplier = 1.0;
let mut add_damage = 0.0;
let mut add_speed = 0.0;

// get attack damage
if let Some(item_stack) = item_slot {
if let Some(item) = get_item_by_id(item_stack.item_id) {
// TODO: this should be cached in memory
if let Some(modifiers) = &item.components.attribute_modifiers {
for item_mod in &modifiers.modifiers {
if item_mod.operation == "add_value" {
if item_mod.id == "minecraft:base_attack_damage" {
add_damage = item_mod.amount;
}
if item_mod.id == "minecraft:base_attack_speed" {
add_speed = item_mod.amount;
}
}
}
}
}
}
drop(inventory);

let attack_speed = base_attack_speed + add_speed;

let attack_cooldown_progress = self.get_attack_cooldown_progress(0.5);
let attack_cooldown_progress = self.get_attack_cooldown_progress(0.5, attack_speed);
self.last_attacked_ticks
.store(0, std::sync::atomic::Ordering::Relaxed);

// TODO: attack damage attribute and deal damage
let mut damage = 1.0;
// only reduce attack damage if in cooldown
// TODO: Enchantments are reduced same way just without the square
if attack_cooldown_progress < 1.0 {
damage_multiplier = 0.2 + attack_cooldown_progress.pow(2) * 0.8;
}
// modify added damage based on multiplier
let mut damage = base_damage + add_damage * damage_multiplier;

let pos = victim_entity.pos.load();

if (config.protect_creative && victim.gamemode.load() == GameMode::Creative)
|| !victim.living_entity.check_damage(damage)
|| !victim.living_entity.check_damage(damage as f32)
{
world
.play_sound(
Expand All @@ -253,7 +295,7 @@ impl Player {
.play_sound(sound!("entity.player.hurt"), SoundCategory::Players, &pos)
.await;

let attack_type = AttackType::new(self, attack_cooldown_progress).await;
let attack_type = AttackType::new(self, attack_cooldown_progress as f32).await;

player_attack_sound(&pos, world, attack_type).await;

Expand All @@ -263,7 +305,7 @@ impl Player {

victim
.living_entity
.damage(damage, 34) // PlayerAttack
.damage(damage as f32, 34) // PlayerAttack
.await;

let mut knockback_strength = 1.0;
Expand Down Expand Up @@ -327,16 +369,14 @@ impl Player {
}
}

pub fn get_attack_cooldown_progress(&self, base_time: f32) -> f32 {
pub fn get_attack_cooldown_progress(&self, base_time: f64, attack_speed: f64) -> f64 {
#[allow(clippy::cast_precision_loss)]
let x = self
.last_attacked_ticks
.load(std::sync::atomic::Ordering::Acquire) as f32
+ base_time;
// TODO attack speed attribute
let attack_speed = 4.0;
let progress_per_tick = 1.0 / attack_speed * 20.0;
let x = f64::from(
self.last_attacked_ticks
.load(std::sync::atomic::Ordering::Acquire),
) + base_time;

let progress_per_tick = f64::from(BASIC_CONFIG.tps) / attack_speed;
let progress = x / progress_per_tick;
progress.clamp(0.0, 1.0)
}
Expand Down

0 comments on commit 4d5b7ac

Please sign in to comment.