From 8178b1855ef31d5b824f131d599dd6f2a78d4e17 Mon Sep 17 00:00:00 2001 From: Zsolt Molnar Date: Mon, 9 Sep 2024 18:25:35 +0200 Subject: [PATCH] Fix offhand --- CHANGELOG.md | 2 + .../logic/PlayerAttackHelper.java | 35 ++-- .../bettercombat/mixin/LivingEntityMixin.java | 4 +- .../bettercombat/network/ServerNetwork.java | 190 +++++++++--------- .../weapon_attributes/wooden_sword.json | 2 +- 5 files changed, 116 insertions(+), 117 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad374d1a..51a8bdc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # 2.0.2 +- Fix enchantments on from offhand weapon strikes not being applied +- Fix offhand weapon strikes not reducing durability - (NeoForge) Fix hand swapping two-handed items, causing offhand item deletion - (NeoForge) Fix missing declaration to Cloth Config causing crash diff --git a/common/src/main/java/net/bettercombat/logic/PlayerAttackHelper.java b/common/src/main/java/net/bettercombat/logic/PlayerAttackHelper.java index c4ca3108..31cb63c7 100644 --- a/common/src/main/java/net/bettercombat/logic/PlayerAttackHelper.java +++ b/common/src/main/java/net/bettercombat/logic/PlayerAttackHelper.java @@ -1,27 +1,16 @@ package net.bettercombat.logic; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; import net.bettercombat.BetterCombatMod; import net.bettercombat.api.AttackHand; import net.bettercombat.api.ComboState; import net.bettercombat.api.WeaponAttributes; import net.bettercombat.utils.AttributeModifierHelper; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.component.type.AttributeModifiersComponent; -import net.minecraft.entity.attribute.EntityAttribute; -import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.ShieldItem; -import net.minecraft.registry.entry.RegistryEntry; -import org.jetbrains.annotations.NotNull; import java.util.Arrays; -import static net.minecraft.entity.EquipmentSlot.MAINHAND; - public class PlayerAttackHelper { public static float getDualWieldingAttackDamageMultiplier(PlayerEntity player, AttackHand hand) { return isDualWielding(player) @@ -165,15 +154,33 @@ private static boolean evaluateCondition(WeaponAttributes.Condition condition, P private static final Object attributesLock = new Object(); - public static void offhandAttributes(PlayerEntity player, Runnable runnable) { - synchronized (attributesLock) { + public static void swapHandAttributes(PlayerEntity player, Runnable runnable) { + swapHandAttributes(player, true, runnable); + } + + public static void swapHandAttributes(PlayerEntity player, boolean useOffHand, Runnable runnable) { + if (!useOffHand) { + runnable.run(); + return; + } + synchronized (player) { + var inventory = player.getInventory(); + var mainHandStack = player.getMainHandStack(); + var offHandStack = inventory.offHand.get(0); + setAttributesForOffHandAttack(player, true); + inventory.main.set(inventory.selectedSlot, offHandStack); + inventory.offHand.set(0, offHandStack); + runnable.run(); + + inventory.main.set(inventory.selectedSlot, mainHandStack); + inventory.offHand.set(0, offHandStack); setAttributesForOffHandAttack(player, false); } } - public static void setAttributesForOffHandAttack(PlayerEntity player, boolean useOffHand) { + private static void setAttributesForOffHandAttack(PlayerEntity player, boolean useOffHand) { var mainHandStack = player.getMainHandStack(); var offHandStack = player.getOffHandStack(); ItemStack add; diff --git a/common/src/main/java/net/bettercombat/mixin/LivingEntityMixin.java b/common/src/main/java/net/bettercombat/mixin/LivingEntityMixin.java index 6702e5b3..f52fe86d 100644 --- a/common/src/main/java/net/bettercombat/mixin/LivingEntityMixin.java +++ b/common/src/main/java/net/bettercombat/mixin/LivingEntityMixin.java @@ -24,10 +24,10 @@ public void getAttributeValue_Inject(RegistryEntry attribute, C if (object instanceof PlayerEntity) { var player = (PlayerEntity)object; var comboCount = ((PlayerAttackProperties)player).getComboCount(); - if (// player.getWorld().isClient && + if (player.getWorld().isClient && comboCount > 0 && PlayerAttackHelper.shouldAttackWithOffHand(player, comboCount)) { - PlayerAttackHelper.offhandAttributes(player, () -> { + PlayerAttackHelper.swapHandAttributes(player, () -> { var value = player.getAttributes().getValue(attribute); cir.setReturnValue(value); }); diff --git a/common/src/main/java/net/bettercombat/network/ServerNetwork.java b/common/src/main/java/net/bettercombat/network/ServerNetwork.java index 9581ba2a..8e30a01c 100644 --- a/common/src/main/java/net/bettercombat/network/ServerNetwork.java +++ b/common/src/main/java/net/bettercombat/network/ServerNetwork.java @@ -34,15 +34,9 @@ import net.minecraft.util.Identifier; import org.slf4j.Logger; -import java.util.UUID; - public class ServerNetwork { static final Logger LOGGER = LogUtils.getLogger(); - private static final UUID COMBO_DAMAGE_MODIFIER_ID = UUID.randomUUID(); - private static final UUID DUAL_WIELDING_MODIFIER_ID = UUID.randomUUID(); - private static final UUID SWEEPING_MODIFIER_ID = UUID.randomUUID(); - public static void handleAttackAnimation(Packets.AttackAnimation packet, MinecraftServer server, ServerPlayerEntity player) { ServerWorld world = Iterables.tryFind(server.getWorlds(), (element) -> element == player.getWorld()) .orNull(); @@ -92,124 +86,120 @@ public static void handleAttackRequest(Packets.C2S_AttackRequest request, Minecr world.getServer().executeSync(() -> { ((PlayerAttackProperties)player).setComboCount(request.comboCount()); - double damageBaseMultiplier = 0.0; - double range = 18.0; - if (attributes != null && attack != null) { - range = attributes.attackRange(); + PlayerAttackHelper.swapHandAttributes(player, hand.isOffHand(), () -> { - double comboMultiplier = attack.damageMultiplier() - 1; - damageBaseMultiplier += comboMultiplier; + double damageBaseMultiplier = 0.0; + double range = 18.0; - var dualWieldingMultiplier = PlayerAttackHelper.getDualWieldingAttackDamageMultiplier(player, hand) - 1; - damageBaseMultiplier += dualWieldingMultiplier; - if (hand.isOffHand()) { - PlayerAttackHelper.setAttributesForOffHandAttack(player, true); - } + if (attributes != null && attack != null) { + range = attributes.attackRange(); - SoundHelper.playSound(world, player, attack.swingSound()); + double comboMultiplier = attack.damageMultiplier() - 1; + damageBaseMultiplier += comboMultiplier; - if (BetterCombatMod.config.allow_reworked_sweeping && request.entityIds().length > 1) { - double multiplier = 0 - - (BetterCombatMod.config.reworked_sweeping_maximum_damage_penalty / BetterCombatMod.config.reworked_sweeping_extra_target_count) - * Math.min(BetterCombatMod.config.reworked_sweeping_extra_target_count, request.entityIds().length - 1); - var sweepRatio = player.getAttributeValue(EntityAttributes.PLAYER_SWEEPING_DAMAGE_RATIO); + var dualWieldingMultiplier = PlayerAttackHelper.getDualWieldingAttackDamageMultiplier(player, hand) - 1; + damageBaseMultiplier += dualWieldingMultiplier; - damageBaseMultiplier += multiplier + (BetterCombatMod.config.reworked_sweeping_maximum_damage_penalty * sweepRatio); + SoundHelper.playSound(world, player, attack.swingSound()); - boolean playEffects = !BetterCombatMod.config.reworked_sweeping_sound_and_particles_only_for_swords - || (hand.itemStack().getItem() instanceof SwordItem); - if (BetterCombatMod.config.reworked_sweeping_plays_sound && playEffects) { - world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENTITY_PLAYER_ATTACK_SWEEP, player.getSoundCategory(), 1.0f, 1.0f); - } - if (BetterCombatMod.config.reworked_sweeping_emits_particles && playEffects) { - player.spawnSweepAttackParticles(); + if (BetterCombatMod.config.allow_reworked_sweeping && request.entityIds().length > 1) { + double multiplier = 0 + - (BetterCombatMod.config.reworked_sweeping_maximum_damage_penalty / BetterCombatMod.config.reworked_sweeping_extra_target_count) + * Math.min(BetterCombatMod.config.reworked_sweeping_extra_target_count, request.entityIds().length - 1); + var sweepRatio = player.getAttributeValue(EntityAttributes.PLAYER_SWEEPING_DAMAGE_RATIO); + + damageBaseMultiplier += multiplier + (BetterCombatMod.config.reworked_sweeping_maximum_damage_penalty * sweepRatio); + + boolean playEffects = !BetterCombatMod.config.reworked_sweeping_sound_and_particles_only_for_swords + || (hand.itemStack().getItem() instanceof SwordItem); + if (BetterCombatMod.config.reworked_sweeping_plays_sound && playEffects) { + world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENTITY_PLAYER_ATTACK_SWEEP, player.getSoundCategory(), 1.0f, 1.0f); + } + if (BetterCombatMod.config.reworked_sweeping_emits_particles && playEffects) { + player.spawnSweepAttackParticles(); + } } } - } - Multimap, EntityAttributeModifier> damageModifier = null; - if (damageBaseMultiplier != 0) { - AttributeModifierHelper.fromModifier(EntityAttributes.GENERIC_ATTACK_DAMAGE, null); - damageModifier = AttributeModifierHelper.fromModifier( - EntityAttributes.GENERIC_ATTACK_DAMAGE, - new EntityAttributeModifier(TEMPORARY_ATTACK, damageBaseMultiplier, EntityAttributeModifier.Operation.ADD_MULTIPLIED_BASE)); - player.getAttributes().addTemporaryModifiers(damageModifier); - } + Multimap, EntityAttributeModifier> damageModifier = null; + if (damageBaseMultiplier != 0) { + AttributeModifierHelper.fromModifier(EntityAttributes.GENERIC_ATTACK_DAMAGE, null); + damageModifier = AttributeModifierHelper.fromModifier( + EntityAttributes.GENERIC_ATTACK_DAMAGE, + new EntityAttributeModifier(TEMPORARY_ATTACK, damageBaseMultiplier, EntityAttributeModifier.Operation.ADD_MULTIPLIED_BASE)); + player.getAttributes().addTemporaryModifiers(damageModifier); + } - var attackCooldown = PlayerAttackHelper.getAttackCooldownTicksCapped(player); - var knockbackMultiplier = BetterCombatMod.config.knockback_reduced_for_fast_attacks - ? MathHelper.clamp(attackCooldown / 12.5F, 0.1F, 1F) - : 1F; - var lastAttackedTicks = ((LivingEntityAccessor)player).getLastAttackedTicks(); - if (!useVanillaPacket) { - player.setSneaking(request.isSneaking()); - } + var attackCooldown = PlayerAttackHelper.getAttackCooldownTicksCapped(player); + var knockbackMultiplier = BetterCombatMod.config.knockback_reduced_for_fast_attacks + ? MathHelper.clamp(attackCooldown / 12.5F, 0.1F, 1F) + : 1F; + var lastAttackedTicks = ((LivingEntityAccessor) player).getLastAttackedTicks(); + if (!useVanillaPacket) { + player.setSneaking(request.isSneaking()); + } - var validationRangeSquared = range * range * BetterCombatMod.config.target_search_range_multiplier; - for (int entityId: request.entityIds()) { - // getEntityById(entityId); - boolean isBossPart = false; - Entity entity = world.getEntityById(entityId); - if (entity == null) { - isBossPart = true; - entity = world.getDragonPart(entityId); // Get LivingEntity or DragonPart - } + var validationRangeSquared = range * range * BetterCombatMod.config.target_search_range_multiplier; + for (int entityId : request.entityIds()) { + // getEntityById(entityId); + boolean isBossPart = false; + Entity entity = world.getEntityById(entityId); + if (entity == null) { + isBossPart = true; + entity = world.getDragonPart(entityId); // Get LivingEntity or DragonPart + } - if (entity == null - || (entity.equals(player.getVehicle()) && !TargetHelper.isAttackableMount(entity)) - || (entity instanceof ArmorStandEntity && ((ArmorStandEntity)entity).isMarker())) { - continue; - } - if (entity instanceof LivingEntity livingEntity) { - if (BetterCombatMod.config.allow_fast_attacks) { - livingEntity.timeUntilRegen = 0; + if (entity == null + || (entity.equals(player.getVehicle()) && !TargetHelper.isAttackableMount(entity)) + || (entity instanceof ArmorStandEntity && ((ArmorStandEntity) entity).isMarker())) { + continue; } - if (knockbackMultiplier != 1F) { - ((ConfigurableKnockback)livingEntity).setKnockbackMultiplier_BetterCombat(knockbackMultiplier); + if (entity instanceof LivingEntity livingEntity) { + if (BetterCombatMod.config.allow_fast_attacks) { + livingEntity.timeUntilRegen = 0; + } + if (knockbackMultiplier != 1F) { + ((ConfigurableKnockback) livingEntity).setKnockbackMultiplier_BetterCombat(knockbackMultiplier); + } } - } - ((LivingEntityAccessor) player).setLastAttackedTicks(lastAttackedTicks); - // System.out.println("Server - Attacking hand: " + (hand.isOffHand() ? "offhand" : "mainhand") + " CD: " + player.getAttackCooldownProgress(0)); - if (!isBossPart && useVanillaPacket) { - // System.out.println("HIT - A entity: " + entity.getEntityName() + " id: " + entity.getId() + " class: " + entity.getClass()); - PlayerInteractEntityC2SPacket vanillaAttackPacket = PlayerInteractEntityC2SPacket.attack(entity, request.isSneaking()); - handler.onPlayerInteractEntity(vanillaAttackPacket); - } else { - // System.out.println("HIT - B entity: " + entity.getEntityName() + " id: " + entity.getId() + " class: " + entity.getClass()); - if (!BetterCombatMod.config.server_target_range_validation - || player.squaredDistanceTo(entity) <= validationRangeSquared) { - if (entity instanceof ItemEntity || entity instanceof ExperienceOrbEntity || entity instanceof PersistentProjectileEntity || entity == player) { - handler.disconnect(Text.translatable("multiplayer.disconnect.invalid_entity_attacked")); - LOGGER.warn("Player {} tried to attack an invalid entity", (Object)player.getName().getString()); - return; + ((LivingEntityAccessor) player).setLastAttackedTicks(lastAttackedTicks); + // System.out.println("Server - Attacking hand: " + (hand.isOffHand() ? "offhand" : "mainhand") + " CD: " + player.getAttackCooldownProgress(0)); + if (!isBossPart && useVanillaPacket) { + // System.out.println("HIT - A entity: " + entity.getEntityName() + " id: " + entity.getId() + " class: " + entity.getClass()); + PlayerInteractEntityC2SPacket vanillaAttackPacket = PlayerInteractEntityC2SPacket.attack(entity, request.isSneaking()); + handler.onPlayerInteractEntity(vanillaAttackPacket); + } else { + // System.out.println("HIT - B entity: " + entity.getEntityName() + " id: " + entity.getId() + " class: " + entity.getClass()); + if (!BetterCombatMod.config.server_target_range_validation + || player.squaredDistanceTo(entity) <= validationRangeSquared) { + if (entity instanceof ItemEntity || entity instanceof ExperienceOrbEntity || entity instanceof PersistentProjectileEntity || entity == player) { + handler.disconnect(Text.translatable("multiplayer.disconnect.invalid_entity_attacked")); + LOGGER.warn("Player {} tried to attack an invalid entity", (Object) player.getName().getString()); + return; + } + player.attack(entity); } - player.attack(entity); } - } - if (entity instanceof LivingEntity livingEntity) { - if (knockbackMultiplier != 1F) { - ((ConfigurableKnockback)livingEntity).setKnockbackMultiplier_BetterCombat(1F); + if (entity instanceof LivingEntity livingEntity) { + if (knockbackMultiplier != 1F) { + ((ConfigurableKnockback) livingEntity).setKnockbackMultiplier_BetterCombat(1F); + } } } - } - - if (!useVanillaPacket) { - player.updateLastActionTime(); - } + if (!useVanillaPacket) { + player.updateLastActionTime(); + } - if (damageModifier != null) { - player.getAttributes().removeModifiers(damageModifier); - } - - if (hand.isOffHand()) { - PlayerAttackHelper.setAttributesForOffHandAttack(player, false); - } + if (damageModifier != null) { + player.getAttributes().removeModifiers(damageModifier); + } - ((PlayerAttackProperties)player).setComboCount(-1); + ((PlayerAttackProperties) player).setComboCount(-1); + }); }); } } diff --git a/common/src/main/resources/data/minecraft/weapon_attributes/wooden_sword.json b/common/src/main/resources/data/minecraft/weapon_attributes/wooden_sword.json index c8bb11ed..11bc4728 100644 --- a/common/src/main/resources/data/minecraft/weapon_attributes/wooden_sword.json +++ b/common/src/main/resources/data/minecraft/weapon_attributes/wooden_sword.json @@ -1,3 +1,3 @@ { - "parent": "bettercombat:sword" + "parent": "bettercombat:claymore" } \ No newline at end of file