kernitus / BukkitOldCombatMechanics

Spigot plugin to configure combat mechanics from 1.9 onwards
https://www.spigotmc.org/resources/19510/
Mozilla Public License 2.0
161 stars 69 forks source link

HumanEntity.getAttackCooldown() not available on <1.16 #633

Closed skbeh closed 1 year ago

skbeh commented 1 year ago

Information

Problem Description

When hitting another player, the console throws the errors above.

### To Reproduce Steps to reproduce the behavior: 1. install OldCombatMechanics. 2. Put two players in the server. 3. Let one player hit another. ### Expected Behaviour Replace these methods to what 1.12.2 has when running on 1.12.2 so that it will work fine.
kernitus commented 1 year ago

It seems the getAttackCooldown() method in HumanEntity was only added in 1.16. This is bad because the player's attack cooldown is necessary to be able to accurately calculate the damage. We must find a workaround for version below that.

skbeh commented 1 year ago

Please note that LivingEntity.getAbsorptionAmount also only exists in 1.16 and above.

kernitus commented 1 year ago

@skbeh It seems Damageable.getAbsorptionAmount was added in 1.15, as shown here. For both of these methods it seems we will have to use NMS with reflection for the versions between 1.9 and when they were introduced.

skbeh commented 1 year ago

@kernitus Is the cooldown of player always 1.0 in 1.12.2? I tried to backport these apis to 1.12.2, but the plugin seems not working correctly.

skbeh commented 1 year ago

@kernitus If you want to test, you can apply https://github.com/nopjmp/Dionysus/pull/106 and https://github.com/nopjmp/Dionysus/pull/105 on Dionysus repo.

kernitus commented 1 year ago

The cooldown shouldn't always be 1.0, unless the player/weapon has no cooldown. The getAttackCooldown() Spigot method should be calling getAttackStrengthScale() from NMS:

    public float getAttackStrengthScale(float f) { // this is called with f = 0.5
        return MathHelper.clamp(((float) this.attackStrengthTicker + f) / this.getCurrentItemAttackStrengthDelay(), 0.0F, 1.0F);
    }
    public float getCurrentItemAttackStrengthDelay() {
        return (float) (1.0D / this.getAttributeValue(GenericAttributes.ATTACK_SPEED) * 20.0D);
    }

Which effectively means it should be a float between 0 and 1 depending on the attack speed and the attack strength ticker (which goes up by 1 every tick, and is reset to 0 after every attack). This yields the following formula:

strength = (delay + 0.5) / (1 / speed * 20)

which means with no delay, a minimum speed of 40 is needed to have full attack strength:

strength = (0 + 0.5) / (1 / 40 * 20) strength = 0.5 / 0.5 = 1

skbeh commented 1 year ago

@kernitus I figured out that it should be the correct behavior because disable-attack-cooldown is enabled by default. However, there is only a little to no "invulnerability between hits" in both 1.12.2 modded Dionysus and the latest 1.19.3 paper, which likes a combo game.

skbeh commented 1 year ago

@kernitus It seems that the problem is that the damage applies even when NoDamageTicks have not passed. The problem happens only if you are sprinting. For example, if you set attack-frequency.mobDelay to a very long time like 2000, when you attack the mob while jumping, it will not become red or be knockbacked, but it's health decreases at a normal rate. I would think that it is a bug in the damage code or critical code of the plugin.

kernitus commented 1 year ago

@skbeh That's a completely different issue. The attack frequency module simply sets the maximum no damage ticks for entities, it does not do any calculations itself. You may just be experiencing overdamage: even while immune, an entity can still get damaged if hit by an attack stronger than the previous one. They will get damaged by the difference between the two attacks. Can you turn debug mode on and see what the actual values are? Debug mode will also say if the attack was an overdamage or not.

kernitus commented 1 year ago

@skbeh Can you please try the latest test builds, I have made the plugin fall back to calling the methods using reflection when they are unavailable in the API.

skbeh commented 1 year ago

@kernitus When testing it with 1.19.3, it throws the following exception occasionally:

[12:22:06 ERROR]: Could not pass event EntityDamageByEntityEvent to OldCombatMechanics v2.0.0BETA
java.lang.NullPointerException: Cannot invoke "org.bukkit.attribute.AttributeInstance.getValue()" because the return value of "org.bukkit.attribute.Attributable.getAttribute(org.bukkit.attribute.Attribute)" is null
at kernitus.plugin.OldCombatMechanics.utilities.damage.EntityDamageByEntityListener.onEntityDamage(EntityDamageByEntityListener.java:150) ~[OldCombatMechanics.jar:?]
at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor32.execute(Unknown Source) ~[?:?]
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:77) ~[paper-api-1.19.3-R0.1-SNAPSHOT.jar:?]
at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:80) ~[paper-api-1.19.3-R0.1-SNAPSHOT.jar:git-Paper-365]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[paper-api-1.19.3-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:672) ~[paper-api-1.19.3-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.callEvent(CraftEventFactory.java:250) ~[paper-1.19.3.jar:git-Paper-365]
at org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.callEntityDamageEvent(CraftEventFactory.java:1154) ~[paper-1.19.3.jar:git-Paper-365]
at org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.handleEntityDamageEvent(CraftEventFactory.java:1013) ~[paper-1.19.3.jar:git-Paper-365]
at org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.handleEntityDamageEvent(CraftEventFactory.java:965) ~[paper-1.19.3.jar:git-Paper-365]
at org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.handleLivingEntityDamageEvent(CraftEventFactory.java:1188) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.world.entity.LivingEntity.damageEntity0(LivingEntity.java:2150) ~[?:?]
at net.minecraft.world.entity.LivingEntity.hurt(LivingEntity.java:1377) ~[?:?]
at net.minecraft.world.entity.boss.enderdragon.EnderDragon.hurt(EnderDragon.java:469) ~[?:?]
at net.minecraft.world.entity.boss.enderdragon.EnderDragon.aiStep(EnderDragon.java:328) ~[?:?]
at net.minecraft.world.entity.LivingEntity.tick(LivingEntity.java:3009) ~[?:?]
at net.minecraft.world.entity.Mob.tick(Mob.java:402) ~[?:?]
at net.minecraft.server.level.ServerLevel.tickNonPassenger(ServerLevel.java:1211) ~[?:?]
at net.minecraft.world.level.Level.guardEntityTick(Level.java:918) ~[?:?]
at net.minecraft.server.level.ServerLevel.lambda$tick$6(ServerLevel.java:731) ~[?:?]
at net.minecraft.world.level.entity.EntityTickList.forEach(EntityTickList.java:42) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.server.level.ServerLevel.tick(ServerLevel.java:711) ~[?:?]
at net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1535) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.server.dedicated.DedicatedServer.tickChildren(DedicatedServer.java:440) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:1397) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1173) ~[paper-1.19.3.jar:git-Paper-365]
at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:316) ~[paper-1.19.3.jar:git-Paper-365]
at java.lang.Thread.run(Thread.java:1589) ~[?:?]
skbeh commented 1 year ago

@kernitus When testing with 1.12.2, it constantly throws exceptions and I could not join the server.

[12:29:14 ERROR]: Could not pass event EntityDamageEvent to OldCombatMechanics v2.0.0BETA
org.bukkit.event.EventException: null
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:72) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:78) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:513) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEvent(CraftEventFactory.java:94) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEntityDamageEvent(CraftEventFactory.java:620) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleEntityDamageEvent(CraftEventFactory.java:606) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleLivingEntityDamageEvent(CraftEventFactory.java:652) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity0(EntityLiving.java:1417) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity(EntityLiving.java:890) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.damageEntity(EntityHorseAbstract.java:166) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.Y(EntityLiving.java:215) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.Y(EntityInsentient.java:190) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.Entity.B_(Entity.java:365) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.B_(EntityLiving.java:1948) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.B_(EntityInsentient.java:250) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.B_(EntityHorseAbstract.java:526) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorse.B_(SourceFile:209) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.entityJoinedWorld(World.java:1793) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.h(World.java:1763) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.tickEntities(World.java:1570) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.WorldServer.tickEntities(WorldServer.java:667) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.D(MinecraftServer.java:933) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.DedicatedServer.D(DedicatedServer.java:427) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.C(MinecraftServer.java:775) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.run(MinecraftServer.java:666) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at java.lang.Thread.run(Thread.java:1589) ~[?:?]
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "method" is null
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.invokeMethod(Reflector.java:113) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.lambda$memoiseMethodInvocation$6(Reflector.java:134) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:57) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:64) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.damage.DefenceUtils.calculateDefenceDamageReduction(DefenceUtils.java:132) ~[?:?]
at kernitus.plugin.OldCombatMechanics.module.ModuleOldArmourStrength.onEntityDamage(ModuleOldArmourStrength.java:46) ~[?:?]
at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor31.execute(Unknown Source) ~[?:?]
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:70) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
... 26 more
[12:29:14 ERROR]: Could not pass event EntityDamageEvent to OldCombatMechanics v2.0.0BETA
org.bukkit.event.EventException: null
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:72) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:78) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:513) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEvent(CraftEventFactory.java:94) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEntityDamageEvent(CraftEventFactory.java:620) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleEntityDamageEvent(CraftEventFactory.java:606) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleLivingEntityDamageEvent(CraftEventFactory.java:652) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity0(EntityLiving.java:1417) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity(EntityLiving.java:890) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.damageEntity(EntityHorseAbstract.java:166) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.Y(EntityLiving.java:215) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.Y(EntityInsentient.java:190) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.Entity.B_(Entity.java:365) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.B_(EntityLiving.java:1948) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.B_(EntityInsentient.java:250) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.B_(EntityHorseAbstract.java:526) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorse.B_(SourceFile:209) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.entityJoinedWorld(World.java:1793) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.h(World.java:1763) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.tickEntities(World.java:1570) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.WorldServer.tickEntities(WorldServer.java:667) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.D(MinecraftServer.java:933) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.DedicatedServer.D(DedicatedServer.java:427) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.C(MinecraftServer.java:775) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.run(MinecraftServer.java:666) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at java.lang.Thread.run(Thread.java:1589) ~[?:?]
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "method" is null
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.invokeMethod(Reflector.java:113) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.lambda$memoiseMethodInvocation$6(Reflector.java:134) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:57) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:64) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.damage.DefenceUtils.calculateDefenceDamageReduction(DefenceUtils.java:132) ~[?:?]
at kernitus.plugin.OldCombatMechanics.module.ModuleOldArmourStrength.onEntityDamage(ModuleOldArmourStrength.java:46) ~[?:?]
at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor31.execute(Unknown Source) ~[?:?]
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:70) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
... 26 more
[12:29:14 ERROR]: Could not pass event EntityDamageEvent to OldCombatMechanics v2.0.0BETA
org.bukkit.event.EventException: null
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:72) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:78) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:513) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEvent(CraftEventFactory.java:94) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.callEntityDamageEvent(CraftEventFactory.java:620) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleEntityDamageEvent(CraftEventFactory.java:606) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory.handleLivingEntityDamageEvent(CraftEventFactory.java:652) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity0(EntityLiving.java:1417) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.damageEntity(EntityLiving.java:890) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.damageEntity(EntityHorseAbstract.java:166) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.Y(EntityLiving.java:215) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.Y(EntityInsentient.java:190) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.Entity.B_(Entity.java:365) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityLiving.B_(EntityLiving.java:1948) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityInsentient.B_(EntityInsentient.java:250) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorseAbstract.B_(EntityHorseAbstract.java:526) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.EntityHorse.B_(SourceFile:209) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.entityJoinedWorld(World.java:1793) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.h(World.java:1763) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.World.tickEntities(World.java:1570) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.WorldServer.tickEntities(WorldServer.java:667) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.D(MinecraftServer.java:933) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.DedicatedServer.D(DedicatedServer.java:427) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.C(MinecraftServer.java:775) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at net.minecraft.server.v1_12_R1.MinecraftServer.run(MinecraftServer.java:666) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
at java.lang.Thread.run(Thread.java:1589) ~[?:?]
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "method" is null
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.invokeMethod(Reflector.java:113) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector.lambda$memoiseMethodInvocation$6(Reflector.java:134) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:57) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.reflection.SpigotFunctionChooser.apply(SpigotFunctionChooser.java:64) ~[?:?]
at kernitus.plugin.OldCombatMechanics.utilities.damage.DefenceUtils.calculateDefenceDamageReduction(DefenceUtils.java:132) ~[?:?]
at kernitus.plugin.OldCombatMechanics.module.ModuleOldArmourStrength.onEntityDamage(ModuleOldArmourStrength.java:46) ~[?:?]
at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor31.execute(Unknown Source) ~[?:?]
at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:70) ~[patched_1.12.2.jar:git-Dionysus-"42ce9ca"]
... 26 more
skbeh commented 1 year ago

By the way, will GENERIC_ATTACK_SPEED influence how much damage a player dealing within a period of NoDamageTicks?

kernitus commented 1 year ago

@skbeh It seems I made a series of assumptions about accessing non-api methods with reflection that did not hold. It should work now with the test builds from commit cd362f5 onwards, although I have only tested on 1.9 for now. You are welcome to test these on 1.12.

GENERIC_ATTACK_SPEED does not directly influence how much damage a player can deal on an entity that has been recently hit and has a value for noDamageTicks. The way it affects it is that if you have no cooldown, you are always able to deal full-damage attacks. Thus, you are more likely to deal "overdamage". In fact, there is no such thing as full damage immunity - if an entity receives damage of a value higher than the last damage they received while they are "immune", they will be damaged by the difference between the two damages. This is more likely to happen if players always have full-damage attacks due to no cooldown.

skbeh commented 1 year ago

@kernitus It runs fine with 1.12.2. However, as what I mentioned previously, all combats seem like combo combats which feels like only a little to no noDamageTicks. The damage delay feels not only much less than 1.8.8 but also less than BukkitOldCombatMechanics 1.11.0. And the damage is dealt much more faster than 1.8.8.

Please notice that, (I feel like that) BukkitOldCombatMechanics 1.11.0 with Paper 1.12.2 also has less damage delay than 1.8.8. Players on my server also reported the damage delay being nearly to none from time to time.

The behavior is also reproducible with 1.19.3 in my previous tests.

skbeh commented 1 year ago

if an entity receives damage of a value higher than the last damage they received while they are "immune", they will be damaged by the difference between the two damages. This is more likely to happen if players always have full-damage attacks due to no cooldown.

@kernitus Will the damage be accumulated or only the damage of the attack that has the highest damage is dealt? Also, it can not explain why the health of the mob (attack-frequency.mobDelay: 1600) that I attack with a iron sword and critical decreases about 8 (4 hearts) almost every 2 to 3 seconds, although the mob does not become red except the first time.

kernitus commented 1 year ago

Of course it's less than OCM 1.11, the damage calculations were completely scuffed and allowed for crazy things. These have now been fixed.

Overdamage does not cause the entity to flash red again, it only does so when it is first hit. It will then received the difference in damage between the first attack and the second, but only if the second is of a higher value. E.g. first attack is 7, second attack is 9 whilst they are still immune, so they get damaged by 2 the second time. This makes for a total of 9. Multiple subsequent attacks can occur, but the immunity period is not reset.

Base tool damage, strength potion, tool enchantments and critical hits are taken into account for the attack value.

As shown in 1.8.8 EntityLiving.damageEntity() NMS code:

                if ((float) this.noDamageTicks > (float) this.maxNoDamageTicks / 2.0F) {
                    if (f <= this.lastDamage) {
                        return false;
                    }

                    this.d(damagesource, f - this.lastDamage);
                    this.lastDamage = f;
                    flag = false;
                } else {
                    this.lastDamage = f;
                    this.noDamageTicks = this.maxNoDamageTicks;
                    this.d(damagesource, f);
                    this.hurtTicks = this.av = 10;
                }

N.B. While looking into this I noticed the last damage value was not being updated when a successful overdamage attack was completed. This allowed for example a first attack of value 5 then multiple attacks of value 7 to all deal an additional 2 damage, when in reality only the first one should. Overdamage only happens if attacks keep increasing in value during the immunity period. This has now been fixed. If you think the damage is still not quite right, please open up a new bug report with a debug log.