From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik Date: Fri, 23 Feb 2024 01:48:08 +0000 Subject: [PATCH] Legacy player combat mechanics diff --git a/src/main/java/me/samsuik/sakura/utils/CombatUtil.java b/src/main/java/me/samsuik/sakura/utils/CombatUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..b1c55ef758f61914e6df9b2c8096bce639b26353 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/utils/CombatUtil.java @@ -0,0 +1,39 @@ +package me.samsuik.sakura.utils; + +import it.unimi.dsi.fastutil.objects.*; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.*; + +public final class CombatUtil { + private static final Reference2FloatMap LEGACY_ITEM_DAMAGE_MAP = new Reference2FloatOpenHashMap<>(); + + public static float getLegacyItemDamage(Item item) { + return LEGACY_ITEM_DAMAGE_MAP.getFloat(item); + } + + private static float baseToolDamage(TieredItem item) { + return switch (item) { + case SwordItem swordItem -> 4.0f; + case AxeItem axeItem -> 3.0f; + case PickaxeItem pickaxeItem -> 2.0f; + case ShovelItem shovelItem -> 1.0f; + case null, default -> 0.0f; + }; + } + + static { + LEGACY_ITEM_DAMAGE_MAP.defaultReturnValue(Float.MIN_VALUE); + + for (Item item : BuiltInRegistries.ITEM) { + if (item instanceof TieredItem tieredItem) { + LEGACY_ITEM_DAMAGE_MAP.put(item, baseToolDamage(tieredItem) + tieredItem.getTier().getAttackDamageBonus()); + } + + if (item instanceof HoeItem) { + LEGACY_ITEM_DAMAGE_MAP.put(item, 0.0f); + } + } + + //LEGACY_ITEM_DAMAGE_MAP.put(Items.TRIDENT, LEGACY_ITEM_DAMAGE_MAP.getFloat(Items.DIAMOND_SWORD)); + } +} diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java index c0a0a8808003d7e56c4de4f4ad1c494b15cc41a2..d0f5ace260a913bc5169ea7ea0481c3e3b4b5616 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -287,6 +287,70 @@ public abstract class LivingEntity extends Entity implements Attackable { ++this.noActionTime; // Above all the floats } // Spigot end + // Sakura start - legacy combat mechanics + private static final UUID LEGACY_COMBAT_MECHANICS_UUID = UUID.fromString("84ef96f8-9f48-4ae4-a26c-e04551324816"); + private static final AttributeModifier LEGACY_ATTACK_SPEED_MODIFIER = new AttributeModifier(LEGACY_COMBAT_MECHANICS_UUID, "Legacy attack speed", 100.0, AttributeModifier.Operation.ADD_VALUE); + + private void updateAttackSpeedModifier() { + AttributeInstance attackSpeed = this.getAttribute(Attributes.ATTACK_SPEED); + if (attackSpeed != null) { + attackSpeed.removeModifier(LEGACY_ATTACK_SPEED_MODIFIER); + + if (this.level().sakuraConfig().players.combat.legacyCombatMechanics) { + attackSpeed.addTransientModifier(LEGACY_ATTACK_SPEED_MODIFIER); + } + } + } + + protected final float getAttackDamageFromAttributes() { + AttributeInstance attackDamage = this.getAttribute(Attributes.ATTACK_DAMAGE); + AttributeModifier legacyModifier = null; + + if (this.level().sakuraConfig().players.combat.legacyCombatMechanics) { + legacyModifier = this.getLegacyAttackModifier(); + } + + final double damage; + if (attackDamage == null || legacyModifier == null) { + damage = this.getAttributeValue(Attributes.ATTACK_DAMAGE); + } else { + attackDamage.addTransientModifier(legacyModifier); + damage = this.getAttributeValue(Attributes.ATTACK_DAMAGE); + attackDamage.removeModifier(legacyModifier); + } + + return (float) damage; + } + + private @Nullable AttributeModifier getLegacyAttackModifier() { + ItemStack itemstack = this.getLastHandItem(EquipmentSlot.MAINHAND); + net.minecraft.world.item.component.ItemAttributeModifiers defaultModifiers = itemstack.getItem().components().get(DataComponents.ATTRIBUTE_MODIFIERS); + if (defaultModifiers != null && !defaultModifiers.modifiers().isEmpty()) { // exists + double baseAttack = 0.0; + for (net.minecraft.world.item.component.ItemAttributeModifiers.Entry entry : defaultModifiers.modifiers()) { + if (!entry.slot().test(EquipmentSlot.MAINHAND) || !entry.attribute().is(Attributes.ATTACK_DAMAGE)) + continue; + if (entry.modifier().operation() != AttributeModifier.Operation.ADD_VALUE) + return null; + baseAttack += entry.modifier().amount(); + } + + float legacyAttack = me.samsuik.sakura.utils.CombatUtil.getLegacyItemDamage(itemstack.getItem()); + double attackDifference = (double) legacyAttack - baseAttack; + + if (baseAttack != 0.0f && legacyAttack != Float.MIN_VALUE) { + return new AttributeModifier(LEGACY_COMBAT_MECHANICS_UUID, "Legacy attack damage", attackDifference, AttributeModifier.Operation.ADD_VALUE); + } + } + return null; + } + + protected final float calculateLegacySharpnessDamage() { + ItemStack itemstack = this.getMainHandItem(); + int level = EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.SHARPNESS, itemstack); + return level * 1.25F - net.minecraft.world.item.enchantment.Enchantments.SHARPNESS.getDamageBonus(level, null); + } + // Sakura end - legacy combat mechanics protected LivingEntity(EntityType type, Level world) { super(type, world); @@ -2181,7 +2245,16 @@ public abstract class LivingEntity extends Entity implements Attackable { protected float getDamageAfterArmorAbsorb(DamageSource source, float amount) { if (!source.is(DamageTypeTags.BYPASSES_ARMOR)) { // this.hurtArmor(damagesource, f); // CraftBukkit - Moved into actuallyHurt(DamageSource, float) + // Sakura start - legacy combat mechanics + if (!this.level().sakuraConfig().players.combat.legacyCombatMechanics) { amount = CombatRules.getDamageAfterAbsorb(amount, source, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS)); + } else { + // See: applyArmorModifier(DamageSource, float) + int i = 25 - this.getArmorValue(); + float f1 = amount * (float) i; + amount = f1 / 25.0F; + } + // Sakura end - legacy combat mechanics } return amount; @@ -3277,6 +3350,12 @@ public abstract class LivingEntity extends Entity implements Attackable { }); } + + // Sakura start - legacy combat mechanics + if (this instanceof ServerPlayer && enumitemslot == EquipmentSlot.MAINHAND) { + this.updateAttackSpeedModifier(); + } + // Sakura end - legacy combat mechanics } } diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index 4e8a41dc9e27244b19e1d45b58ad8363801c5b72..fcc2523e330f1d275f320006374406969cd817fa 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1267,12 +1267,18 @@ public abstract class Player extends LivingEntity { if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable. { // Paper end - PlayerAttackEntityEvent - float f = (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE); + float f = this.getAttackDamageFromAttributes(); // Sakura - legacy combat mechanics float f1 = EnchantmentHelper.getDamageBonus(this.getMainHandItem(), target.getType()); float f2 = this.getAttackStrengthScale(0.5F); + // Sakura start - legacy combat mechanics + if (!this.level().sakuraConfig().players.combat.legacyCombatMechanics) { f *= 0.2F + f2 * f2 * 0.8F; f1 *= f2; + } else if (f1 != 0.0) { + f1 += this.calculateLegacySharpnessDamage(); + } + // Sakura end - legacy combat mechanics // this.resetAttackStrengthTicker(); // CraftBukkit - Moved to EntityLiving to reset the cooldown after the damage is dealt if (target.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && target instanceof Projectile) { Projectile iprojectile = (Projectile) target; @@ -1298,7 +1304,7 @@ public abstract class Player extends LivingEntity { } f += this.getItemInHand(InteractionHand.MAIN_HAND).getItem().getAttackDamageBonus(this, f); - boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && !this.isSprinting(); // Paper - Add critical damage API; diff on change + boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && (this.level().sakuraConfig().players.combat.legacyCombatMechanics || !this.isSprinting()); // Sakura - legacy combat mechanics // Paper - Add critical damage API; diff on change flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits if (flag2) {