mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-22 23:58:02 -05:00
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:
parent
fbdec5486a
commit
c8964fcb8d
26 changed files with 968 additions and 231 deletions
|
@ -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')
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,7 @@
|
|||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"MixinItemStack",
|
||||
"MixinLivingEntity",
|
||||
"MixinPlayerInventory"
|
||||
"MixinLivingEntity"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"variants": {
|
||||
"": { "model": "block/gravel" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"parent": "block/gravel"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "item/apple"
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"fabric-tool-attribute-api-v1-testmod:test_shovel"
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue