tool attribute 1.1 (#589)

* Actual support

* Remove this useless mixin

* Resolve some issues

* Remove duplicate entries

* maybe?

* fix max breaking speed

* choose an item that is the closest

* Set version to 1.1

* better docs remove stuff

* deprecation doc and no todo comments

* Check if block has valid mining level

* javadocs

* Most of the issues resolved

* Some more javadoc and resolve some issues

* Forgot to change order for these

* Adds post process method to DynamicAttributeTool
Fixed going to vanilla again to query
Fixed tool mining level < 0
Fixed vanilla items on modded blocks not working
Renamed taggedToolHandlerInvoker to toolHandlerInvoker
Renamed entries to ENTRIES

* New comparision method for modded tools to vanilla blocks

* Remove useless mixins and use getMaterial().getMiningSpeed to support more tools.

* Simply mixin

* Some useful javadocs

* Fix license

* Bump fabric-object-builders-v0 because we are good

* Bump version of fabric-object-builder-api-v1 because we are nice

* Resolve some issues

* a

* remove vanilla tools vanilla blocks thing ok

* descriptive

* Get the faster speed instead

* Rename ModdedToolsVanillaBlocksToolHandler

* Remove tri state

* Fix compile errors

* testmod

* fix formatting

* fix testmod javadoc

* forgot to license format testmod

* Bump to 1.1.0
# Conflicts:
#	fabric-object-builder-api-v1/build.gradle
#	fabric-tool-attribute-api-v1/build.gradle
#	fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/api/tool/attribute/v1/DynamicAttributeTool.java
#	fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinItemStack.java
#	fabric-tool-attribute-api-v1/src/main/java/net/fabricmc/fabric/mixin/tool/attribute/MixinPlayerInventory.java
This commit is contained in:
modmuss50 2020-05-11 22:12:43 +01:00
parent fbdec5486a
commit c8964fcb8d
26 changed files with 968 additions and 231 deletions

View file

@ -1,5 +1,5 @@
archivesBaseName = "fabric-object-builder-api-v1"
version = getSubprojectVersion(project, "1.2.0")
version = getSubprojectVersion(project, "1.3.0")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')

View file

@ -261,16 +261,27 @@ public class FabricBlockSettings extends AbstractBlock.Settings {
/* FABRIC HELPERS */
/**
* Makes the block breakable by any tool if {@code breakByHand} is set to true.
*/
public FabricBlockSettings breakByHand(boolean breakByHand) {
FabricBlockInternals.computeExtraData(this).breakByHand(breakByHand);
return this;
}
/**
* Please make the material require a tool if you plan to disable drops and slow the breaking down using the
* incorrect tool by using {@link FabricMaterialBuilder#requiresTool()}.
*/
public FabricBlockSettings breakByTool(Tag<Item> tag, int miningLevel) {
FabricBlockInternals.computeExtraData(this).addMiningLevel(tag, miningLevel);
return this;
}
/**
* Please make the material require a tool if you plan to disable drops and slow the breaking down using the
* incorrect tool by using {@link FabricMaterialBuilder#requiresTool()}.
*/
public FabricBlockSettings breakByTool(Tag<Item> tag) {
return this.breakByTool(tag, 0);
}

View file

@ -84,6 +84,9 @@ public class FabricMaterialBuilder extends Material.Builder {
return this;
}
/**
* Make the material require tool to drop and slows down mining speed if the incorrect tool is used.
*/
@Override
public FabricMaterialBuilder requiresTool() {
super.requiresTool();

View file

@ -23,7 +23,7 @@ import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.tag.Tag;
import net.fabricmc.fabric.impl.tool.attribute.ToolManager;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
public final class FabricBlockInternals {
private FabricBlockInternals() {
@ -45,11 +45,11 @@ public final class FabricBlockInternals {
if (data != null) {
if (data.breakByHand != null) {
ToolManager.entry(block).setBreakByHand(data.breakByHand);
ToolManagerImpl.entry(block).setBreakByHand(data.breakByHand);
}
for (MiningLevel tml : data.miningLevels) {
ToolManager.entry(block).putBreakByTool(tml.tag, tml.level);
ToolManagerImpl.entry(block).putBreakByTool(tml.tag, tml.level);
}
}
}

View file

@ -68,16 +68,27 @@ public class FabricBlockSettings {
/* FABRIC HELPERS */
/**
* Makes the block breakable by any tool if {@code breakByHand} is set to true.
*/
public FabricBlockSettings breakByHand(boolean breakByHand) {
this.delegate.breakByHand(breakByHand);
return this;
}
/**
* Please make the material require a tool if you plan to disable drops and slow the breaking down using the
* incorrect tool by using {@link net.fabricmc.fabric.api.object.builder.v1.block.FabricMaterialBuilder#requiresTool()}.
*/
public FabricBlockSettings breakByTool(Tag<Item> tag, int miningLevel) {
this.delegate.breakByTool(tag, miningLevel);
return this;
}
/**
* Please make the material require a tool if you plan to disable drops and slow the breaking down using the
* incorrect tool by using {@link net.fabricmc.fabric.api.object.builder.v1.block.FabricMaterialBuilder#requiresTool()}.
*/
public FabricBlockSettings breakByTool(Tag<Item> tag) {
this.delegate.breakByTool(tag);
return this;

View file

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

View file

@ -19,11 +19,14 @@ package net.fabricmc.fabric.api.tool.attribute.v1;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import net.minecraft.block.BlockState;
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.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tag.Tag;
/**
* Interface for adding various tool attributes to items.
@ -34,22 +37,74 @@ public interface DynamicAttributeTool {
/**
* 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.
* @param stack The item stack being used to mine the block
* @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.
* @deprecated Use {@link #getMiningLevel(Tag, BlockState, ItemStack, LivingEntity)} to detect tag and block.
*/
// nullable on user once we have an official @Nullable annotation in
@Deprecated
default int getMiningLevel(ItemStack stack, /* @Nullable */ LivingEntity user) {
return 0;
}
/**
* Determines the mining level of the passed stack, which is used for calculating what blocks this tool is allowed to break.
*
* @param tag The tool tag the item stack is being compared to
* @param state The block to mine
* @param stack The item stack being used to mine the block
* @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);
// nullable on user once we have an official @Nullable annotation in
default int getMiningLevel(Tag<Item> tag, BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return getMiningLevel(stack, 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.
* @param stack The item stack being used to mine the block
* @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.
* @deprecated Use {@link #getMiningLevel(Tag, BlockState, ItemStack, LivingEntity)} to detect tag and block.
*/
// nullable on user once we have an official @Nullable annotation in
@Deprecated
default float getMiningSpeedMultiplier(ItemStack stack, /* @Nullable */ LivingEntity user) {
return 1.0F;
}
/**
* Determines the mining speed multiplier of the passed stack, which is one factor in overall mining speed.
*
* @param tag The tool tag the item stack is being compared to
* @param state The block to mine
* @param stack The item stack being used to mine the block
* @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);
// nullable on user once we have an official @Nullable annotation in
default float getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return getMiningSpeedMultiplier(stack, user);
}
/**
* Post process the mining speed, can be used to change tool speed regardless if the tool is effective.
* Useful if you want to change the mining speed even if it is not effective.
*
* @param tag The tool tag the item stack is handled by
* @param state The block to mine
* @param stack The item stack being used to mine the block
* @param user The current user of the tool, or null if there isn't any
* @param currentSpeed The mining speed before post process
* @param isEffective whether the tool has been handled
* @return the speed after post processing
*/
default float postProcessMiningSpeed(Tag<Item> tag, BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user, float currentSpeed, boolean isEffective) {
return currentSpeed;
}
/**
* Add modifiers for any {@link net.minecraft.entity.attribute.EntityAttributes} your item should give when equipped, based on the stack.
@ -58,11 +113,11 @@ public interface DynamicAttributeTool {
*
* @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
* @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) {
// nullable on user once we have an official @Nullable annotation in
default Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, /* @Nullable */ LivingEntity user) {
return EMPTY;
}
}

View file

@ -0,0 +1,80 @@
/*
* 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.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
/**
* API facing part to register tool handlers and get information about how tools are handled.
* Implement {@link DynamicAttributeTool} to change the mining level or speed of your tool depending on the {@link ItemStack}.
*/
public final class ToolManager {
/**
* Handles if the tool is effective on a block.
*
* @param state the block state to break
* @param stack the item stack involved with breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return whether the tool is effective
*/
public static boolean handleIsEffectiveOn(BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return stack.isEffectiveOn(state) || handleIsEffectiveOnIgnoresVanilla(state, stack, user);
}
/**
* Handles if the tool is effective on a block, ignores vanilla tools on vanilla blocks.
*
* @param state the block state to break
* @param stack the item stack involved with breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return whether the tool is effective
*/
public static boolean handleIsEffectiveOnIgnoresVanilla(BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return ToolManagerImpl.handleIsEffectiveOnIgnoresVanilla(state, stack, user);
}
/**
* Handles the breaking speed breaking a block.
*
* @param state the block state to break
* @param stack the item stack involved with breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return the speed multiplier in breaking the block, 1.0 if no change.
*/
public static float handleBreakingSpeed(BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return Math.max(stack.getMiningSpeedMultiplier(state), handleBreakingSpeedIgnoresVanilla(state, stack, user));
}
/**
* Handles the breaking speed breaking a block, ignores vanilla tools on vanilla blocks.
*
* @param state the block state to break
* @param stack the item stack involved with breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return the speed multiplier in breaking the block, 1.0 if no change.
*/
public static float handleBreakingSpeedIgnoresVanilla(BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return ToolManagerImpl.handleBreakingSpeedIgnoresVanilla(state, stack, user);
}
private ToolManager() {
}
}

View file

@ -0,0 +1,80 @@
/*
* 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.Arrays;
import net.minecraft.item.Items;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.fabricmc.fabric.impl.tool.attribute.handlers.ModdedToolsVanillaBlocksToolHandler;
import net.fabricmc.fabric.impl.tool.attribute.handlers.ModdedToolsModdedBlocksToolHandler;
import net.fabricmc.fabric.impl.tool.attribute.handlers.ShearsVanillaBlocksToolHandler;
import net.fabricmc.fabric.impl.tool.attribute.handlers.VanillaToolsModdedBlocksToolHandler;
/**
* Entrypoint to register the default tool handlers.
*/
public class ToolHandlers implements ModInitializer {
@Override
public void onInitialize() {
ToolManagerImpl.general().register(new ModdedToolsModdedBlocksToolHandler());
ToolManagerImpl.general().register(new VanillaToolsModdedBlocksToolHandler());
ToolManagerImpl.tag(FabricToolTags.PICKAXES).register(new ModdedToolsVanillaBlocksToolHandler(
Arrays.asList(
Items.WOODEN_PICKAXE,
Items.STONE_PICKAXE,
Items.IRON_PICKAXE,
Items.DIAMOND_PICKAXE
)
));
ToolManagerImpl.tag(FabricToolTags.AXES).register(new ModdedToolsVanillaBlocksToolHandler(
Arrays.asList(
Items.WOODEN_AXE,
Items.STONE_AXE,
Items.IRON_AXE,
Items.DIAMOND_AXE
)
));
ToolManagerImpl.tag(FabricToolTags.SHOVELS).register(new ModdedToolsVanillaBlocksToolHandler(
Arrays.asList(
Items.WOODEN_SHOVEL,
Items.STONE_SHOVEL,
Items.IRON_SHOVEL,
Items.DIAMOND_SHOVEL
)
));
ToolManagerImpl.tag(FabricToolTags.HOES).register(new ModdedToolsVanillaBlocksToolHandler(
Arrays.asList(
Items.WOODEN_HOE,
Items.STONE_HOE,
Items.IRON_HOE,
Items.DIAMOND_HOE
)
));
ToolManagerImpl.tag(FabricToolTags.SWORDS).register(new ModdedToolsVanillaBlocksToolHandler(
Arrays.asList(
Items.WOODEN_SWORD,
Items.STONE_SWORD,
Items.IRON_SWORD,
Items.DIAMOND_SWORD
)
));
ToolManagerImpl.tag(FabricToolTags.SHEARS).register(new ShearsVanillaBlocksToolHandler());
}
}

View file

@ -1,119 +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.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.tag.Tag;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.api.util.TriState;
public final class ToolManager {
public interface Entry {
void setBreakByHand(boolean value);
void putBreakByTool(Tag<Item> tag, int miningLevel);
}
private static class EntryImpl implements Entry {
@SuppressWarnings("unchecked")
private Tag<Item>[] tags = new Tag[0];
private int[] tagLevels = new int[0];
private TriState defaultValue = TriState.DEFAULT;
@Override
public void setBreakByHand(boolean value) {
this.defaultValue = TriState.of(value);
}
@Override
public void putBreakByTool(Tag<Item> tag, int miningLevel) {
for (int i = 0; i < tags.length; i++) {
if (tags[i] == tag) {
tagLevels[i] = miningLevel;
return;
}
}
//noinspection unchecked
Tag<Item>[] newTags = new Tag[tags.length + 1];
int[] newTagLevels = new int[tagLevels.length + 1];
System.arraycopy(tags, 0, newTags, 0, tags.length);
System.arraycopy(tagLevels, 0, newTagLevels, 0, tagLevels.length);
newTags[tags.length] = tag;
newTagLevels[tagLevels.length] = miningLevel;
tags = newTags;
tagLevels = newTagLevels;
}
}
private static final Map<Block, EntryImpl> entries = new HashMap<>();
private ToolManager() { }
public static Entry entry(Block block) {
return entries.computeIfAbsent(block, (bb) -> new EntryImpl());
}
@Deprecated
public static void registerBreakByHand(Block block, boolean value) {
entry(block).setBreakByHand(value);
}
@Deprecated
public static void registerBreakByTool(Block block, Tag<Item> tag, int miningLevel) {
entry(block).putBreakByTool(tag, miningLevel);
}
//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;
}
}
/**
* Hook for ItemStack.isEffectiveOn and similar methods.
*/
//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) {
Item item = stack.getItem();
for (int i = 0; i < entry.tags.length; i++) {
if (item.isIn(entry.tags[i])) {
return TriState.of(getMiningLevel(stack, user) >= entry.tagLevels[i]);
}
}
return entry.defaultValue;
} else {
return TriState.DEFAULT;
}
}
}

View file

@ -0,0 +1,267 @@
/*
* 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.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
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.tag.Tag;
import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.api.util.TriState;
public final class ToolManagerImpl {
public interface Entry {
void setBreakByHand(boolean value);
void putBreakByTool(Tag<Item> tag, int miningLevel);
int getMiningLevel(Tag<Item> tag);
}
private static class EntryImpl implements Entry {
private Tag<Item>[] tags = new Tag[0];
private int[] tagLevels = new int[0];
private TriState defaultValue = TriState.DEFAULT;
@Override
public void setBreakByHand(boolean value) {
this.defaultValue = TriState.of(value);
}
@Override
public void putBreakByTool(Tag<Item> tag, int miningLevel) {
tag(tag); // Generate tag entry
for (int i = 0; i < tags.length; i++) {
if (tags[i] == tag) {
tagLevels[i] = miningLevel;
return;
}
}
tags = Arrays.copyOf(tags, tags.length + 1);
tags[tags.length - 1] = tag;
tagLevels = Arrays.copyOf(tagLevels, tagLevels.length + 1);
tagLevels[tagLevels.length - 1] = miningLevel;
}
@Override
public int getMiningLevel(Tag<Item> tag) {
for (int i = 0; i < tags.length; i++) {
if (tags[i] == tag) {
return tagLevels[i];
}
}
return -1;
}
}
private static final Map<Tag<Item>, Event<ToolHandler>> HANDLER_MAP = new HashMap<>();
private static final Event<ToolHandler> GENERAL_TOOLS_HANDLER = EventFactory.createArrayBacked(ToolHandler.class, ToolManagerImpl::toolHandlerInvoker);
private static final Map<Block, EntryImpl> ENTRIES = new IdentityHashMap<>();
/**
* Returns a event for the tag provided, creates a new event if it does not exist.
*
* @param tag the tag provided for the tool
* @return the event callback.
*/
public static Event<ToolHandler> tag(Tag<Item> tag) {
for (Map.Entry<Tag<Item>, Event<ToolHandler>> entry : HANDLER_MAP.entrySet()) {
if ((tag instanceof Tag.Identified ? (((Tag.Identified<Item>) entry.getKey()).getId().equals(((Tag.Identified<Item>) tag).getId())) : entry.getKey().equals(tag))) {
return entry.getValue();
}
}
HANDLER_MAP.put(tag, EventFactory.createArrayBacked(ToolHandler.class, ToolManagerImpl::toolHandlerInvoker));
return HANDLER_MAP.get(tag);
}
/**
* Returns a event used for every tag registered.
*
* @return the event callback.
*/
public static Event<ToolHandler> general() {
return GENERAL_TOOLS_HANDLER;
}
private static ToolHandler toolHandlerInvoker(ToolHandler[] toolHandlers) {
return new ToolHandler() {
@Override
public ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
for (ToolHandler toolHandler : toolHandlers) {
ActionResult effectiveOn = Objects.requireNonNull(toolHandler.isEffectiveOn(tag, state, stack, user));
if (effectiveOn != ActionResult.PASS) {
return effectiveOn;
}
}
return ActionResult.PASS;
}
@Override
public TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
for (ToolHandler toolHandler : toolHandlers) {
TypedActionResult<Float> miningSpeedMultiplier = Objects.requireNonNull(toolHandler.getMiningSpeedMultiplier(tag, state, stack, user));
if (miningSpeedMultiplier.getResult() != ActionResult.PASS) {
return miningSpeedMultiplier;
}
}
return TypedActionResult.pass(1f);
}
};
}
public static Entry entry(Block block) {
return ENTRIES.computeIfAbsent(block, (bb) -> new EntryImpl());
}
public static Entry entryNullable(Block block) {
return ENTRIES.get(block);
}
@Deprecated
public static void registerBreakByHand(Block block, boolean value) {
entry(block).setBreakByHand(value);
}
@Deprecated
public static void registerBreakByTool(Block block, Tag<Item> tag, int miningLevel) {
entry(block).putBreakByTool(tag, miningLevel);
}
/**
* Hook for ItemStack.isEffectiveOn and similar methods.
*/
//TODO: nullable on user once we have an official @Nullable annotation in
public static boolean handleIsEffectiveOnIgnoresVanilla(BlockState state, ItemStack stack, LivingEntity user) {
for (Map.Entry<Tag<Item>, Event<ToolHandler>> eventEntry : HANDLER_MAP.entrySet()) {
if (stack.getItem().isIn(eventEntry.getKey())) {
ActionResult effective = eventEntry.getValue().invoker().isEffectiveOn(eventEntry.getKey(), state, stack, user);
if (effective.isAccepted()) return true;
effective = general().invoker().isEffectiveOn(eventEntry.getKey(), state, stack, user);
if (effective.isAccepted()) return true;
}
}
EntryImpl entry = (EntryImpl) entryNullable(state.getBlock());
return entry != null && entry.defaultValue.get();
}
public static float handleBreakingSpeedIgnoresVanilla(BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
float breakingSpeed = 0f;
Tag<Item> handledTag = null;
boolean handled = false;
for (Map.Entry<Tag<Item>, Event<ToolHandler>> eventEntry : HANDLER_MAP.entrySet()) {
if (stack.getItem().isIn(eventEntry.getKey())) {
ActionResult effective = eventEntry.getValue().invoker().isEffectiveOn(eventEntry.getKey(), state, stack, user);
if (effective.isAccepted()) {
TypedActionResult<Float> speedMultiplier = Objects.requireNonNull(eventEntry.getValue().invoker().getMiningSpeedMultiplier(eventEntry.getKey(), state, stack, user));
if (speedMultiplier.getResult().isAccepted()) {
handled = true;
if (speedMultiplier.getValue() > breakingSpeed) {
breakingSpeed = speedMultiplier.getValue();
handledTag = eventEntry.getKey();
}
}
}
effective = general().invoker().isEffectiveOn(eventEntry.getKey(), state, stack, user);
if (effective.isAccepted()) {
TypedActionResult<Float> speedMultiplier = Objects.requireNonNull(general().invoker().getMiningSpeedMultiplier(eventEntry.getKey(), state, stack, user));
if (speedMultiplier.getResult().isAccepted()) {
handled = true;
if (speedMultiplier.getValue() > breakingSpeed) {
breakingSpeed = speedMultiplier.getValue();
handledTag = eventEntry.getKey();
}
}
}
}
}
// Give it a default speed if it is not handled.
breakingSpeed = handled ? breakingSpeed : 1f;
if (stack.getItem() instanceof DynamicAttributeTool) {
breakingSpeed = ((DynamicAttributeTool) stack.getItem()).postProcessMiningSpeed(handledTag, state, stack, user, breakingSpeed, handled);
}
return breakingSpeed;
}
/**
* The handler to handle tool speed and effectiveness.
*
* @see net.fabricmc.fabric.impl.tool.attribute.ToolHandlers for default handlers.
*/
public interface ToolHandler {
/**
* Determines whether this handler is active and effective of the tools.
*
* @param tag the tag involved
* @param state the block state to break
* @param stack the item stack breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return the result of effectiveness
*/
default ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, /* @Nullable */ LivingEntity user) {
return ActionResult.PASS;
}
/**
* Determines the mining speed multiplier of the tools.
*
* @param tag the tag involved
* @param state the block state to break
* @param stack the item stack breaking the block
* @param user the user involved in breaking the block, null if not applicable.
* @return the result of mining speed.
*/
default TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
return null;
}
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.handlers;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tag.Tag;
import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
/**
* This handler handles items that are an subclass of {@link DynamicAttributeTool} by comparing their mining level
* using {@link DynamicAttributeTool#getMiningLevel(Tag, BlockState, ItemStack, LivingEntity)} and the block mining level.
*
* <p>Only applicable to modded blocks that are registered, as only they have the registered required mining level.</p>
*/
public class ModdedToolsModdedBlocksToolHandler implements ToolManagerImpl.ToolHandler {
@Override
public ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (stack.getItem() instanceof DynamicAttributeTool) {
ToolManagerImpl.Entry entry = ToolManagerImpl.entryNullable(state.getBlock());
if (entry != null) {
int miningLevel = ((DynamicAttributeTool) stack.getItem()).getMiningLevel(tag, state, stack, user);
int requiredMiningLevel = entry.getMiningLevel(tag);
return requiredMiningLevel >= 0 && miningLevel >= 0 && miningLevel >= requiredMiningLevel ? ActionResult.SUCCESS : ActionResult.PASS;
}
}
return ActionResult.PASS;
}
@Override
public TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (stack.getItem() instanceof DynamicAttributeTool) {
float multiplier = ((DynamicAttributeTool) stack.getItem()).getMiningSpeedMultiplier(tag, state, stack, user);
if (multiplier != 1.0F) return TypedActionResult.success(multiplier);
}
return TypedActionResult.pass(1.0F);
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.handlers;
import java.util.List;
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.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
/**
* This handler handles items that are a subclass of {@link DynamicAttributeTool} by using the
* vanilla {@link Item#isEffectiveOn(BlockState)} with a custom fake tool material to use the mining level
* from {@link DynamicAttributeTool#getMiningLevel(Tag, BlockState, ItemStack, LivingEntity)}.
*
* <p>Only applicable to blocks that are vanilla or share the material that is handled by their vanilla tool.</p>
*/
public class ModdedToolsVanillaBlocksToolHandler implements ToolManagerImpl.ToolHandler {
private final List<Item> vanillaItems;
public ModdedToolsVanillaBlocksToolHandler(List<Item> vanillaItems) {
this.vanillaItems = vanillaItems;
}
private ToolItem getVanillaItem(int miningLevel) {
if (miningLevel < 0) return (ToolItem) vanillaItems.get(0);
if (miningLevel >= vanillaItems.size()) return (ToolItem) vanillaItems.get(vanillaItems.size() - 1);
return (ToolItem) vanillaItems.get(miningLevel);
}
@Override
public ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (stack.getItem() instanceof DynamicAttributeTool) {
if (ToolManagerImpl.entryNullable(state.getBlock()) != null) {
// Block is a modded block, and we should ignore it
return ActionResult.PASS;
}
// Gets the mining level from our modded tool
int miningLevel = ((DynamicAttributeTool) stack.getItem()).getMiningLevel(tag, state, stack, user);
if (miningLevel < 0) return ActionResult.PASS;
ToolItem vanillaItem = getVanillaItem(miningLevel);
boolean effective = vanillaItem.isEffectiveOn(state) || vanillaItem.getMiningSpeedMultiplier(new ItemStack(vanillaItem), state) != 1.0F;
return effective ? ActionResult.SUCCESS : ActionResult.PASS;
}
return ActionResult.PASS;
}
@Override
public TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (stack.getItem() instanceof DynamicAttributeTool) {
// Gets the mining level from our modded tool
int miningLevel = ((DynamicAttributeTool) stack.getItem()).getMiningLevel(tag, state, stack, user);
if (miningLevel < 0) return null;
float moddedToolSpeed = ((DynamicAttributeTool) stack.getItem()).getMiningSpeedMultiplier(tag, state, stack, user);
ToolItem firstVanillaItem = getVanillaItem(miningLevel);
ToolItem secondVanillaItem = getVanillaItem(miningLevel + 1 >= vanillaItems.size() ? vanillaItems.size() - 2 : miningLevel + 1);
float firstSpeed = firstVanillaItem.getMiningSpeedMultiplier(new ItemStack(firstVanillaItem, 1), state);
float secondSpeed = secondVanillaItem.getMiningSpeedMultiplier(new ItemStack(secondVanillaItem, 1), state);
boolean hasForcedSpeed = firstSpeed == secondSpeed && firstSpeed >= 1.0F;
// Has forced speed, which as actions like swords breaking cobwebs.
if (hasForcedSpeed) {
return secondSpeed != 1.0F ? TypedActionResult.success(secondSpeed) : TypedActionResult.pass(1.0F);
}
// We adjust the mining speed according to the ratio for the closest tool.
float adjustedMiningSpeed = firstSpeed / firstVanillaItem.getMaterial().getMiningSpeedMultiplier() * moddedToolSpeed;
return adjustedMiningSpeed != 1.0F ? TypedActionResult.success(adjustedMiningSpeed) : TypedActionResult.pass(1.0F);
}
return TypedActionResult.pass(1.0F);
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.handlers;
import net.minecraft.block.BlockState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.ShearsItem;
import net.minecraft.tag.Tag;
import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
/**
* This handler handles items that are registered in the {@link FabricToolTags#SHEARS} by using the
* vanilla {@link Item#isEffectiveOn(BlockState)} using the vanilla shears or the item itself if the item
* is a subclass of {@link ShearsItem}.
*
* <p>Only applicable to items that are not a subclass of {@link DynamicAttributeTool}</p>
* <p>Only applicable to blocks that are vanilla or share the material that is handled by their vanilla tool.</p>
*/
public class ShearsVanillaBlocksToolHandler implements ToolManagerImpl.ToolHandler {
private final Item vanillaItem = Items.SHEARS;
@Override
public ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (ToolManagerImpl.entryNullable(state.getBlock()) != null) {
// Block is a modded block, and we should ignore it
return ActionResult.PASS;
}
if (!(stack.getItem() instanceof DynamicAttributeTool)) {
if (!(stack.getItem() instanceof ShearsItem)) {
return vanillaItem.isEffectiveOn(state) || vanillaItem.getMiningSpeedMultiplier(new ItemStack(vanillaItem), state) != 1.0F ? ActionResult.SUCCESS : ActionResult.PASS;
} else {
return stack.getItem().isEffectiveOn(state) || stack.getItem().getMiningSpeedMultiplier(stack, state) != 1.0F ? ActionResult.SUCCESS : ActionResult.PASS;
}
}
return ActionResult.PASS;
}
@Override
public TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
float speed = 1.0F;
if (!(stack.getItem() instanceof DynamicAttributeTool)) {
if (!(stack.getItem() instanceof ShearsItem)) {
speed = vanillaItem.getMiningSpeedMultiplier(new ItemStack(vanillaItem), state);
} else {
speed = stack.getItem().getMiningSpeedMultiplier(stack, state);
}
}
return speed != 1.0F ? TypedActionResult.success(speed) : TypedActionResult.pass(1.0F);
}
}

View file

@ -0,0 +1,63 @@
/*
* 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.handlers;
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.item.ToolMaterial;
import net.minecraft.tag.Tag;
import net.minecraft.util.ActionResult;
import net.minecraft.util.TypedActionResult;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.impl.tool.attribute.ToolManagerImpl;
/**
* This handler handles items that are not a subclass of {@link DynamicAttributeTool} by
* comparing their mining level using {@link ToolMaterial#getMiningLevel()} and the block mining level.
*
* <p>Only applicable to modded blocks that are registered, as only they have the registered required mining level.</p>
*/
public class VanillaToolsModdedBlocksToolHandler implements ToolManagerImpl.ToolHandler {
@Override
public ActionResult isEffectiveOn(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (!(stack.getItem() instanceof DynamicAttributeTool)) {
ToolManagerImpl.Entry entry = ToolManagerImpl.entryNullable(state.getBlock());
if (entry != null) {
int miningLevel = stack.getItem() instanceof ToolItem ? ((ToolItem) stack.getItem()).getMaterial().getMiningLevel() : -1;
int requiredMiningLevel = entry.getMiningLevel(tag);
return requiredMiningLevel >= 0 && miningLevel >= 0 && miningLevel >= requiredMiningLevel ? ActionResult.SUCCESS : ActionResult.PASS;
}
}
return ActionResult.PASS;
}
@Override
public TypedActionResult<Float> getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (!(stack.getItem() instanceof DynamicAttributeTool)) {
float multiplier = stack.getItem() instanceof ToolItem ? ((ToolItem) stack.getItem()).getMaterial().getMiningSpeedMultiplier() : stack.getItem().getMiningSpeedMultiplier(stack, state);
if (multiplier != 1.0F) return TypedActionResult.success(multiplier);
}
return TypedActionResult.pass(1.0F);
}
}

View file

@ -32,40 +32,27 @@ 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.api.tool.attribute.v1.ToolManager;
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)
@Inject(at = @At("RETURN"), 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();
if (!info.getReturnValueZ()) {
info.setReturnValue(ToolManager.handleIsEffectiveOnIgnoresVanilla(state, (ItemStack) (Object) this, null));
}
}
@Inject(at = @At("HEAD"), method = "getMiningSpeedMultiplier", cancellable = true)
@Inject(at = @At("RETURN"), method = "getMiningSpeedMultiplier", cancellable = true)
public void getMiningSpeedMultiplier(BlockState state, CallbackInfoReturnable<Float> info) {
TriState triState = ToolManager.handleIsEffectiveOn((ItemStack) (Object) this, state, null);
float customSpeed = ToolManager.handleBreakingSpeedIgnoresVanilla(state, (ItemStack) (Object) this, 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);
if (info.getReturnValueF() < customSpeed) {
info.setReturnValue(customSpeed);
}
}

View file

@ -1,73 +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.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

@ -4,8 +4,7 @@
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinItemStack",
"MixinLivingEntity",
"MixinPlayerInventory"
"MixinLivingEntity"
],
"injectors": {
"defaultRequire": 1

View file

@ -20,6 +20,11 @@
"fabric-api-base": "*",
"fabric-tag-extensions-v0": "*"
},
"entrypoints": {
"main": [
"net.fabricmc.fabric.impl.tool.attribute.ToolHandlers"
]
},
"description": "Dynamic atttributes for tools.",
"mixins": [
"fabric-tool-attribute-api-v1.mixins.json"

View file

@ -0,0 +1,74 @@
/*
* 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.test.tool.attribute;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.MaterialColor;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricMaterialBuilder;
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
public class ToolAttributeTest implements ModInitializer {
@Override
public void onInitialize() {
// Register a custom shovel that has a mining level of 2 (iron) dynamically.
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "test_shovel"), new TestShovel(new Item.Settings()));
// Register a block that requires a shovel that is as strong or stronger than an iron one.
Block block = Registry.register(Registry.BLOCK, new Identifier("fabric-tool-attribute-api-v1-testmod", "hardened_block"),
new Block(FabricBlockSettings.of(new FabricMaterialBuilder(MaterialColor.SAND).requiresTool().build(), MaterialColor.STONE)
.breakByTool(FabricToolTags.SHOVELS, 2)
.strength(0.6F)
.sounds(BlockSoundGroup.GRAVEL)));
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "hardened_block"), new BlockItem(block, new Item.Settings()));
}
private static class TestShovel extends Item implements DynamicAttributeTool {
private TestShovel(Settings settings) {
super(settings);
}
@Override
public int getMiningLevel(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (tag.equals(FabricToolTags.SHOVELS)) {
return 2;
}
return 0;
}
@Override
public float getMiningSpeedMultiplier(Tag<Item> tag, BlockState state, ItemStack stack, LivingEntity user) {
if (tag.equals(FabricToolTags.SHOVELS)) {
return 10.0F;
}
return 1.0F;
}
}
}

View file

@ -0,0 +1,5 @@
{
"variants": {
"": { "model": "block/gravel" }
}
}

View file

@ -0,0 +1,6 @@
{
"parent": "item/generated",
"textures": {
"layer0": "item/apple"
}
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "fabric-tool-attribute-api-v1-testmod:hardened_block"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"fabric-tool-attribute-api-v1-testmod:test_shovel"
]
}

View file

@ -0,0 +1,16 @@
{
"schemaVersion": 1,
"id": "fabric-tool-attribute-api-v1-testmod",
"name": "Fabric Tool Attribute API (v1) Test Mod",
"version": "1.0.0",
"environment": "*",
"license": "Apache-2.0",
"depends": {
"fabric-tool-attribute-api-v1": "*"
},
"entrypoints": {
"main": [
"net.fabricmc.fabric.test.tool.attribute.ToolAttributeTest"
]
}
}