Improve damage type

This commit is contained in:
Alexander Medvedev 2025-02-07 22:33:52 +01:00
parent ec0e8a723a
commit 5c5bc67b3a
8 changed files with 32 additions and 87 deletions

View File

@ -1,8 +1,9 @@
use heck::{ToPascalCase, ToShoutySnakeCase}; use heck::ToShoutySnakeCase;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use syn::LitInt;
#[derive(Deserialize)] #[derive(Deserialize)]
struct DamageTypeEntry { struct DamageTypeEntry {
@ -30,9 +31,8 @@ pub(crate) fn build() -> TokenStream {
for (name, entry) in damage_types { for (name, entry) in damage_types {
let const_ident = format_ident!("{}", name.to_shouty_snake_case()); 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 data = &entry.components;
let death_message_type = match &data.death_message_type { let death_message_type = match &data.death_message_type {
@ -43,27 +43,19 @@ pub(crate) fn build() -> TokenStream {
let exhaustion = data.exhaustion; let exhaustion = data.exhaustion;
let message_id = &data.message_id; let message_id = &data.message_id;
let scaling = &data.scaling; 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! { constants.push(quote! {
pub const #const_ident: DamageTypeData = DamageTypeData { pub const #const_ident: DamageType = DamageType {
death_message_type: #death_message_type, death_message_type: #death_message_type,
exhaustion: #exhaustion, exhaustion: #exhaustion,
message_id: #message_id, message_id: #message_id,
scaling: #scaling, 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 type_name_pairs = enum_variants.iter().map(|variant| {
let name = variant.to_string(); let name = variant.to_string();
let name_lowercase = name.to_lowercase(); let name_lowercase = name.to_lowercase();
@ -73,25 +65,9 @@ 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! { quote! {
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct DamageTypeData { pub struct DamageType {
pub death_message_type: Option<&'static str>, pub death_message_type: Option<&'static str>,
pub exhaustion: f32, pub exhaustion: f32,
pub message_id: &'static str, pub message_id: &'static str,
@ -99,27 +75,8 @@ pub(crate) fn build() -> TokenStream {
pub id: u32, pub id: u32,
} }
#(#constants)*
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DamageType {
#(#enum_variants,)*
}
impl DamageType { impl DamageType {
pub const fn data(&self) -> &'static DamageTypeData { #(#constants)*
match self {
#(#enum_arms)*
}
}
#[doc = r" Get all possible damage types"]
pub fn values() -> &'static [DamageType] {
static VALUES: &[DamageType] = &[
#(#variant_array,)*
];
VALUES
}
#[doc = r" Try to parse a damage type from a resource location string"] #[doc = r" Try to parse a damage type from a resource location string"]
pub fn from_name(name: &str) -> Option<Self> { pub fn from_name(name: &str) -> Option<Self> {
@ -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,)*
}
}
} }
} }
} }

View File

@ -14,11 +14,13 @@ pub struct DamageTypeArgumentConsumer;
impl GetClientSideArgParser for DamageTypeArgumentConsumer { impl GetClientSideArgParser for DamageTypeArgumentConsumer {
fn get_client_side_parser(&self) -> ArgumentType { fn get_client_side_parser(&self) -> ArgumentType {
ArgumentType::ResourceLocation ArgumentType::Resource {
identifier: "damage_type",
}
} }
fn get_client_side_suggestion_type_override(&self) -> Option<SuggestionProviders> { fn get_client_side_suggestion_type_override(&self) -> Option<SuggestionProviders> {
Some(SuggestionProviders::AskServer) None
} }
} }
@ -30,15 +32,12 @@ impl ArgumentConsumer for DamageTypeArgumentConsumer {
_server: &'a Server, _server: &'a Server,
args: &mut RawArgs<'a>, args: &mut RawArgs<'a>,
) -> Option<Arg<'a>> { ) -> Option<Arg<'a>> {
let s = args.pop()?; let name = args.pop()?;
// Create a static damage type first // 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 // Find matching static damage type from values array
DamageType::values() Some(Arg::DamageType(damage_type))
.iter()
.find(|&&dt| std::mem::discriminant(&dt) == std::mem::discriminant(&damage_type))
.map(Arg::DamageType)
} }
async fn suggest<'a>( async fn suggest<'a>(
@ -47,18 +46,13 @@ impl ArgumentConsumer for DamageTypeArgumentConsumer {
_server: &'a Server, _server: &'a Server,
_input: &'a str, _input: &'a str,
) -> Result<Option<Vec<CommandSuggestion>>, CommandError> { ) -> Result<Option<Vec<CommandSuggestion>>, CommandError> {
// Get all available damage types Ok(None)
let suggestions = DamageType::values()
.iter()
.map(|dt| CommandSuggestion::new(dt.to_name().to_string(), None))
.collect();
Ok(Some(suggestions))
} }
} }
impl DefaultNameArgConsumer for DamageTypeArgumentConsumer { impl DefaultNameArgConsumer for DamageTypeArgumentConsumer {
fn default_name(&self) -> &'static str { fn default_name(&self) -> &'static str {
"damageType" "damage_type"
} }
} }

View File

@ -101,7 +101,7 @@ pub enum Arg<'a> {
#[allow(unused)] #[allow(unused)]
Simple(&'a str), Simple(&'a str),
SoundCategory(SoundCategory), SoundCategory(SoundCategory),
DamageType(&'a DamageType), DamageType(DamageType),
} }
/// see [`crate::commands::tree::builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree::builder::NonLeafNodeBuilder::execute`] /// see [`crate::commands::tree::builder::argument`] and [`CommandTree::execute`]/[`crate::commands::tree::builder::NonLeafNodeBuilder::execute`]

View File

@ -82,9 +82,9 @@ impl CommandExecutor for DamageLocationExecutor {
let damage_type = args let damage_type = args
.get(ARG_DAMAGE_TYPE) .get(ARG_DAMAGE_TYPE)
.map_or(DamageType::Generic, |arg| match arg { .map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => **dt, Arg::DamageType(dt) => *dt,
_ => DamageType::Generic, _ => DamageType::GENERIC,
}); });
let location = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?; let location = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
@ -122,9 +122,9 @@ impl CommandExecutor for DamageEntityExecutor {
let damage_type = args let damage_type = args
.get(ARG_DAMAGE_TYPE) .get(ARG_DAMAGE_TYPE)
.map_or(DamageType::Generic, |arg| match arg { .map_or(DamageType::GENERIC, |arg| match arg {
Arg::DamageType(dt) => **dt, Arg::DamageType(dt) => *dt,
_ => DamageType::Generic, _ => DamageType::GENERIC,
}); });
let source = EntityArgumentConsumer::find_arg(args, ARG_ENTITY).ok(); let source = EntityArgumentConsumer::find_arg(args, ARG_ENTITY).ok();

View File

@ -50,7 +50,7 @@ impl HungerManager {
} else if level == 0 { } else if level == 0 {
self.tick_timer.fetch_add(1); self.tick_timer.fetch_add(1);
if self.tick_timer.load() >= 80 { 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); self.tick_timer.store(0);
} }
} else { } else {

View File

@ -81,7 +81,7 @@ impl LivingEntity {
cause: Option<&Entity>, cause: Option<&Entity>,
) -> bool { ) -> bool {
// Check invulnerability before applying damage // Check invulnerability before applying damage
if self.entity.is_invulnerable_to(damage_type) { if self.entity.is_invulnerable_to(&damage_type) {
return false; return false;
} }
@ -89,7 +89,7 @@ impl LivingEntity {
.world .world
.broadcast_packet_all(&CDamageEvent::new( .broadcast_packet_all(&CDamageEvent::new(
self.entity.entity_id.into(), self.entity.entity_id.into(),
damage_type.data().id.into(), damage_type.id.into(),
source.map(|e| e.entity_id.into()), source.map(|e| e.entity_id.into()),
cause.map(|e| e.entity_id.into()), cause.map(|e| e.entity_id.into()),
position, position,
@ -156,7 +156,7 @@ impl LivingEntity {
.play_sound(Self::get_fall_sound(fall_distance as i32)) .play_sound(Self::get_fall_sound(fall_distance as i32))
.await; .await;
// TODO: Play block fall sound // 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 { } else if height_difference < 0.0 {
let distance = self.fall_distance.load(); let distance = self.fall_distance.load();
self.fall_distance self.fall_distance

View File

@ -357,9 +357,9 @@ impl Entity {
.await; .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.invulnerable.load(std::sync::atomic::Ordering::Relaxed)
|| self.damage_immunities.contains(&damage_type) || self.damage_immunities.contains(damage_type)
} }
} }

View File

@ -355,7 +355,7 @@ impl Player {
victim victim
.living_entity .living_entity
.damage(damage as f32, DamageType::PlayerAttack) // PlayerAttack .damage(damage as f32, DamageType::PLAYER_ATTACK)
.await; .await;
let mut knockback_strength = 1.0; let mut knockback_strength = 1.0;