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 quote::{format_ident, quote};
use serde::Deserialize;
use std::collections::HashMap;
use syn::LitInt;
#[derive(Deserialize)]
struct DamageTypeEntry {
@@ -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 {
@@ -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();
@@ -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! {
#[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,
@@ -99,27 +75,8 @@ pub(crate) fn build() -> TokenStream {
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> {
@@ -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 {
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
}
}
@@ -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>(
@@ -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"
}
}

View File

@@ -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`]

View File

@@ -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)?;
@@ -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();

View File

@@ -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 {

View File

@@ -81,7 +81,7 @@ 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;
}
@@ -89,7 +89,7 @@ impl LivingEntity {
.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,
@@ -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

View File

@@ -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)
}
}

View File

@@ -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;