mcMMO-Dev/mcMMO — pull request #193 by bm01 (2012-03-06 06:21:25+00:00)
Title: Fix for XP gain with enchanted swords

There is one problem with bukkit, totally unrelated to mcMMO: Event damage doesn't take enchants into account. So a diamond sword always does 7 damage (without critical hit) and mcMMO use that for XP rewarding.

Since enchants damage are random (at least for swords), the only fix I'm aware of is to use a delayed task to compare healths right at the end of the current server tick. That's what the class gainXP I propose does, called by startGainXP (which replace PvPExperienceGain, PvEExperienceGain and getXp).

I also moved Taming.rewardXp, replaced by one line in Combat.combatCheks(). The exp gain versus player is also a little different now (previously configValue*2*10*1.5, now configValue*20, the same as the other combat skills). But that's because I haven't thought about it in the first place. All skills had the same multiplier (when added) except for Taming versus Player.

Anyway, here's the most interesting part. That worth mentioning because experience gain is based on that. As we know entities have an invulnerability timer (0.5sec) which can be bypassed if the new damage is superior to the previous one. For example you're fighting a burning creature and you hit right after a fire tick damage, the listener will report 1 damage for the fire tick then 7 damage for the hit (diamond sword let's say).

Well, the thing is, the total damage isn't 8, but 7 (new damage minus previous damage). The same can happens with critical hit, which in this case does less damage than a normal hit (but is done sooner, since it bypass the invulnerability timer).

The only way to tell what the real damage done are is to save the entity health somewhere and to subtract the new health from it. Once added, the total will be exactly the same as the entity's maxHealth. This isn't the case if we use event.getDamage() or event.getLastDamage() because event damage seems to make a sum of all damage done during the invulnerability timer (and also doesn't take zombies armor into account).

I don't exactly understand what's really happening, but I guess all we need to know is that the sum of all event damage are sometimes (almost always if the player jumps a lot) superior to the entity's health. And I made gainXP with that in mind, it uses entity health and not event damage to calculate the experience gain. But of course it's possible to go back to the previous behavior while keeping enchant damages.