mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-18 12:48:53 +01:00
da7138233f
Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: ed0ec489 SPIGOT-7965: Unknown TransformReason for Hoglins 9db03457 SPIGOT-7964: Fix typo in Deprecation annotation d14119af PR-1082: Add "since" to Deprecation annotations e8a318d4 PR-1067: Add method to get Advancement requirements CraftBukkit Changes: 40dd796db SPIGOT-7971: NotSerializableException on serialize CraftUseCooldownComponent fa85c5e0a SPIGOT-7968: ProjectileHitEvent not trigerred when arrow hits entity b75b792ec SPIGOT-7970: World#getMaxHeight() returning incorrect value 2b9a094bb SPIGOT-7965: Unknown TransformReason for Hoglins fd3f5a380 SPIGOT-7966: Some trees do not generate with #generateTree f2822317c PR-1515: Add a Class reader and Class node argument provider 07abf6852 PR-1514: Add a test case for ClassTraverser a7577cb24 Fix Inventory#addItem not respecting max stack size 066a74e74 PR-1490: Add method to get Advancement requirements 4a1df30e4 PR-1512: Test Art class based on specific values instead of the implementation, to better catch implementation changes 53254c56f PR-1503: Simplify CAS loop to getAndSet e9447dc5e Make BlockDataMeta#setBlockData hide unspecified states dd08a7120 SPIGOT-7960: Fix inconsistency between natural item drop coordinates e9e8ed753 SPIGOT-7960: Improve natural item drop methods Spigot Changes: 60c9969b Rebuild patches
220 lines
11 KiB
Diff
220 lines
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Ineusia <ineusia@yahoo.com>
|
|
Date: Mon, 26 Oct 2020 11:48:06 -0500
|
|
Subject: [PATCH] Add Destroy Speed API
|
|
|
|
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
|
index a2fe7149a837040cf9f23eb426d398a5f90be394..27a7852a5d3f8c8960f098646ff5587c50556aa5 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
|
@@ -153,20 +153,20 @@ public class AttributeInstance {
|
|
double d = this.getBaseValue();
|
|
|
|
for (AttributeModifier attributeModifier : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_VALUE)) {
|
|
- d += attributeModifier.amount();
|
|
+ d += attributeModifier.amount(); // Paper - destroy speed API - diff on change
|
|
}
|
|
|
|
double e = d;
|
|
|
|
for (AttributeModifier attributeModifier2 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_BASE)) {
|
|
- e += d * attributeModifier2.amount();
|
|
+ e += d * attributeModifier2.amount(); // Paper - destroy speed API - diff on change
|
|
}
|
|
|
|
for (AttributeModifier attributeModifier3 : this.getModifiersOrEmpty(AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL)) {
|
|
- e *= 1.0 + attributeModifier3.amount();
|
|
+ e *= 1.0 + attributeModifier3.amount(); // Paper - destroy speed API - diff on change
|
|
}
|
|
|
|
- return this.attribute.value().sanitizeValue(e);
|
|
+ return attribute.value().sanitizeValue(e); // Paper - destroy speed API - diff on change
|
|
}
|
|
|
|
private Collection<AttributeModifier> getModifiersOrEmpty(AttributeModifier.Operation operation) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
|
index cabf3146b0dd5790536cb9995de6a876d7ab3f50..0cf033e1b559506bd902a2159adef2b279c18798 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
|
@@ -729,4 +729,35 @@ public class CraftBlockData implements BlockData {
|
|
public BlockState createBlockState() {
|
|
return CraftBlockStates.getBlockState(this.state, null);
|
|
}
|
|
+
|
|
+ // Paper start - destroy speed API
|
|
+ @Override
|
|
+ public float getDestroySpeed(final ItemStack itemStack, final boolean considerEnchants) {
|
|
+ net.minecraft.world.item.ItemStack nmsItemStack = CraftItemStack.unwrap(itemStack);
|
|
+ float speed = nmsItemStack.getDestroySpeed(this.state);
|
|
+ if (speed > 1.0F && considerEnchants) {
|
|
+ final net.minecraft.core.Holder<net.minecraft.world.entity.ai.attributes.Attribute> attribute = net.minecraft.world.entity.ai.attributes.Attributes.MINING_EFFICIENCY;
|
|
+ // Logic sourced from AttributeInstance#calculateValue
|
|
+ final double initialBaseValue = attribute.value().getDefaultValue();
|
|
+ final org.apache.commons.lang3.mutable.MutableDouble modifiedBaseValue = new org.apache.commons.lang3.mutable.MutableDouble(initialBaseValue);
|
|
+ final org.apache.commons.lang3.mutable.MutableDouble baseValMul = new org.apache.commons.lang3.mutable.MutableDouble(1);
|
|
+ final org.apache.commons.lang3.mutable.MutableDouble totalValMul = new org.apache.commons.lang3.mutable.MutableDouble(1);
|
|
+
|
|
+ net.minecraft.world.item.enchantment.EnchantmentHelper.forEachModifier(
|
|
+ nmsItemStack, net.minecraft.world.entity.EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> {
|
|
+ switch (attributeModifier.operation()) {
|
|
+ case ADD_VALUE -> modifiedBaseValue.add(attributeModifier.amount());
|
|
+ case ADD_MULTIPLIED_BASE -> baseValMul.add(attributeModifier.amount());
|
|
+ case ADD_MULTIPLIED_TOTAL -> totalValMul.setValue(totalValMul.doubleValue() * (1D + attributeModifier.amount()));
|
|
+ }
|
|
+ }
|
|
+ );
|
|
+
|
|
+ final double actualModifier = modifiedBaseValue.doubleValue() * baseValMul.doubleValue() * totalValMul.doubleValue();
|
|
+
|
|
+ speed += (float) attribute.value().sanitizeValue(actualModifier);
|
|
+ }
|
|
+ return speed;
|
|
+ }
|
|
+ // Paper end - destroy speed API
|
|
}
|
|
diff --git a/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..32d38205a5a72c3c1838ed28cb83bcea5ad59b6b
|
|
--- /dev/null
|
|
+++ b/src/test/java/io/papermc/paper/block/CraftBlockDataDestroySpeedTest.java
|
|
@@ -0,0 +1,138 @@
|
|
+package io.papermc.paper.block;
|
|
+
|
|
+import java.util.List;
|
|
+import java.util.Optional;
|
|
+import net.minecraft.core.Holder;
|
|
+import net.minecraft.core.HolderSet;
|
|
+import net.minecraft.core.component.DataComponentMap;
|
|
+import net.minecraft.core.component.DataComponents;
|
|
+import net.minecraft.network.chat.Component;
|
|
+import net.minecraft.world.entity.EquipmentSlot;
|
|
+import net.minecraft.world.entity.EquipmentSlotGroup;
|
|
+import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
|
+import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
|
+import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
+import net.minecraft.world.item.Items;
|
|
+import net.minecraft.world.item.enchantment.Enchantment;
|
|
+import net.minecraft.world.item.enchantment.EnchantmentEffectComponents;
|
|
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
|
+import net.minecraft.world.item.enchantment.ItemEnchantments;
|
|
+import net.minecraft.world.item.enchantment.LevelBasedValue;
|
|
+import net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect;
|
|
+import net.minecraft.world.level.block.Blocks;
|
|
+import net.minecraft.world.level.block.state.BlockState;
|
|
+import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
|
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
|
+import org.bukkit.inventory.ItemStack;
|
|
+import org.bukkit.support.environment.AllFeatures;
|
|
+import org.bukkit.util.Vector;
|
|
+import org.jetbrains.annotations.NotNull;
|
|
+import org.junit.jupiter.api.Assertions;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+import static net.minecraft.resources.ResourceLocation.fromNamespaceAndPath;
|
|
+
|
|
+/**
|
|
+ * CraftBlockData's {@link org.bukkit.craftbukkit.block.data.CraftBlockData#getDestroySpeed(ItemStack, boolean)}
|
|
+ * uses a reimplementation of AttributeValue without any map to avoid attribute instance allocation and mutation
|
|
+ * for 0 gain.
|
|
+ * <p>
|
|
+ * This test is responsible for ensuring that said logic emits the expected destroy speed under heavy attribute
|
|
+ * modifier use.
|
|
+ */
|
|
+@AllFeatures
|
|
+public class CraftBlockDataDestroySpeedTest {
|
|
+
|
|
+ @Test
|
|
+ public void testCorrectEnchantmentDestroySpeedComputation() {
|
|
+ // Construct fake enchantment that has *all and multiple of* operations
|
|
+ final Enchantment speedEnchantment = speedEnchantment();
|
|
+ final BlockState blockStateToMine = Blocks.STONE.defaultBlockState();
|
|
+
|
|
+ final ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(ItemEnchantments.EMPTY);
|
|
+ mutable.set(Holder.direct(speedEnchantment), 1);
|
|
+
|
|
+ final net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.DIAMOND_PICKAXE);
|
|
+ itemStack.set(DataComponents.ENCHANTMENTS, mutable.toImmutable());
|
|
+
|
|
+ // Compute expected value by running the entire attribute instance chain
|
|
+ final AttributeInstance dummyInstance = new AttributeInstance(Attributes.MINING_EFFICIENCY, $ -> {
|
|
+ });
|
|
+ EnchantmentHelper.forEachModifier(itemStack, EquipmentSlot.MAINHAND, (attributeHolder, attributeModifier) -> {
|
|
+ if (attributeHolder.is(Attributes.MINING_EFFICIENCY)) dummyInstance.addTransientModifier(attributeModifier);
|
|
+ });
|
|
+
|
|
+ final double toolSpeed = itemStack.getDestroySpeed(blockStateToMine);
|
|
+ final double expectedSpeed = toolSpeed <= 1.0F ? toolSpeed : toolSpeed + dummyInstance.getValue();
|
|
+
|
|
+ // API stack + computation
|
|
+ final CraftItemStack craftMirror = CraftItemStack.asCraftMirror(itemStack);
|
|
+ final CraftBlockData data = CraftBlockData.createData(blockStateToMine);
|
|
+ final float actualSpeed = data.getDestroySpeed(craftMirror, true);
|
|
+
|
|
+ Assertions.assertEquals(expectedSpeed, actualSpeed, Vector.getEpsilon());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Complex enchantment that holds attribute modifiers for the mining efficiency.
|
|
+ * The enchantment holds 2 of each operation to also ensure that such behaviour works correctly.
|
|
+ *
|
|
+ * @return the enchantment.
|
|
+ */
|
|
+ private static @NotNull Enchantment speedEnchantment() {
|
|
+ return new Enchantment(
|
|
+ Component.empty(),
|
|
+ new Enchantment.EnchantmentDefinition(
|
|
+ HolderSet.empty(),
|
|
+ Optional.empty(),
|
|
+ 0, 0,
|
|
+ Enchantment.constantCost(0),
|
|
+ Enchantment.constantCost(0),
|
|
+ 0,
|
|
+ List.of(EquipmentSlotGroup.ANY)
|
|
+ ),
|
|
+ HolderSet.empty(),
|
|
+ DataComponentMap.builder()
|
|
+ .set(EnchantmentEffectComponents.ATTRIBUTES, List.of(
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "base1"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.constant(1),
|
|
+ AttributeModifier.Operation.ADD_VALUE
|
|
+ ),
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "base2"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.perLevel(3),
|
|
+ AttributeModifier.Operation.ADD_VALUE
|
|
+ ),
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "base-mul1"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.perLevel(7),
|
|
+ AttributeModifier.Operation.ADD_MULTIPLIED_BASE
|
|
+ ),
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "base-mul2"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.constant(10),
|
|
+ AttributeModifier.Operation.ADD_MULTIPLIED_BASE
|
|
+ ),
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "total-mul1"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.constant(.2f),
|
|
+ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL
|
|
+ ),
|
|
+ new EnchantmentAttributeEffect(
|
|
+ fromNamespaceAndPath("paper", "total-mul2"),
|
|
+ Attributes.MINING_EFFICIENCY,
|
|
+ LevelBasedValue.constant(-.5F),
|
|
+ AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL
|
|
+ )
|
|
+ ))
|
|
+ .build()
|
|
+ );
|
|
+ }
|
|
+
|
|
+}
|