package net.minecraft.world.damagesource; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponents; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; public class DamageSource { private final Holder type; @Nullable private final Entity causingEntity; @Nullable private final Entity directEntity; @Nullable private final Vec3 damageSourcePosition; public String toString() { return "DamageSource (" + this.type().msgId() + ")"; } /** * How much satiate (food) is consumed by this {@code DamageSource}. */ public float getFoodExhaustion() { return this.type().exhaustion(); } public boolean isDirect() { return this.causingEntity == this.directEntity; } private DamageSource(Holder type, @Nullable Entity directEntity, @Nullable Entity causingEntity, @Nullable Vec3 damageSourcePosition) { this.type = type; this.causingEntity = causingEntity; this.directEntity = directEntity; this.damageSourcePosition = damageSourcePosition; } public DamageSource(Holder type, @Nullable Entity directEntity, @Nullable Entity causingEntity) { this(type, directEntity, causingEntity, null); } public DamageSource(Holder type, Vec3 damageSourcePosition) { this(type, null, null, damageSourcePosition); } public DamageSource(Holder type, @Nullable Entity entity) { this(type, entity, entity); } public DamageSource(Holder type) { this(type, null, null, null); } /** * Retrieves the immediate causer of the damage, e.g. the arrow entity, not its shooter */ @Nullable public Entity getDirectEntity() { return this.directEntity; } /** * Retrieves the true causer of the damage, e.g. the player who fired an arrow, the shulker who fired the bullet, etc. */ @Nullable public Entity getEntity() { return this.causingEntity; } @Nullable public ItemStack getWeaponItem() { return this.directEntity != null ? this.directEntity.getWeaponItem() : null; } /** * Gets the death message that is displayed when the player dies */ public Component getLocalizedDeathMessage(LivingEntity livingEntity) { String string = "death.attack." + this.type().msgId(); if (this.causingEntity == null && this.directEntity == null) { LivingEntity livingEntity3 = livingEntity.getKillCredit(); String string2 = string + ".player"; return livingEntity3 != null ? Component.translatable(string2, livingEntity.getDisplayName(), livingEntity3.getDisplayName()) : Component.translatable(string, livingEntity.getDisplayName()); } else { Component component = this.causingEntity == null ? this.directEntity.getDisplayName() : this.causingEntity.getDisplayName(); ItemStack itemStack = this.causingEntity instanceof LivingEntity livingEntity2 ? livingEntity2.getMainHandItem() : ItemStack.EMPTY; return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) ? Component.translatable(string + ".item", livingEntity.getDisplayName(), component, itemStack.getDisplayName()) : Component.translatable(string, livingEntity.getDisplayName(), component); } } /** * Return the name of damage type. */ public String getMsgId() { return this.type().msgId(); } /** * Return whether this damage source will have its damage amount scaled based on the current difficulty. */ public boolean scalesWithDifficulty() { return switch (this.type().scaling()) { case NEVER -> false; case WHEN_CAUSED_BY_LIVING_NON_PLAYER -> this.causingEntity instanceof LivingEntity && !(this.causingEntity instanceof Player); case ALWAYS -> true; }; } public boolean isCreativePlayer() { return this.getEntity() instanceof Player player && player.getAbilities().instabuild; } /** * Gets the location from which the damage originates. */ @Nullable public Vec3 getSourcePosition() { if (this.damageSourcePosition != null) { return this.damageSourcePosition; } else { return this.directEntity != null ? this.directEntity.position() : null; } } @Nullable public Vec3 sourcePositionRaw() { return this.damageSourcePosition; } public boolean is(TagKey damageTypeKey) { return this.type.is(damageTypeKey); } public boolean is(ResourceKey damageTypeKey) { return this.type.is(damageTypeKey); } public DamageType type() { return this.type.value(); } public Holder typeHolder() { return this.type; } }