Question How to ensure Player loss at least 1 health?

tetratheta

New member
Oct 2, 2022
6
1
1
In EntityDamageEvent, there is getDamage() and getFinalDamage(). But even though there is setDamage(double), there is no setFinalDamage(double) or any similar method.

I want to make damaged entity, in this case Player, loss at least 1 health. I can't do that with setDamage(double) because that damage can be less than 1 after damage reduction calculation, which makes the player don't loss any health at all, just making damage tilt and damage sound only.

Here is current code of modifying damage that player takes.

Java:
@EventHandler
public void onPlayerTakeDamage(EntityDamageEvent e) {
    if (!(e.getEntity() instanceof Player p)) return;
    // ... Check other stuff before processing the damage
    if (e instanceof EntityDamageByEntityEvent ee) {
        if (ee.getDamager() instanceof Player) {
            e.setDamage(e.getDamage() * playerModifier);
        // ...
}

With this code, player can make himself don't take any damage from the 'event' with strong armor or potion effects. I don't want it. I want to make the player always loss 1 health from the 'damage'.

First thing I though about using was using another EntityDamageEvent to check the final damage is less than 1, then hurt the player.

Java:
@EventHandler
public void ensureDamage(EntityDamageEvent e) {
    if (!(e.getEntity() instanceof Player p)) return;
    if (e.getFinalDamage() < 1) {
      p.damage(1);
    }
}

Adding this code makes server to shutdown. Maybe it is because of those two methods creates infinite loop, but I can't tell if it is the reason or not. Server crashes even after setting second method's priority to HIGHEST.

Also, even though that code works, that creates another problem. If the player dies from the damage, the death message would be Player died, rather than showing the reason of why he died. Player#damage(double) can't set the reason of the death. Player#damage(double, Entity) can't solve this because this can't resolve 'death from block'.

Player can take damage from various sources. Even though I dig into NMS which can utilize DamageSource, this thing might take too much code for analyzing the damage and process it. It should be considered that maintaining code which uses NMS is hard too.

In this case, how to make sure player to loss at least 1 health?
For clarification, I'm not talking about 'set damage to 1' thing. Player must loss at least 1 health, from every damage events even though they have strong armor or potion effects.
 

tetratheta

New member
Oct 2, 2022
6
1
1
^- based on this spigot forum, try:
Java:
p.setDamage(DamageAmount)
and try one method at the time to not crash your server.
I read the spigot forum article. Unfortunately, I think it doesn't provide useful information to me.

Like I said, The whole purpose of doing these, including use of ensureDamage() method, is Making sure the player takes at least 1 damage.

Java:
//Get the entity's GENERIC_ATTACK_DAMAGE attribute
AttributeInstance dmgAttribute = livingEntity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
//Not all living entities have this attribute, so a null check is necessary. Example: Pigs
if(dmgAttribute != null){
  //To completely override its damage (instead of modifying the current value), change the base value.
  dmgAttribute.setBaseValue(3.0);
}

This is code I found at the article. This would cause problem because I can't determine how much base attack damage attibute should be increased to ensure the player takes 1 damage. Player might have strong armor or effect that decreases final damage calculated.

I'm not sure the final damage will be re-calculated after changing base attack damage attribute. And keep increasing base attack damage and re-calculate final damage until final damage gets equal or more than 1 is not good idea.

Do you have any other alternatives in mind?