mirror of
https://github.com/FabricMC/fabric.git
synced 2025-02-16 19:59:56 -05:00
* dynamic tool attributes v2, part 1 * move duck interface to impl package * add licenses * fix mixin build failure on a dedicated server * remove unused shadow of getItem() * add a simple user-context-based attribute tool to the test item suite * add clarifying comments in DynamicAttributeTool jdoc regarding parameter reliability + extended docs on getDynamicModifiers for attribute freshing * player -> user because context is not always a player * add license to TestNullableItem
This commit is contained in:
parent
b90688755c
commit
f5d458fc56
13 changed files with 385 additions and 192 deletions
|
@ -1,9 +1,10 @@
|
|||
archivesBaseName = "fabric-tool-attribute-api-v1"
|
||||
version = getSubprojectVersion(project, "1.2.9")
|
||||
version = getSubprojectVersion(project, "1.2.10")
|
||||
|
||||
dependencies {
|
||||
testmodCompile project(path: ':fabric-object-builder-api-v1', configuration: 'dev')
|
||||
testmodCompile project(path: ':fabric-lifecycle-events-v1', configuration: 'dev')
|
||||
testmodCompile project(path: ':fabric-resource-loader-v0', configuration: 'dev')
|
||||
}
|
||||
|
||||
moduleDependencies(project, [
|
||||
|
|
|
@ -31,6 +31,9 @@ import net.minecraft.tag.Tag;
|
|||
|
||||
/**
|
||||
* Interface for adding various tool attributes to items.
|
||||
*
|
||||
* <p> Functions in this interface will provide user context if it is available.
|
||||
* These context parameters are provided on a best-effort basis, and implementations should not fail hard if they are absent.</p>
|
||||
*/
|
||||
public interface DynamicAttributeTool {
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> EMPTY = ImmutableSetMultimap.of();
|
||||
|
@ -107,11 +110,14 @@ public interface DynamicAttributeTool {
|
|||
/**
|
||||
* Add modifiers for any {@link net.minecraft.entity.attribute.EntityAttributes} your item should give when equipped, based on the stack.
|
||||
*
|
||||
* <p>Appends to either attribute modifier NBT or the result from {@link net.minecraft.item.Item#getAttributeModifiers(EquipmentSlot)}.</p>
|
||||
* <p>Appends to either attribute modifier NBT or the result from {@link net.minecraft.item.Item#getAttributeModifiers(EquipmentSlot)}.
|
||||
* The attributes returned from this method will only be applied to an entity when the {@link ItemStack} providing the attributes is modified, or the player re-selects the stack in their hotbar.
|
||||
* If your attribute relies on data from outside the stack, such as the user's age, you will need to modify the stack in some way to re-assign attributes to the entity.
|
||||
* A fix for this may be provided in the future.</p>
|
||||
*
|
||||
* @param slot The equipment slot this item is equipped in.
|
||||
* @param stack The stack that's equipped.
|
||||
* @param user The current user of the tool, or none if there isn't any
|
||||
* @param user The current user of the tool, if available.
|
||||
* @return The dynamic modifiers to add on top of other modifiers on this stack. If none, return {@link #EMPTY}.
|
||||
*/
|
||||
default Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, @Nullable LivingEntity user) {
|
||||
|
|
|
@ -1,118 +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.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
|
||||
public final class AttributeManager {
|
||||
private AttributeManager() { }
|
||||
|
||||
/**
|
||||
* Merge two multimaps of EntityAttributeModifiers, combining their modifiers to prevent duplicate entries in a tooltip.
|
||||
*
|
||||
* @param left The first of the two multimaps to merge.
|
||||
* @param right The second of the two multimaps to merge.
|
||||
* @return The merged form of the two.
|
||||
*/
|
||||
public static Multimap<EntityAttribute, EntityAttributeModifier> mergeAttributes(Multimap<EntityAttribute, EntityAttributeModifier> left, Multimap<EntityAttribute, EntityAttributeModifier> right) {
|
||||
if (left.isEmpty()) return right;
|
||||
if (right.isEmpty()) return left;
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> ret = HashMultimap.create();
|
||||
Set<EntityAttribute> allKeys = new HashSet<>();
|
||||
allKeys.addAll(left.keySet());
|
||||
allKeys.addAll(right.keySet());
|
||||
|
||||
for (EntityAttribute key : allKeys) {
|
||||
Collection<EntityAttributeModifier> leftModifiers = left.get(key);
|
||||
Collection<EntityAttributeModifier> rightModifiers = right.get(key);
|
||||
|
||||
if (leftModifiers.isEmpty()) {
|
||||
ret.putAll(key, rightModifiers);
|
||||
} else if (rightModifiers.isEmpty()) {
|
||||
ret.putAll(key, leftModifiers);
|
||||
} else {
|
||||
Collection<EntityAttributeModifier> modifiers = new ArrayList<>(leftModifiers.size() + rightModifiers.size());
|
||||
modifiers.addAll(leftModifiers);
|
||||
modifiers.addAll(rightModifiers);
|
||||
|
||||
EntityAttributeModifier lastAddMod = null;
|
||||
EntityAttributeModifier lastMultBaseMod = null;
|
||||
EntityAttributeModifier lastMultTotalMod = null;
|
||||
int addCount = 0;
|
||||
int multBaseCount = 0;
|
||||
int multTotalCount = 0;
|
||||
double add = 0;
|
||||
double multBase = 1;
|
||||
double multTotal = 1;
|
||||
|
||||
for (EntityAttributeModifier mod : modifiers) {
|
||||
double amount = mod.getValue();
|
||||
if (amount == 0) continue;
|
||||
|
||||
switch (mod.getOperation()) {
|
||||
case ADDITION:
|
||||
lastAddMod = mod;
|
||||
addCount++;
|
||||
add += amount;
|
||||
break;
|
||||
case MULTIPLY_BASE:
|
||||
lastMultBaseMod = mod;
|
||||
multBaseCount++;
|
||||
multBase += amount;
|
||||
break;
|
||||
case MULTIPLY_TOTAL:
|
||||
lastMultTotalMod = mod;
|
||||
multTotalCount++;
|
||||
multTotal *= 1 + amount;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addCount == 1) {
|
||||
ret.put(key, lastAddMod);
|
||||
} else if (addCount > 0) {
|
||||
ret.put(key, new EntityAttributeModifier("merged add", add, EntityAttributeModifier.Operation.ADDITION));
|
||||
}
|
||||
|
||||
if (multBaseCount == 1) {
|
||||
ret.put(key, lastMultBaseMod);
|
||||
} else if (multBaseCount > 0) {
|
||||
ret.put(key, new EntityAttributeModifier("merged multiply-base", multBase, EntityAttributeModifier.Operation.MULTIPLY_BASE));
|
||||
}
|
||||
|
||||
if (multTotalCount == 1) {
|
||||
ret.put(key, lastMultTotalMod);
|
||||
} else if (multTotalCount > 0) {
|
||||
ret.put(key, new EntityAttributeModifier("merged multiply-total", multTotal, EntityAttributeModifier.Operation.MULTIPLY_TOTAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
||||
public interface ItemStackContext {
|
||||
void fabricToolAttributes_setContext(@Nullable LivingEntity contextEntity);
|
||||
}
|
|
@ -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.mixin.tool.attribute;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.AttributeContainer;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.impl.tool.attribute.ItemStackContext;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public class LivingEntityMixin {
|
||||
@Nullable
|
||||
@Unique private ItemStack stackContext = null;
|
||||
@Nullable
|
||||
@Unique private EquipmentSlot slotContext = null;
|
||||
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/attribute/AttributeContainer;removeModifiers(Lcom/google/common/collect/Multimap;)V"), method = "method_30129", locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void storeRemoveStackContext(CallbackInfoReturnable<Map> cir, Map map, EquipmentSlot[] var2, int var3, int var4, EquipmentSlot equipmentSlot, ItemStack oldStack, ItemStack newStack) {
|
||||
stackContext = oldStack;
|
||||
slotContext = equipmentSlot;
|
||||
}
|
||||
|
||||
@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/attribute/AttributeContainer;removeModifiers(Lcom/google/common/collect/Multimap;)V"), method = "method_30129")
|
||||
private void setupRemoveModifierContext(AttributeContainer attributeContainer, Multimap<EntityAttribute, EntityAttributeModifier> oldModifiers) {
|
||||
((ItemStackContext) (Object) stackContext).fabricToolAttributes_setContext((LivingEntity) (Object) this);
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers = stackContext.getAttributeModifiers(slotContext);
|
||||
((ItemStackContext) (Object) stackContext).fabricToolAttributes_setContext(null);
|
||||
attributeContainer.removeModifiers(attributeModifiers);
|
||||
}
|
||||
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/attribute/AttributeContainer;addTemporaryModifiers(Lcom/google/common/collect/Multimap;)V"), method = "method_30129", locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void storeAddStackContext(CallbackInfoReturnable<Map> cir, Map map, EquipmentSlot[] var2, int var3, int var4, EquipmentSlot equipmentSlot, ItemStack oldStack, ItemStack newStack) {
|
||||
stackContext = newStack;
|
||||
slotContext = equipmentSlot;
|
||||
}
|
||||
|
||||
@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/attribute/AttributeContainer;addTemporaryModifiers(Lcom/google/common/collect/Multimap;)V"), method = "method_30129")
|
||||
private void setupAddModifierContext(AttributeContainer attributeContainer, Multimap<EntityAttribute, EntityAttributeModifier> oldModifiers) {
|
||||
((ItemStackContext) (Object) stackContext).fabricToolAttributes_setContext((LivingEntity) (Object) this);
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers = stackContext.getAttributeModifiers(slotContext);
|
||||
((ItemStackContext) (Object) stackContext).fabricToolAttributes_setContext(null);
|
||||
attributeContainer.addTemporaryModifiers(attributeModifiers);
|
||||
}
|
||||
}
|
|
@ -16,29 +16,39 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.tool.attribute;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
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.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.ToolManager;
|
||||
import net.fabricmc.fabric.impl.tool.attribute.AttributeManager;
|
||||
import net.fabricmc.fabric.impl.tool.attribute.ItemStackContext;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public abstract class MixinItemStack {
|
||||
@Shadow
|
||||
public abstract Item getItem();
|
||||
public abstract class MixinItemStack implements ItemStackContext {
|
||||
@Unique
|
||||
@Nullable
|
||||
private LivingEntity contextEntity = null;
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "isSuitableFor", cancellable = true)
|
||||
public void isEffectiveOn(BlockState state, CallbackInfoReturnable<Boolean> info) {
|
||||
|
@ -54,14 +64,44 @@ public abstract class MixinItemStack {
|
|||
}
|
||||
}
|
||||
|
||||
// This inject stores context about the player viewing an ItemStack's tooltip before attributes are calculated.
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;"), method = "getTooltip")
|
||||
private void storeTooltipAttributeEntityContext(PlayerEntity player, TooltipContext context, CallbackInfoReturnable<List<Text>> cir) {
|
||||
contextEntity = player;
|
||||
}
|
||||
|
||||
// This inject removes context specified in the previous inject.
|
||||
// This is done to prevent issues with other mods calling getAttributeModifiers.
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;", shift = At.Shift.AFTER), method = "getTooltip")
|
||||
private void revokeTooltipAttributeEntityContext(PlayerEntity player, TooltipContext context, CallbackInfoReturnable<List<Text>> cir) {
|
||||
contextEntity = null;
|
||||
}
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "getAttributeModifiers", cancellable = true, locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
public void getAttributeModifiers(EquipmentSlot slot, CallbackInfoReturnable<Multimap<EntityAttribute, EntityAttributeModifier>> info, Multimap<EntityAttribute, EntityAttributeModifier> multimap) {
|
||||
ItemStack stack = (ItemStack) (Object) this;
|
||||
|
||||
// Only perform our custom operations if the tool being operated on is dynamic.
|
||||
if (stack.getItem() instanceof DynamicAttributeTool) {
|
||||
// The Multimap passed in is not ordered, so we need to re-assemble the vanilla and modded attributes
|
||||
// into a custom, ordered Multimap. If this step is not done, and both vanilla + modded attributes
|
||||
// exist at once, the item tooltip attribute lines will randomly switch positions.
|
||||
LinkedListMultimap<EntityAttribute, EntityAttributeModifier> orderedAttributes = LinkedListMultimap.create();
|
||||
|
||||
// First, add all vanilla attributes to our ordered Multimap.
|
||||
orderedAttributes.putAll(multimap);
|
||||
|
||||
// Second, calculate the dynamic attributes, and add them at the end of our Multimap.
|
||||
DynamicAttributeTool holder = (DynamicAttributeTool) stack.getItem();
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> ret = AttributeManager.mergeAttributes(multimap, (holder).getDynamicModifiers(slot, stack, null));
|
||||
info.setReturnValue(ret);
|
||||
orderedAttributes.putAll(holder.getDynamicModifiers(slot, stack, contextEntity));
|
||||
info.setReturnValue(orderedAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fabricToolAttributes_setContext(@Nullable LivingEntity contextEntity) {
|
||||
this.contextEntity = contextEntity;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +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 com.google.common.collect.Multimap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
import net.fabricmc.fabric.impl.tool.attribute.AttributeManager;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class MixinLivingEntity extends Entity {
|
||||
public MixinLivingEntity(EntityType<?> type, World world) {
|
||||
super(type, world);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author B0undarybreaker
|
||||
* @reason get entity attribute modifiers for dynamic tools
|
||||
*/
|
||||
@Redirect(method = "method_30129", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;"))
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> actTickModifiers(ItemStack stack, EquipmentSlot slot) {
|
||||
return actModifiers(stack, slot, (LivingEntity) (Object) this);
|
||||
}
|
||||
|
||||
private static Multimap<EntityAttribute, EntityAttributeModifier> actModifiers(ItemStack stack, EquipmentSlot slot, LivingEntity user) {
|
||||
Multimap<EntityAttribute, EntityAttributeModifier> original = stack.getAttributeModifiers(slot);
|
||||
|
||||
if (stack.getItem() instanceof DynamicAttributeTool) {
|
||||
DynamicAttributeTool tool = (DynamicAttributeTool) stack.getItem();
|
||||
return (AttributeManager.mergeAttributes(original, tool.getDynamicModifiers(slot, stack, user)));
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@
|
|||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"BambooBlockMixin",
|
||||
"MixinItemStack",
|
||||
"MixinLivingEntity"
|
||||
"LivingEntityMixin",
|
||||
"MixinItemStack"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
|
|
@ -41,6 +41,10 @@ import net.fabricmc.fabric.api.object.builder.v1.block.FabricMaterialBuilder;
|
|||
import net.fabricmc.fabric.api.tag.TagRegistry;
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
|
||||
import net.fabricmc.fabric.test.tool.attribute.item.TestDynamicCancelItem;
|
||||
import net.fabricmc.fabric.test.tool.attribute.item.TestDynamicSwordItem;
|
||||
import net.fabricmc.fabric.test.tool.attribute.item.TestDynamicToolItem;
|
||||
import net.fabricmc.fabric.test.tool.attribute.item.TestNullableItem;
|
||||
|
||||
public class ToolAttributeTest implements ModInitializer {
|
||||
private static final float DEFAULT_BREAK_SPEED = 1.0F;
|
||||
|
@ -101,6 +105,16 @@ public class ToolAttributeTest implements ModInitializer {
|
|||
.sounds(BlockSoundGroup.CROP)));
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "tater_effective_block"), new BlockItem(taterEffectiveBlock, new Item.Settings()));
|
||||
|
||||
// DYNAMIC ATTRIBUTE MODIFIERS
|
||||
// The Dynamic Sword tests to make sure standard vanilla attributes can co-exist with dynamic attributes.
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "dynamic_sword"), new TestDynamicSwordItem(new Item.Settings()));
|
||||
// The Dynamic Tool ensures a tool can have dynamic attributes (with no vanilla atributes). It applies 2 layers of speed reduction to the player.
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "dynamic_tool"), new TestDynamicToolItem(new Item.Settings()));
|
||||
// Test cancels-out attributes
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "cancel_item"), new TestDynamicCancelItem(new Item.Settings()));
|
||||
// Test parameter nullability
|
||||
Registry.register(Registry.ITEM, new Identifier("fabric-tool-attribute-api-v1-testmod", "null_test"), new TestNullableItem(new Item.Settings()));
|
||||
|
||||
ServerTickEvents.START_SERVER_TICK.register(this::validate);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.item;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
|
||||
public class TestDynamicCancelItem extends Item implements DynamicAttributeTool {
|
||||
public static final UUID TEST_UUID = UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF");
|
||||
|
||||
public TestDynamicCancelItem(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, @Nullable LivingEntity user) {
|
||||
if (slot.equals(EquipmentSlot.MAINHAND)) {
|
||||
ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> builder = ImmutableMultimap.builder();
|
||||
builder.put(EntityAttributes.GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(TEST_UUID, "TEST", -1.0, EntityAttributeModifier.Operation.ADDITION));
|
||||
builder.put(EntityAttributes.GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(TEST_UUID, "TEST", 1.0, EntityAttributeModifier.Operation.ADDITION));
|
||||
return builder.build();
|
||||
} else {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.item;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.SwordItem;
|
||||
import net.minecraft.item.ToolMaterials;
|
||||
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
|
||||
public class TestDynamicSwordItem extends SwordItem implements DynamicAttributeTool {
|
||||
public static final UUID TEST_UUID = UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF");
|
||||
|
||||
public TestDynamicSwordItem(Settings settings) {
|
||||
super(ToolMaterials.DIAMOND, 6, -2.4f, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, @Nullable LivingEntity user) {
|
||||
if (slot.equals(EquipmentSlot.MAINHAND)) {
|
||||
ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> builder = ImmutableMultimap.builder();
|
||||
builder.put(EntityAttributes.GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(TEST_UUID, "TEST", 2.0, EntityAttributeModifier.Operation.MULTIPLY_TOTAL));
|
||||
builder.put(EntityAttributes.GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(TEST_UUID, "TEST2", 2.0, EntityAttributeModifier.Operation.MULTIPLY_TOTAL));
|
||||
return builder.build();
|
||||
} else {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.item;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
|
||||
public class TestDynamicToolItem extends Item implements DynamicAttributeTool {
|
||||
public static final UUID TEST_UUID = UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF");
|
||||
|
||||
public TestDynamicToolItem(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, @Nullable LivingEntity user) {
|
||||
if (slot.equals(EquipmentSlot.MAINHAND)) {
|
||||
ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> builder = ImmutableMultimap.builder();
|
||||
builder.put(EntityAttributes.GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(TEST_UUID, "TEST", -1.0, EntityAttributeModifier.Operation.ADDITION));
|
||||
builder.put(EntityAttributes.GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(TEST_UUID, "TEST", -1.0, EntityAttributeModifier.Operation.ADDITION));
|
||||
return builder.build();
|
||||
} else {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.item;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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.entity.attribute.EntityAttributes;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import net.fabricmc.fabric.api.tool.attribute.v1.DynamicAttributeTool;
|
||||
|
||||
public class TestNullableItem extends Item implements DynamicAttributeTool {
|
||||
public static final UUID TEST_UUID = UUID.fromString("CB3F55D3-645C-4F38-A497-9C13A33DB5CF");
|
||||
|
||||
public TestNullableItem(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<EntityAttribute, EntityAttributeModifier> getDynamicModifiers(EquipmentSlot slot, ItemStack stack, @Nullable LivingEntity user) {
|
||||
if (slot.equals(EquipmentSlot.MAINHAND)) {
|
||||
ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> builder = ImmutableMultimap.builder();
|
||||
builder.put(EntityAttributes.GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(TEST_UUID, "Increasing speed", user == null ? 0 : user.age * 0.001, EntityAttributeModifier.Operation.ADDITION));
|
||||
return builder.build();
|
||||
} else {
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue