Skip to content

Commit

Permalink
Improve damage type
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Feb 7, 2025
1 parent ec0e8a7 commit 5c5bc67
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 87 deletions.
67 changes: 9 additions & 58 deletions pumpkin-data/build/damage_type.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use heck::{ToPascalCase, ToShoutySnakeCase};
use heck::ToShoutySnakeCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use serde::Deserialize;
use std::collections::HashMap;
use syn::LitInt;

#[derive(Deserialize)]
struct DamageTypeEntry {
Expand Down Expand Up @@ -30,9 +31,8 @@ pub(crate) fn build() -> TokenStream {

for (name, entry) in damage_types {
let const_ident = format_ident!("{}", name.to_shouty_snake_case());
let enum_ident = format_ident!("{}", name.to_pascal_case());

enum_variants.push(enum_ident.clone());
enum_variants.push(const_ident.clone());

let data = &entry.components;
let death_message_type = match &data.death_message_type {
Expand All @@ -43,27 +43,19 @@ pub(crate) fn build() -> TokenStream {
let exhaustion = data.exhaustion;
let message_id = &data.message_id;
let scaling = &data.scaling;
let id = entry.id;
let id_lit = LitInt::new(&entry.id.to_string(), proc_macro2::Span::call_site());

constants.push(quote! {
pub const #const_ident: DamageTypeData = DamageTypeData {
pub const #const_ident: DamageType = DamageType {
death_message_type: #death_message_type,
exhaustion: #exhaustion,
message_id: #message_id,
scaling: #scaling,
id: #id,
id: #id_lit,
};
});
}

let enum_arms = enum_variants.iter().map(|variant| {
let const_name = variant.to_string().to_shouty_snake_case();
let const_ident = format_ident!("{}", &const_name);
quote! {
DamageType::#variant => &#const_ident,
}
});

let type_name_pairs = enum_variants.iter().map(|variant| {
let name = variant.to_string();
let name_lowercase = name.to_lowercase();
Expand All @@ -73,53 +65,18 @@ pub(crate) fn build() -> TokenStream {
}
});

let type_to_name_pairs = enum_variants.iter().map(|variant| {
let name = variant.to_string();
let name_lowercase = name.to_lowercase();
let resource_name = format!("minecraft:{}", name_lowercase);
quote! {
Self::#variant => #resource_name
}
});

// Create array of all variants for values() method
let variant_array = enum_variants.iter().map(|variant| {
quote! {
DamageType::#variant
}
});

quote! {
#[derive(Clone, Debug)]
pub struct DamageTypeData {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DamageType {
pub death_message_type: Option<&'static str>,
pub exhaustion: f32,
pub message_id: &'static str,
pub scaling: &'static str,
pub id: u32,
}

#(#constants)*

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DamageType {
#(#enum_variants,)*
}

impl DamageType {
pub const fn data(&self) -> &'static DamageTypeData {
match self {
#(#enum_arms)*
}
}

#[doc = r" Get all possible damage types"]
pub fn values() -> &'static [DamageType] {
static VALUES: &[DamageType] = &[
#(#variant_array,)*
];
VALUES
}
#(#constants)*

#[doc = r" Try to parse a damage type from a resource location string"]
pub fn from_name(name: &str) -> Option<Self> {
Expand All @@ -129,12 +86,6 @@ pub(crate) fn build() -> TokenStream {
}
}

#[doc = r" Get the resource location string for this damage type"]
pub const fn to_name(&self) -> &'static str {
match self {
#(#type_to_name_pairs,)*
}
}
}
}
}
24 changes: 9 additions & 15 deletions pumpkin/src/command/args/damage_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ pub struct DamageTypeArgumentConsumer;

impl GetClientSideArgParser for DamageTypeArgumentConsumer {
fn get_client_side_parser(&self) -> ArgumentType {
ArgumentType::ResourceLocation
ArgumentType::Resource {
identifier: "damage_type",
}
}

fn get_client_side_suggestion_type_override(&self) -> Option<SuggestionProviders> {
Some(SuggestionProviders::AskServer)
None
}
}

Expand All @@ -30,15 +32,12 @@ impl ArgumentConsumer for DamageTypeArgumentConsumer {
_server: &'a Server,
args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> {
let s = args.pop()?;
let name = args.pop()?;

// Create a static damage type first
let damage_type = DamageType::from_name(s)?;
let damage_type = DamageType::from_name(name)?;
// Find matching static damage type from values array
DamageType::values()
.iter()
.find(|&&dt| std::mem::discriminant(&dt) == std::mem::discriminant(&damage_type))
.map(Arg::DamageType)
Some(Arg::DamageType(damage_type))
}

async fn suggest<'a>(
Expand All @@ -47,18 +46,13 @@ impl ArgumentConsumer for DamageTypeArgumentConsumer {
_server: &'a Server,
_input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
// Get all available damage types
let suggestions = DamageType::values()
.iter()
.map(|dt| CommandSuggestion::new(dt.to_name().to_string(), None))
.collect();
Ok(Some(suggestions))
Ok(None)
}
}

impl DefaultNameArgConsumer for DamageTypeArgumentConsumer {
fn default_name(&self) -> &'static str {
"damageType"
"damage_type"
}
}

Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/command/args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub enum Arg<'a> {
#[allow(unused)]
Simple(&'a str),
SoundCategory(SoundCategory),
DamageType(&'a DamageType),
DamageType(DamageType),
}

/// see [`crate::commands::tree::builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree::builder::NonLeafNodeBuilder::execute`]
Expand Down
12 changes: 6 additions & 6 deletions pumpkin/src/command/commands/damage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,9 @@ impl CommandExecutor for DamageLocationExecutor {

let damage_type = args
.get(ARG_DAMAGE_TYPE)
.map_or(DamageType::Generic, |arg| match arg {
Arg::DamageType(dt) => **dt,
_ => DamageType::Generic,
.map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => *dt,
_ => DamageType::GENERIC,
});

let location = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
Expand Down Expand Up @@ -122,9 +122,9 @@ impl CommandExecutor for DamageEntityExecutor {

let damage_type = args
.get(ARG_DAMAGE_TYPE)
.map_or(DamageType::Generic, |arg| match arg {
Arg::DamageType(dt) => **dt,
_ => DamageType::Generic,
.map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => *dt,
_ => DamageType::GENERIC,
});

let source = EntityArgumentConsumer::find_arg(args, ARG_ENTITY).ok();
Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/entity/hunger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl HungerManager {
} else if level == 0 {
self.tick_timer.fetch_add(1);
if self.tick_timer.load() >= 80 {
player.living_entity.damage(1.0, DamageType::Starve).await;
player.living_entity.damage(1.0, DamageType::STARVE).await;
self.tick_timer.store(0);
}
} else {
Expand Down
6 changes: 3 additions & 3 deletions pumpkin/src/entity/living.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ impl LivingEntity {
cause: Option<&Entity>,
) -> bool {
// Check invulnerability before applying damage
if self.entity.is_invulnerable_to(damage_type) {
if self.entity.is_invulnerable_to(&damage_type) {
return false;
}

self.entity
.world
.broadcast_packet_all(&CDamageEvent::new(
self.entity.entity_id.into(),
damage_type.data().id.into(),
damage_type.id.into(),
source.map(|e| e.entity_id.into()),
cause.map(|e| e.entity_id.into()),
position,
Expand Down Expand Up @@ -156,7 +156,7 @@ impl LivingEntity {
.play_sound(Self::get_fall_sound(fall_distance as i32))
.await;
// TODO: Play block fall sound
self.damage(damage, DamageType::Fall).await; // Fall
self.damage(damage, DamageType::FALL).await; // Fall
} else if height_difference < 0.0 {
let distance = self.fall_distance.load();
self.fall_distance
Expand Down
4 changes: 2 additions & 2 deletions pumpkin/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,9 +357,9 @@ impl Entity {
.await;
}

pub fn is_invulnerable_to(&self, damage_type: DamageType) -> bool {
pub fn is_invulnerable_to(&self, damage_type: &DamageType) -> bool {
self.invulnerable.load(std::sync::atomic::Ordering::Relaxed)
|| self.damage_immunities.contains(&damage_type)
|| self.damage_immunities.contains(damage_type)
}
}

Expand Down
2 changes: 1 addition & 1 deletion pumpkin/src/entity/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ impl Player {

victim
.living_entity
.damage(damage as f32, DamageType::PlayerAttack) // PlayerAttack
.damage(damage as f32, DamageType::PLAYER_ATTACK)
.await;

let mut knockback_strength = 1.0;
Expand Down

0 comments on commit 5c5bc67

Please sign in to comment.