From ec951ea440432bd584dfd23f7afba759822b0917 Mon Sep 17 00:00:00 2001 From: Meredith Espinosa Date: Tue, 21 Apr 2020 20:30:02 -0700 Subject: [PATCH] fabric-mining-levels-v0 -> fabric-tool-attribute-api-v1 (1.15 edition) (#460) Moves the ToolManager and tool tags declared in fabric-mining-levels-v0 to a new fabric-tool-attributes-v1, along with adding new interfaces to be implemented on tools so that mining speed, mining level, and entity attribute modifiers can be decided by the itemstack. --- fabric-mining-levels-v0/build.gradle | 3 +- .../fabric/api/tag/FabricItemTags.java | 4 +- .../fabric/api/tools/FabricToolTags.java | 20 ++--- .../mining/level/MiningToolItemAccessor.java | 28 ------ .../mixin/mining/level/MixinItemStack.java | 58 ------------ .../fabric-mining-levels-v0.mixins.json | 12 --- .../src/main/resources/fabric.mod.json | 8 +- fabric-object-builders-v0/build.gradle | 2 +- .../fabric/api/block/FabricBlockSettings.java | 2 +- .../src/main/resources/fabric.mod.json | 2 +- fabric-tool-attribute-api-v1/build.gradle | 7 ++ .../attribute/v1/DynamicAttributeTool.java | 67 ++++++++++++++ .../api/tool/attribute/v1/FabricToolTags.java | 41 +++++++++ .../impl/tool/attribute/AttributeManager.java | 83 ++++++++++++++++++ .../impl/tool/attribute}/ToolManager.java | 17 ++-- .../mixin/tool/attribute/MixinItemStack.java | 81 +++++++++++++++++ .../tool/attribute/MixinLivingEntity.java | 60 +++++++++++++ .../tool/attribute/MixinPlayerInventory.java | 73 +++++++++++++++ .../mixin/tool/attribute/MixinToolItem.java | 48 ++++++++++ .../fabric-tool-attribute-api-v1/icon.png | Bin 0 -> 1579 bytes .../data/fabric/tags/items/axes.json | 0 .../data/fabric/tags/items/hoes.json | 0 .../data/fabric/tags/items/pickaxes.json | 0 .../data/fabric/tags/items/shears.json | 6 ++ .../data/fabric/tags/items/shovels.json | 0 .../data/fabric/tags/items/swords.json | 0 .../fabric-tool-attribute-api-v1.mixins.json | 14 +++ .../src/main/resources/fabric.mod.json | 27 ++++++ settings.gradle | 1 + 29 files changed, 536 insertions(+), 128 deletions(-) delete mode 100644 fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MiningToolItemAccessor.java delete mode 100644 fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MixinItemStack.java delete mode 100644 fabric-mining-levels-v0/src/main/resources/fabric-mining-levels-v0.mixins.json create mode 100644 fabric-tool-attribute-api-v1/build.gradle create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/DynamicAttributeTool.java create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/FabricToolTags.java create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/AttributeManager.java rename {fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/impl/mining/level => fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute}/ToolManager.java (82%) create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinItemStack.java create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinLivingEntity.java create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinPlayerInventory.java create mode 100644 fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinToolItem.java create mode 100644 fabric-tool-attribute-api-v1/src/main/resources/assets/fabric-tool-attribute-api-v1/icon.png rename {fabric-mining-levels-v0 => fabric-tool-attribute-api-v1}/src/main/resources/data/fabric/tags/items/axes.json (100%) rename {fabric-mining-levels-v0 => fabric-tool-attribute-api-v1}/src/main/resources/data/fabric/tags/items/hoes.json (100%) rename {fabric-mining-levels-v0 => fabric-tool-attribute-api-v1}/src/main/resources/data/fabric/tags/items/pickaxes.json (100%) create mode 100644 fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shears.json rename {fabric-mining-levels-v0 => fabric-tool-attribute-api-v1}/src/main/resources/data/fabric/tags/items/shovels.json (100%) rename {fabric-mining-levels-v0 => fabric-tool-attribute-api-v1}/src/main/resources/data/fabric/tags/items/swords.json (100%) create mode 100644 fabric-tool-attribute-api-v1/src/main/resources/fabric-tool-attribute-api-v1.mixins.json create mode 100644 fabric-tool-attribute-api-v1/src/main/resources/fabric.mod.json diff --git a/fabric-mining-levels-v0/build.gradle b/fabric-mining-levels-v0/build.gradle index e7543e2b9..7b1d897ac 100644 --- a/fabric-mining-levels-v0/build.gradle +++ b/fabric-mining-levels-v0/build.gradle @@ -1,7 +1,8 @@ archivesBaseName = "fabric-mining-levels-v0" -version = getSubprojectVersion(project, "0.1.1") +version = getSubprojectVersion(project, "0.1.2") dependencies { compile project(path: ':fabric-api-base', configuration: 'dev') compile project(path: ':fabric-tag-extensions-v0', configuration: 'dev') + compile project(path: ':fabric-tool-attribute-api-v1', configuration: 'dev') } diff --git a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java index 570d7dbee..ae6cc17ad 100644 --- a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java +++ b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java @@ -20,12 +20,12 @@ import net.minecraft.item.Item; import net.minecraft.tag.Tag; import net.minecraft.util.Identifier; -import net.fabricmc.fabric.api.tools.FabricToolTags; +import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags; /** * Item tags provided by Fabric. * - * @deprecated Use dedicated classes, such as {@link net.fabricmc.fabric.api.tools.FabricToolTags} + * @deprecated Use dedicated classes, such as {@link FabricToolTags} */ @Deprecated public class FabricItemTags { diff --git a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tools/FabricToolTags.java b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tools/FabricToolTags.java index a7567c43d..62aa3684f 100644 --- a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tools/FabricToolTags.java +++ b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/api/tools/FabricToolTags.java @@ -18,23 +18,19 @@ package net.fabricmc.fabric.api.tools; import net.minecraft.item.Item; import net.minecraft.tag.Tag; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.tag.TagRegistry; /** * Tool item tags provided by Fabric. + * + * @deprecated Use the moved {@link net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags} class instead */ +@Deprecated public class FabricToolTags { - public static final Tag AXES = register("axes"); - public static final Tag HOES = register("hoes"); - public static final Tag PICKAXES = register("pickaxes"); - public static final Tag SHOVELS = register("shovels"); - public static final Tag SWORDS = register("swords"); + public static final Tag AXES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.AXES; + public static final Tag HOES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.HOES; + public static final Tag PICKAXES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.PICKAXES; + public static final Tag SHOVELS = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.SHOVELS; + public static final Tag SWORDS = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.SWORDS; private FabricToolTags() { } - - private static Tag register(String id) { - return TagRegistry.item(new Identifier("fabric", id)); - } } diff --git a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MiningToolItemAccessor.java b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MiningToolItemAccessor.java deleted file mode 100644 index e7547f51b..000000000 --- a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MiningToolItemAccessor.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.mixin.mining.level; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.item.MiningToolItem; - -@Mixin(MiningToolItem.class) -public interface MiningToolItemAccessor { - @Accessor - float getMiningSpeed(); -} diff --git a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MixinItemStack.java b/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MixinItemStack.java deleted file mode 100644 index 3ce3cbdfc..000000000 --- a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/mixin/mining/level/MixinItemStack.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.mixin.mining.level; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.block.BlockState; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; - -import net.fabricmc.fabric.api.util.TriState; -import net.fabricmc.fabric.impl.mining.level.ToolManager; - -@Mixin(ItemStack.class) -public abstract class MixinItemStack { - @Shadow - public abstract Item getItem(); - - @Inject(at = @At("HEAD"), method = "isEffectiveOn", cancellable = true) - public void isEffectiveOn(BlockState state, CallbackInfoReturnable info) { - TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state); - - if (triState != TriState.DEFAULT) { - info.setReturnValue(triState.get()); - info.cancel(); - } - } - - @Inject(at = @At("HEAD"), method = "getMiningSpeed", cancellable = true) - public void getBlockBreakingSpeed(BlockState state, CallbackInfoReturnable info) { - if (this.getItem() instanceof MiningToolItemAccessor) { - TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state); - - if (triState != TriState.DEFAULT) { - info.setReturnValue(triState.get() ? ((MiningToolItemAccessor) this.getItem()).getMiningSpeed() : 1.0F); - info.cancel(); - } - } - } -} diff --git a/fabric-mining-levels-v0/src/main/resources/fabric-mining-levels-v0.mixins.json b/fabric-mining-levels-v0/src/main/resources/fabric-mining-levels-v0.mixins.json deleted file mode 100644 index 258312778..000000000 --- a/fabric-mining-levels-v0/src/main/resources/fabric-mining-levels-v0.mixins.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "required": true, - "package": "net.fabricmc.fabric.mixin.mining.level", - "compatibilityLevel": "JAVA_8", - "mixins": [ - "MiningToolItemAccessor", - "MixinItemStack" - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/fabric-mining-levels-v0/src/main/resources/fabric.mod.json b/fabric-mining-levels-v0/src/main/resources/fabric.mod.json index a0a2c8aaa..bbf95ced2 100644 --- a/fabric-mining-levels-v0/src/main/resources/fabric.mod.json +++ b/fabric-mining-levels-v0/src/main/resources/fabric.mod.json @@ -18,10 +18,8 @@ "depends": { "fabricloader": ">=0.4.0", "fabric-api-base": "*", - "fabric-tag-extensions-v0": "*" + "fabric-tag-extensions-v0": "*", + "fabric-tool-attribute-api-v1": "*" }, - "description": "Block mining level tags for tools.", - "mixins": [ - "fabric-mining-levels-v0.mixins.json" - ] + "description": "Block mining level tags for tools. Deprecated and replaced by fabric-tool-attribute-v1." } diff --git a/fabric-object-builders-v0/build.gradle b/fabric-object-builders-v0/build.gradle index e208b125f..5356e710c 100644 --- a/fabric-object-builders-v0/build.gradle +++ b/fabric-object-builders-v0/build.gradle @@ -3,5 +3,5 @@ version = getSubprojectVersion(project, "0.1.4") dependencies { compile project(path: ':fabric-api-base', configuration: 'dev') - compile project(path: ':fabric-mining-levels-v0', configuration: 'dev') + compile project(path: ':fabric-tool-attribute-api-v1', configuration: 'dev') } diff --git a/fabric-object-builders-v0/src/main/java/net/fabricmc/fabric/api/block/FabricBlockSettings.java b/fabric-object-builders-v0/src/main/java/net/fabricmc/fabric/api/block/FabricBlockSettings.java index a20b00cb4..2c22e048b 100644 --- a/fabric-object-builders-v0/src/main/java/net/fabricmc/fabric/api/block/FabricBlockSettings.java +++ b/fabric-object-builders-v0/src/main/java/net/fabricmc/fabric/api/block/FabricBlockSettings.java @@ -32,7 +32,7 @@ import net.minecraft.util.DyeColor; import net.minecraft.util.Identifier; import net.fabricmc.fabric.api.event.registry.BlockConstructedCallback; -import net.fabricmc.fabric.impl.mining.level.ToolManager; +import net.fabricmc.fabric.impl.tool.attribute.ToolManager; /** * Fabric's version of Block.Settings. Adds additional methods and hooks diff --git a/fabric-object-builders-v0/src/main/resources/fabric.mod.json b/fabric-object-builders-v0/src/main/resources/fabric.mod.json index 225288f0d..bd83856a3 100644 --- a/fabric-object-builders-v0/src/main/resources/fabric.mod.json +++ b/fabric-object-builders-v0/src/main/resources/fabric.mod.json @@ -18,7 +18,7 @@ "depends": { "fabricloader": ">=0.4.0", "fabric-api-base": "*", - "fabric-mining-levels-v0": "*" + "fabric-tool-attribute-api-v1": "*" }, "description": "Builders for objects vanilla has locked down.", "mixins": [ diff --git a/fabric-tool-attribute-api-v1/build.gradle b/fabric-tool-attribute-api-v1/build.gradle new file mode 100644 index 000000000..6b1768f45 --- /dev/null +++ b/fabric-tool-attribute-api-v1/build.gradle @@ -0,0 +1,7 @@ +archivesBaseName = "fabric-tool-attribute-api-v1" +version = getSubprojectVersion(project, "1.0.0") + +dependencies { + compile project(path: ':fabric-api-base', configuration: 'dev') + compile project(path: ':fabric-tag-extensions-v0', configuration: 'dev') +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/DynamicAttributeTool.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/DynamicAttributeTool.java new file mode 100644 index 000000000..014e383db --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/DynamicAttributeTool.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.tool.attribute.v1; + +import com.google.common.collect.ImmutableSetMultimap; +import com.google.common.collect.Multimap; + +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.ItemStack; + +/** + * Interface for adding various tool attributes to items. + */ +public interface DynamicAttributeTool { + Multimap EMPTY = ImmutableSetMultimap.of(); + + /** + * Determines the mining level of the passed stack, which is used for calculating what blocks this tool is allowed to break. + * + * @param stack The stack to check on. + * @param user The current user of the tool, or null if there isn't any. + * @return The mining level of the item. 3 is equal to a diamond pick. + */ + //TODO: nullable on user once we have an official @Nullable annotation in + int getMiningLevel(ItemStack stack, LivingEntity user); + + /** + * Determines the mining speed multiplier of the passed stack, which is one factor in overall mining speed. + * + * @param stack The stack to check on. + * @param user The current user of the tool, or null if there isn't any. + * @return The mining speed multiplier of the item. 8.0 is equal to a diamond pick. + */ + //TODO: nullable on user once we have an official @Nullable annotation in + float getMiningSpeedMultiplier(ItemStack stack, LivingEntity user); + + /** + * Add modifiers for any {@link net.minecraft.entity.attribute.EntityAttributes} your item should give when equipped, based on the stack. + * + *

Appends to either attribute modifier NBT or the result from {@link net.minecraft.item.Item#getModifiers(EquipmentSlot)}.

+ * + * @param slot The equipment slot this item is equipped in. + * @param stack The stack that's equipped. + * @param user The current user of the tool, or none if there isn't any + * @return The dynamic modifiers to add on top of other modifiers on this stack. If none, return {@link #EMPTY}. + */ + //TODO: nullable on user once we have an official @Nullable annotation in + default Multimap getDynamicModifiers(EquipmentSlot slot, ItemStack stack, LivingEntity user) { + return EMPTY; + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/FabricToolTags.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/FabricToolTags.java new file mode 100644 index 000000000..854d52fa9 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/FabricToolTags.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.tool.attribute.v1; + +import net.minecraft.item.Item; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; + +import net.fabricmc.fabric.api.tag.TagRegistry; + +/** + * Tool item tags provided by Fabric. + */ +public class FabricToolTags { + public static final Tag AXES = register("axes"); + public static final Tag HOES = register("hoes"); + public static final Tag PICKAXES = register("pickaxes"); + public static final Tag SHOVELS = register("shovels"); + public static final Tag SWORDS = register("swords"); + public static final Tag SHEARS = register("shears"); + + private FabricToolTags() { } + + private static Tag register(String id) { + return TagRegistry.item(new Identifier("fabric", id)); + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/AttributeManager.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/AttributeManager.java new file mode 100644 index 000000000..37f3adca4 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/AttributeManager.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.tool.attribute; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import net.minecraft.entity.attribute.EntityAttributeModifier; + +public final class AttributeManager { + private AttributeManager() { } + + /** + * Merge two multimaps of EntityAttributeModifiers, combining their modifiers to prevent duplicate entries in a tooltip. + * + * @param left The first of the two multimaps to merge. + * @param right The second of the two multimaps to merge. + * @return The merged form of the two. + */ + public static Multimap mergeAttributes(Multimap left, Multimap right) { + if (left.isEmpty()) return right; + if (right.isEmpty()) return left; + Multimap ret = HashMultimap.create(); + Set allKeys = new HashSet<>(); + allKeys.addAll(left.keySet()); + allKeys.addAll(right.keySet()); + + for (String key : allKeys) { + double add = 0; + double multBase = 1; + double multTotal = 1; + Collection modifiers; + + if (left.containsKey(key)) { + modifiers = left.get(key); + if (right.containsKey(key)) modifiers.addAll(right.get(key)); + } else { + //key *must* be in either left or right, so if it's not in left, it *must* be in right + modifiers = right.get(key); + } + + for (EntityAttributeModifier mod : modifiers) { + switch (mod.getOperation()) { + case ADDITION: + add += mod.getAmount(); + break; + case MULTIPLY_BASE: + multBase += mod.getAmount(); + break; + case MULTIPLY_TOTAL: + multTotal *= 1 + mod.getAmount(); + break; + default: + break; + } + } + + ret.put(key, new EntityAttributeModifier(key, add, EntityAttributeModifier.Operation.ADDITION)); + ret.put(key, new EntityAttributeModifier(key, multBase, EntityAttributeModifier.Operation.MULTIPLY_BASE)); + ret.put(key, new EntityAttributeModifier(key, multTotal, EntityAttributeModifier.Operation.MULTIPLY_TOTAL)); + } + + return ret; + } +} diff --git a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/impl/mining/level/ToolManager.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/ToolManager.java similarity index 82% rename from fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/impl/mining/level/ToolManager.java rename to fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/ToolManager.java index 2008ed3bd..5ee834c2c 100644 --- a/fabric-mining-levels-v0/src/main/java/net/fabricmc/fabric/impl/mining/level/ToolManager.java +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/impl/tool/attribute/ToolManager.java @@ -14,18 +14,19 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.mining.level; +package net.fabricmc.fabric.impl.tool.attribute; import java.util.HashMap; import java.util.Map; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.item.ToolItem; import net.minecraft.tag.Tag; +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; import net.fabricmc.fabric.api.util.TriState; public final class ToolManager { @@ -85,9 +86,10 @@ public final class ToolManager { entry(block).putBreakByTool(tag, miningLevel); } - private static int getMiningLevel(ItemStack stack) { - if (stack.getItem() instanceof ToolItem) { - return ((ToolItem) stack.getItem()).getMaterial().getMiningLevel(); + //TODO: nullable on user once we have an official @Nullable annotation in + private static int getMiningLevel(ItemStack stack, LivingEntity user) { + if (stack.getItem() instanceof DynamicAttributeTool) { + return ((DynamicAttributeTool) stack.getItem()).getMiningLevel(stack, user); } else { return 0; } @@ -96,7 +98,8 @@ public final class ToolManager { /** * Hook for ItemStack.isEffectiveOn and similar methods. */ - public static TriState handleIsEffectiveOn(ItemStack stack, BlockState state) { + //TODO: nullable on user once we have an official @Nullable annotation in + public static TriState handleIsEffectiveOn(ItemStack stack, BlockState state, LivingEntity user) { EntryImpl entry = entries.get(state.getBlock()); if (entry != null) { @@ -104,7 +107,7 @@ public final class ToolManager { for (int i = 0; i < entry.tags.length; i++) { if (item.isIn(entry.tags[i])) { - return TriState.of(getMiningLevel(stack) >= entry.tagLevels[i]); + return TriState.of(getMiningLevel(stack, user) >= entry.tagLevels[i]); } } diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinItemStack.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinItemStack.java new file mode 100644 index 000000000..c5a2a526d --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinItemStack.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.tool.attribute; + +import com.google.common.collect.Multimap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.api.util.TriState; +import net.fabricmc.fabric.impl.tool.attribute.AttributeManager; +import net.fabricmc.fabric.impl.tool.attribute.ToolManager; + +@Mixin(ItemStack.class) +public abstract class MixinItemStack { + @Shadow + public abstract Item getItem(); + + @Inject(at = @At("HEAD"), method = "isEffectiveOn", cancellable = true) + public void isEffectiveOn(BlockState state, CallbackInfoReturnable info) { + TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state, null); + + if (triState != TriState.DEFAULT) { + info.setReturnValue(triState.get()); + info.cancel(); + } + } + + @Inject(at = @At("HEAD"), method = "getMiningSpeed", cancellable = true) + public void getMiningSpeed(BlockState state, CallbackInfoReturnable info) { + TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state, null); + + if (triState != TriState.DEFAULT) { + Item item = this.getItem(); + float miningSpeed; + + if (item instanceof DynamicAttributeTool) { + miningSpeed = ((DynamicAttributeTool) this.getItem()).getMiningSpeedMultiplier((ItemStack) (Object) this, null); + } else { + return; + } + + info.setReturnValue(triState.get() ? miningSpeed : 1.0F); + } + } + + @Inject(at = @At("RETURN"), method = "getAttributeModifiers", cancellable = true, locals = LocalCapture.CAPTURE_FAILEXCEPTION) + public void getAttributeModifiers(EquipmentSlot slot, CallbackInfoReturnable> info, Multimap multimap) { + ItemStack stack = (ItemStack) (Object) this; + + if (stack.getItem() instanceof DynamicAttributeTool) { + DynamicAttributeTool holder = (DynamicAttributeTool) stack.getItem(); + Multimap ret = AttributeManager.mergeAttributes(multimap, (holder).getDynamicModifiers(slot, stack, null)); + info.setReturnValue(ret); + } + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinLivingEntity.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinLivingEntity.java new file mode 100644 index 000000000..55a18ffc1 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinLivingEntity.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.tool.attribute; + +import com.google.common.collect.Multimap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.impl.tool.attribute.AttributeManager; + +@Mixin(LivingEntity.class) +public abstract class MixinLivingEntity extends Entity { + public MixinLivingEntity(EntityType type, World world) { + super(type, world); + } + + /** + * @author B0undarybreaker + * @reason get entity attribute modifiers for dynamic tools + */ + @Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;")) + public Multimap actTickModifiers(ItemStack stack, EquipmentSlot slot) { + return actModifiers(stack, slot, (LivingEntity) (Object) this); + } + + private static Multimap actModifiers(ItemStack stack, EquipmentSlot slot, LivingEntity user) { + Multimap original = stack.getAttributeModifiers(slot); + + if (stack.getItem() instanceof DynamicAttributeTool) { + DynamicAttributeTool tool = (DynamicAttributeTool) stack.getItem(); + return (AttributeManager.mergeAttributes(original, tool.getDynamicModifiers(slot, stack, user))); + } + + return original; + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinPlayerInventory.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinPlayerInventory.java new file mode 100644 index 000000000..48efca89d --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinPlayerInventory.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.tool.attribute; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DefaultedList; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; +import net.fabricmc.fabric.api.util.TriState; +import net.fabricmc.fabric.impl.tool.attribute.ToolManager; + +@Mixin(PlayerInventory.class) +public abstract class MixinPlayerInventory { + @Shadow + @Final + public DefaultedList main; + + @Shadow + public int selectedSlot; + + @Shadow + @Final + public PlayerEntity player; + + @Shadow + public abstract ItemStack getInvStack(int int_1); + + @Inject(method = "isUsingEffectiveTool", at = @At("HEAD")) + public void actMiningLevel(BlockState state, CallbackInfoReturnable info) { + ItemStack stack = this.getInvStack(this.selectedSlot); + + if (stack.getItem() instanceof DynamicAttributeTool) { + TriState ret = ToolManager.handleIsEffectiveOn(stack, state, player); + + if (ret != TriState.DEFAULT) { + info.setReturnValue(ret.get()); + } + } + } + + @Inject(method = "getBlockBreakingSpeed", at = @At("HEAD")) + public void actMiningSleed(BlockState state, CallbackInfoReturnable info) { + ItemStack stack = this.main.get(this.selectedSlot); + + if (stack.getItem() instanceof DynamicAttributeTool) { + info.setReturnValue(((DynamicAttributeTool) stack.getItem()).getMiningSpeedMultiplier(stack, player)); + } + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinToolItem.java b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinToolItem.java new file mode 100644 index 000000000..3fe2c5b26 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinToolItem.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.tool.attribute; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ToolItem; +import net.minecraft.item.ToolMaterial; + +import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool; + +@Mixin(ToolItem.class) +public abstract class MixinToolItem extends Item implements DynamicAttributeTool { + @Shadow + public abstract ToolMaterial getMaterial(); + + public MixinToolItem(Settings settings) { + super(settings); + } + + @Override + public int getMiningLevel(ItemStack stack, LivingEntity user) { + return this.getMaterial().getMiningLevel(); + } + + @Override + public float getMiningSpeedMultiplier(ItemStack stack, LivingEntity user) { + return this.getMaterial().getMiningSpeed(); + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/resources/assets/fabric-tool-attribute-api-v1/icon.png b/fabric-tool-attribute-api-v1/src/main/resources/assets/fabric-tool-attribute-api-v1/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2931efbf610873c0084debb8690902b0103d27fe GIT binary patch literal 1579 zcmbVMTWB0r7@iGm)TAXsYw<=rnU=;v=W=GRbL=!tc4Brl6GO7t2vVJ$IlDV#XU;e? z+r2ymsZdMQqAyaFLLUo;RumtE8Z@?uf_*4nP^4;o6fOFoSkN+o1$K?f2nE9_*b5G-l)AV)k5Qhb^- zU{V4ZnTKgnmXdpcB*Kg!W(1hvM2N&RO30x1u~eI9meGQGe@_?PDQq%q1CiV$8~M7 z?MQ_mOdqCh^a65Sv|ntwSXjV5se1;VK1|Kr8G7TQoQL&*ctt{L{fClG}xPK5k^yK3%T69N6J=>3jBqc zDNvZsrJ-yOXI^^mWf1cmY^XST)CVzIGjvEPENowmy}ax zvJ8_(Cf#+H-dBlH53`_u-~6BVAMz|(g?jCVdBWNZ(+A}(pFV7>S3QgPiQcMaflkIC z-3Ti|VT~{au*vq0ts9O&m$p&Gl=L6+q6_m$IcVq}o~+Pl{g>1esQp4%wp~|*zk1n` zZ7T6Toc4`y88s}riCP|ZXrJ?FLz@^KTcyqLjey zu95Yz%F&S{<0~f)Iomek?+hQ%MhCu%T^zsg>C_L`1`Br`xNY&))k9yTQb$JC>)w_f zpU(^tu^Q)y%W~lVz`jz;_ jF?g&s@Y=Qe&c#kW|JbvqK0Y=Rw)4XDoVqsk_>;c_`@;F@ literal 0 HcmV?d00001 diff --git a/fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/axes.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/axes.json similarity index 100% rename from fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/axes.json rename to fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/axes.json diff --git a/fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/hoes.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/hoes.json similarity index 100% rename from fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/hoes.json rename to fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/hoes.json diff --git a/fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/pickaxes.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/pickaxes.json similarity index 100% rename from fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/pickaxes.json rename to fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/pickaxes.json diff --git a/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shears.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shears.json new file mode 100644 index 000000000..7aeb6cb47 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shears.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:shears" + ] +} \ No newline at end of file diff --git a/fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/shovels.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shovels.json similarity index 100% rename from fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/shovels.json rename to fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/shovels.json diff --git a/fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/swords.json b/fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/swords.json similarity index 100% rename from fabric-mining-levels-v0/src/main/resources/data/fabric/tags/items/swords.json rename to fabric-tool-attribute-api-v1/src/main/resources/data/fabric/tags/items/swords.json diff --git a/fabric-tool-attribute-api-v1/src/main/resources/fabric-tool-attribute-api-v1.mixins.json b/fabric-tool-attribute-api-v1/src/main/resources/fabric-tool-attribute-api-v1.mixins.json new file mode 100644 index 000000000..d41f8b3af --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/resources/fabric-tool-attribute-api-v1.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "net.fabricmc.fabric.mixin.tool.attribute", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "MixinItemStack", + "MixinLivingEntity", + "MixinPlayerInventory", + "MixinToolItem" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/fabric-tool-attribute-api-v1/src/main/resources/fabric.mod.json b/fabric-tool-attribute-api-v1/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..2a9700d87 --- /dev/null +++ b/fabric-tool-attribute-api-v1/src/main/resources/fabric.mod.json @@ -0,0 +1,27 @@ +{ + "schemaVersion": 1, + "id": "fabric-tool-attribute-api-v1", + "name": "Fabric Tool Attribute API (v1)", + "version": "${version}", + "environment": "*", + "license": "Apache-2.0", + "icon": "assets/fabric-tool-attribute0api-v1/icon.png", + "contact": { + "homepage": "https://fabricmc.net", + "irc": "irc://irc.esper.net:6667/fabric", + "issues": "https://github.com/FabricMC/fabric/issues", + "sources": "https://github.com/FabricMC/fabric" + }, + "authors": [ + "FabricMC" + ], + "depends": { + "fabricloader": ">=0.4.0", + "fabric-api-base": "*", + "fabric-tag-extensions-v0": "*" + }, + "description": "Dynamic atttributes for tools.", + "mixins": [ + "fabric-tool-attribute-api-v1.mixins.json" + ] +} diff --git a/settings.gradle b/settings.gradle index ef7a1b243..bc20c5703 100644 --- a/settings.gradle +++ b/settings.gradle @@ -43,3 +43,4 @@ include 'fabric-resource-loader-v0' include 'fabric-tag-extensions-v0' include 'fabric-textures-v0' include 'fabric-dimensions-v1' +include 'fabric-tool-attribute-api-v1'