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.
This commit is contained in:
Meredith Espinosa 2020-04-21 20:30:02 -07:00 committed by Player
parent 6c0e72dfcd
commit b764ce9905
29 changed files with 573 additions and 127 deletions

View file

@ -4,4 +4,5 @@ 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')
}

View file

@ -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 {

View file

@ -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<Item> AXES = register("axes");
public static final Tag<Item> HOES = register("hoes");
public static final Tag<Item> PICKAXES = register("pickaxes");
public static final Tag<Item> SHOVELS = register("shovels");
public static final Tag<Item> SWORDS = register("swords");
public static final Tag<Item> AXES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.AXES;
public static final Tag<Item> HOES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.HOES;
public static final Tag<Item> PICKAXES = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.PICKAXES;
public static final Tag<Item> SHOVELS = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.SHOVELS;
public static final Tag<Item> SWORDS = net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags.SWORDS;
private FabricToolTags() { }
private static Tag<Item> register(String id) {
return TagRegistry.item(new Identifier("fabric", id));
}
}

View file

@ -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();
}

View file

@ -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<Boolean> info) {
TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state);
if (triState != TriState.DEFAULT) {
info.setReturnValue(triState.get());
info.cancel();
}
}
@Inject(at = @At("HEAD"), method = "getMiningSpeedMultiplier", cancellable = true)
public void getBlockBreakingSpeed(BlockState state, CallbackInfoReturnable<Float> 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();
}
}
}
}

View file

@ -1,12 +0,0 @@
{
"required": true,
"package": "net.fabricmc.fabric.mixin.mining.level",
"compatibilityLevel": "JAVA_8",
"mixins": [
"MiningToolItemAccessor",
"MixinItemStack"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -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."
}

View file

@ -3,5 +3,5 @@ version = getSubprojectVersion(project, "0.2.5")
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')
}

View file

@ -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

View file

@ -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": [

View file

@ -0,0 +1,7 @@
archivesBaseName = "fabric-tool-attribute-api-v1"
version = getSubprojectVersion(project, "1.0.1")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
compile project(path: ':fabric-tag-extensions-v0', configuration: 'dev')
}

View file

@ -0,0 +1,68 @@
/*
* 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.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.item.ItemStack;
/**
* Interface for adding various tool attributes to items.
*/
public interface DynamicAttributeTool {
Multimap<EntityAttribute, EntityAttributeModifier> 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.
*
* <p>Appends to either attribute modifier NBT or the result from {@link net.minecraft.item.Item#getModifiers(EquipmentSlot)}.</p>
*
* @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<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, LivingEntity user) {
return EMPTY;
}
}

View file

@ -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<Item> AXES = register("axes");
public static final Tag<Item> HOES = register("hoes");
public static final Tag<Item> PICKAXES = register("pickaxes");
public static final Tag<Item> SHOVELS = register("shovels");
public static final Tag<Item> SWORDS = register("swords");
public static final Tag<Item> SHEARS = register("shears");
private FabricToolTags() { }
private static Tag<Item> register(String id) {
return TagRegistry.item(new Identifier("fabric", id));
}
}

View file

@ -0,0 +1,118 @@
/*
* 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.ArrayList;
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.EntityAttribute;
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<EntityAttribute, EntityAttributeModifier> mergeAttributes(Multimap<EntityAttribute, EntityAttributeModifier> left, Multimap<EntityAttribute, EntityAttributeModifier> right) {
if (left.isEmpty()) return right;
if (right.isEmpty()) return left;
Multimap<EntityAttribute, EntityAttributeModifier> ret = HashMultimap.create();
Set<EntityAttribute> allKeys = new HashSet<>();
allKeys.addAll(left.keySet());
allKeys.addAll(right.keySet());
for (EntityAttribute key : allKeys) {
Collection<EntityAttributeModifier> leftModifiers = left.get(key);
Collection<EntityAttributeModifier> rightModifiers = right.get(key);
if (leftModifiers.isEmpty()) {
ret.putAll(key, rightModifiers);
} else if (rightModifiers.isEmpty()) {
ret.putAll(key, leftModifiers);
} else {
Collection<EntityAttributeModifier> modifiers = new ArrayList<>(leftModifiers.size() + rightModifiers.size());
modifiers.addAll(leftModifiers);
modifiers.addAll(rightModifiers);
EntityAttributeModifier lastAddMod = null;
EntityAttributeModifier lastMultBaseMod = null;
EntityAttributeModifier lastMultTotalMod = null;
int addCount = 0;
int multBaseCount = 0;
int multTotalCount = 0;
double add = 0;
double multBase = 1;
double multTotal = 1;
for (EntityAttributeModifier mod : modifiers) {
double amount = mod.getAmount();
if (amount == 0) continue;
switch (mod.getOperation()) {
case ADDITION:
lastAddMod = mod;
addCount++;
add += amount;
break;
case MULTIPLY_BASE:
lastMultBaseMod = mod;
multBaseCount++;
multBase += amount;
break;
case MULTIPLY_TOTAL:
lastMultTotalMod = mod;
multTotalCount++;
multTotal *= 1 + amount;
break;
default:
break;
}
}
if (addCount == 1) {
ret.put(key, lastAddMod);
} else if (addCount > 0) {
ret.put(key, new EntityAttributeModifier("merged add", add, EntityAttributeModifier.Operation.ADDITION));
}
if (multBaseCount == 1) {
ret.put(key, lastMultBaseMod);
} else if (multBaseCount > 0) {
ret.put(key, new EntityAttributeModifier("merged multiply-base", multBase, EntityAttributeModifier.Operation.MULTIPLY_BASE));
}
if (multTotalCount == 1) {
ret.put(key, lastMultTotalMod);
} else if (multTotalCount > 0) {
ret.put(key, new EntityAttributeModifier("merged multiply-total", multTotal, EntityAttributeModifier.Operation.MULTIPLY_TOTAL));
}
}
}
return ret;
}
}

View file

@ -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]);
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.EntityAttribute;
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<Boolean> 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 = "getMiningSpeedMultiplier", cancellable = true)
public void getMiningSpeedMultiplier(BlockState state, CallbackInfoReturnable<Float> 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<Multimap<EntityAttribute, EntityAttributeModifier>> info, Multimap<EntityAttribute, EntityAttributeModifier> multimap) {
ItemStack stack = (ItemStack) (Object) this;
if (stack.getItem() instanceof DynamicAttributeTool) {
DynamicAttributeTool holder = (DynamicAttributeTool) stack.getItem();
Multimap<EntityAttribute, EntityAttributeModifier> ret = AttributeManager.mergeAttributes(multimap, (holder).getDynamicModifiers(slot, stack, null));
info.setReturnValue(ret);
}
}
}

View file

@ -0,0 +1,61 @@
/*
* 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.EntityAttribute;
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<EntityAttribute, EntityAttributeModifier> actTickModifiers(ItemStack stack, EquipmentSlot slot) {
return actModifiers(stack, slot, (LivingEntity) (Object) this);
}
private static Multimap<EntityAttribute, EntityAttributeModifier> actModifiers(ItemStack stack, EquipmentSlot slot, LivingEntity user) {
Multimap<EntityAttribute, EntityAttributeModifier> 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;
}
}

View file

@ -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.collection.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<ItemStack> main;
@Shadow
public int selectedSlot;
@Shadow
@Final
public PlayerEntity player;
@Shadow
public abstract ItemStack getStack(int int_1);
@Inject(method = "isUsingEffectiveTool", at = @At("HEAD"), cancellable = true)
public void actMiningLevel(BlockState state, CallbackInfoReturnable<Boolean> info) {
ItemStack stack = this.getStack(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"), cancellable = true)
public void actMiningSleed(BlockState state, CallbackInfoReturnable<Float> info) {
ItemStack stack = this.main.get(this.selectedSlot);
if (stack.getItem() instanceof DynamicAttributeTool) {
info.setReturnValue(((DynamicAttributeTool) stack.getItem()).getMiningSpeedMultiplier(stack, player));
}
}
}

View file

@ -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().getMiningSpeedMultiplier();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:shears"
]
}

View file

@ -0,0 +1,14 @@
{
"required": true,
"package": "net.fabricmc.fabric.mixin.tool.attribute",
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinItemStack",
"MixinLivingEntity",
"MixinPlayerInventory",
"MixinToolItem"
],
"injectors": {
"defaultRequire": 1
}
}

View file

@ -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"
]
}

View file

@ -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'