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..babeceb7c6063933bf10bcc4bbfc6ea424ffb574 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/utils/CombatUtil.java @@ -0,0 +1,40 @@ +package me.samsuik.sakura.utils; + +import it.unimi.dsi.fastutil.objects.Reference2FloatMap; +import it.unimi.dsi.fastutil.objects.Reference2FloatOpenHashMap; +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 bfa7725cc59c393047c4fb0173453128d0d6e161..377e862bb6b926f73bab3d5cecce41a57fe9b73d 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -299,6 +299,79 @@ public abstract class LivingEntity extends Entity implements Attackable { ++this.noActionTime; // Above all the floats } // Spigot end + // Sakura start - legacy combat mechanics + private static final ResourceLocation LEGACY_COMBAT_MODIFIER_ID = ResourceLocation.fromNamespaceAndPath("sakura", "legacy_combat"); + private static final AttributeModifier LEGACY_ATTACK_SPEED_MODIFIER = new AttributeModifier(LEGACY_COMBAT_MODIFIER_ID, 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_MODIFIER_ID, attackDifference, AttributeModifier.Operation.ADD_VALUE); + } + } + return null; + } + + protected final float calculateLegacySharpnessDamage(ItemStack itemstack, DamageSource damageSource) { + net.minecraft.core.RegistryAccess registryAccess = net.minecraft.server.MinecraftServer.getServer().registryAccess(); + net.minecraft.core.HolderLookup.RegistryLookup enchantments = registryAccess.lookupOrThrow(net.minecraft.core.registries.Registries.ENCHANTMENT); + Holder sharpness = enchantments.getOrThrow(net.minecraft.world.item.enchantment.Enchantments.SHARPNESS); + + int enchantmentLevel = itemstack.getEnchantments().getLevel(sharpness); + ServerLevel serverLevel = (ServerLevel) this.level(); + + org.apache.commons.lang3.mutable.MutableFloat damage = new org.apache.commons.lang3.mutable.MutableFloat(); + sharpness.value().modifyDamage(serverLevel, enchantmentLevel, itemstack, this, damageSource, damage); + + // legacy - modern + return enchantmentLevel * 1.25F - damage.getValue(); + } + // Sakura end - legacy combat mechanics protected LivingEntity(EntityType type, Level world) { super(type, world); @@ -2210,7 +2283,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 - actuallyHurt(DamageSource, float, EntityDamageEvent) for handle damage + // Sakura start - legacy combat mechanics + if (!this.level().sakuraConfig().players.combat.legacyCombatMechanics) { amount = CombatRules.getDamageAfterAbsorb(this, 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; @@ -3352,6 +3434,12 @@ public abstract class LivingEntity extends Entity implements Attackable { }); } + + // Sakura start - legacy combat mechanics + if (this instanceof ServerPlayer && enumitemslot1 == 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 5c3bebf932b6f0376711a2bd679062575bff04a3..d4485ecff16969e57241d3841efbe1745c0814aa 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -1278,14 +1278,20 @@ public abstract class Player extends LivingEntity { if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable. { // Paper end - PlayerAttackEntityEvent - float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE); + float f = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : this.getAttackDamageFromAttributes(); // Sakura - legacy combat mechanics ItemStack itemstack = this.getWeaponItem(); DamageSource damagesource = this.damageSources().playerAttack(this); float f1 = this.getEnchantedDamage(target, f, damagesource) - f; 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(itemstack, damagesource); + } + // 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; @@ -1313,7 +1319,7 @@ public abstract class Player extends LivingEntity { } f += itemstack.getItem().getAttackDamageBonus(target, f, damagesource); - boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround() && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity && !this.isSprinting(); + 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 flag2 = flag2 && !this.level().paperConfig().entities.behavior.disablePlayerCrits; // Paper - Toggleable player crits if (flag2) {