mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-14 19:25:23 -05:00
Stack aware getFoodComponent
(#3520)
* Stack aware `getFoodComponent`
Co-authored-by: Phoupraw <50520903+phoupraw@users.noreply.github.com>
* Back to redirects
---------
Co-authored-by: Phoupraw <50520903+phoupraw@users.noreply.github.com>
(cherry picked from commit d6f2b0841c
)
This commit is contained in:
parent
92bc82c0df
commit
fd154599a6
17 changed files with 511 additions and 3 deletions
|
@ -17,12 +17,14 @@
|
||||||
package net.fabricmc.fabric.api.item.v1;
|
package net.fabricmc.fabric.api.item.v1;
|
||||||
|
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
import net.minecraft.entity.attribute.EntityAttribute;
|
import net.minecraft.entity.attribute.EntityAttribute;
|
||||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.registry.entry.RegistryEntry;
|
import net.minecraft.registry.entry.RegistryEntry;
|
||||||
|
@ -123,4 +125,15 @@ public interface FabricItem {
|
||||||
default ItemStack getRecipeRemainder(ItemStack stack) {
|
default ItemStack getRecipeRemainder(ItemStack stack) {
|
||||||
return ((Item) this).hasRecipeRemainder() ? ((Item) this).getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY;
|
return ((Item) this).hasRecipeRemainder() ? ((Item) this).getRecipeRemainder().getDefaultStack() : ItemStack.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a stack-aware version of {@link Item#getFoodComponent()}.
|
||||||
|
* Note that simple food component can also be set via {@link Item.Settings#food(FoodComponent)}.
|
||||||
|
* If you want to get a food component for a stack, is <strong>recommended</strong> to use the stack version of this method: {@link FabricItemStack#getFoodComponent()}.
|
||||||
|
*
|
||||||
|
* @return this item's {@link FoodComponent}, or {@code null} if none was set
|
||||||
|
*/
|
||||||
|
default @Nullable FoodComponent getFoodComponent(ItemStack stack) {
|
||||||
|
return ((Item) this).getFoodComponent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package net.fabricmc.fabric.api.item.v1;
|
package net.fabricmc.fabric.api.item.v1;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
@ -36,4 +39,14 @@ public interface FabricItemStack {
|
||||||
default ItemStack getRecipeRemainder() {
|
default ItemStack getRecipeRemainder() {
|
||||||
return ((ItemStack) this).getItem().getRecipeRemainder((ItemStack) this);
|
return ((ItemStack) this).getItem().getRecipeRemainder((ItemStack) this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack-aware version of {@link Item#getFoodComponent()}.
|
||||||
|
* See {@link FabricItem#getFoodComponent(ItemStack)} for a more in depth description.
|
||||||
|
*
|
||||||
|
* @return this item stack's {@link FoodComponent}, or {@code null} if none was set
|
||||||
|
*/
|
||||||
|
default @Nullable FoodComponent getFoodComponent() {
|
||||||
|
return ((ItemStack) this).getItem().getFoodComponent(((ItemStack) this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import net.minecraft.item.BlockItem;
|
||||||
|
import net.minecraft.item.ItemUsageContext;
|
||||||
|
|
||||||
|
@Mixin(BlockItem.class)
|
||||||
|
class BlockItemMixin {
|
||||||
|
@Redirect(method = "useOnBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BlockItem;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(BlockItem instance, ItemUsageContext context) {
|
||||||
|
return context.getStack().isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.fabricmc.fabric.mixin.item;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import net.minecraft.entity.passive.CatEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
|
||||||
|
@Mixin(CatEntity.class)
|
||||||
|
class CatEntityMixin {
|
||||||
|
@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, PlayerEntity player, Hand hand) {
|
||||||
|
return player.getStackInHand(hand).getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, PlayerEntity player, Hand hand) {
|
||||||
|
return player.getStackInHand(hand).isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import net.minecraft.data.server.recipe.CookingRecipeJsonBuilder;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
|
||||||
|
@Mixin(CookingRecipeJsonBuilder.class)
|
||||||
|
class CookingRecipeJsonBuilderMixin {
|
||||||
|
@Redirect(method = "getSmeltingRecipeCategory", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private static boolean isStackAwareFood(Item instance) {
|
||||||
|
return instance.getDefaultStack().isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.entity.passive.AnimalEntity;
|
||||||
|
import net.minecraft.entity.passive.FoxEntity;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
@Mixin(FoxEntity.class)
|
||||||
|
abstract class FoxEntityMixin extends AnimalEntity {
|
||||||
|
protected FoxEntityMixin(EntityType<? extends AnimalEntity> entityType, World world) {
|
||||||
|
super(entityType, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = {"canEat", "canPickupItem"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 0))
|
||||||
|
private boolean isStackAwareFood(Item instance, ItemStack stack) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = {"canPickupItem"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 1))
|
||||||
|
private boolean isEquippedStackAwareFood(Item instance) {
|
||||||
|
return this.getEquippedStack(EquipmentSlot.MAINHAND).isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.HungerManager;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
@Mixin(HungerManager.class)
|
||||||
|
class HungerManagerMixin {
|
||||||
|
@Redirect(method = "eat", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, Item item, ItemStack stack) {
|
||||||
|
return stack.getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "eat", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, Item item, ItemStack stack) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,9 +21,16 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
import net.fabricmc.fabric.api.item.v1.CustomDamageHandler;
|
||||||
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
||||||
|
@ -67,4 +74,29 @@ abstract class ItemMixin implements ItemExtensions, FabricItem {
|
||||||
public void fabric_setCustomDamageHandler(@Nullable CustomDamageHandler handler) {
|
public void fabric_setCustomDamageHandler(@Nullable CustomDamageHandler handler) {
|
||||||
this.customDamageHandler = handler;
|
this.customDamageHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, World world, PlayerEntity user, Hand hand) {
|
||||||
|
return user.getStackInHand(hand).getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "getMaxUseTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack) {
|
||||||
|
return stack.getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = {"getMaxUseTime", "getUseAction"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, ItemStack stack) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "use", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, World world, PlayerEntity user, Hand hand) {
|
||||||
|
return user.getStackInHand(hand).isFood();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "finishUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, ItemStack stack, World world, LivingEntity user) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
|
@ -101,4 +102,9 @@ public abstract class ItemStackMixin implements FabricItemStack {
|
||||||
public boolean hookIsSuitableFor(Item item, BlockState state) {
|
public boolean hookIsSuitableFor(Item item, BlockState state) {
|
||||||
return item.isSuitableFor((ItemStack) (Object) this, state);
|
return item.isSuitableFor((ItemStack) (Object) this, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "isFood", at = @At("HEAD"), cancellable = true)
|
||||||
|
public void isStackAwareFood(CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
cir.setReturnValue(this.getFoodComponent() != null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,29 @@
|
||||||
|
|
||||||
package net.fabricmc.fabric.mixin.item;
|
package net.fabricmc.fabric.mixin.item;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
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.CallbackInfoReturnable;
|
||||||
|
|
||||||
import net.minecraft.entity.EquipmentSlot;
|
import net.minecraft.entity.EquipmentSlot;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
import net.fabricmc.fabric.api.item.v1.EquipmentSlotProvider;
|
||||||
import net.fabricmc.fabric.impl.item.ItemExtensions;
|
import net.fabricmc.fabric.impl.item.ItemExtensions;
|
||||||
|
|
||||||
@Mixin(LivingEntity.class)
|
@Mixin(LivingEntity.class)
|
||||||
abstract class LivingEntityMixin {
|
abstract class LivingEntityMixin {
|
||||||
|
@Shadow
|
||||||
|
protected ItemStack activeItemStack;
|
||||||
|
|
||||||
@Inject(method = "getPreferredEquipmentSlot", at = @At(value = "HEAD"), cancellable = true)
|
@Inject(method = "getPreferredEquipmentSlot", at = @At(value = "HEAD"), cancellable = true)
|
||||||
private static void onGetPreferredEquipmentSlot(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> info) {
|
private static void onGetPreferredEquipmentSlot(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> info) {
|
||||||
EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider();
|
EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider();
|
||||||
|
@ -38,4 +47,19 @@ abstract class LivingEntityMixin {
|
||||||
info.setReturnValue(equipmentSlotProvider.getPreferredEquipmentSlot(stack));
|
info.setReturnValue(equipmentSlotProvider.getPreferredEquipmentSlot(stack));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "shouldSpawnConsumptionEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance) {
|
||||||
|
return this.activeItemStack.getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "applyFoodEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack, World world, LivingEntity targetEntity) {
|
||||||
|
return stack.getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "applyFoodEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z"))
|
||||||
|
private boolean isStackAwareFood(Item instance, ItemStack stack, World world, LivingEntity targetEntity) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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.item;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Share;
|
||||||
|
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
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 net.minecraft.entity.passive.WolfEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
|
||||||
|
@Mixin(WolfEntity.class)
|
||||||
|
class WolfEntityMixin {
|
||||||
|
@Inject(method = "interactMob", at = @At("HEAD"))
|
||||||
|
private void storeCopy(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir, @Share("interaction_stack") LocalRef<ItemStack> stackRef) {
|
||||||
|
stackRef.set(player.getStackInHand(hand).copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "interactMob", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, PlayerEntity player, Hand hand, @Share("interaction_stack") LocalRef<ItemStack> stackRef) {
|
||||||
|
return stackRef.get().getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "isBreedingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;getFoodComponent()Lnet/minecraft/item/FoodComponent;"))
|
||||||
|
private @Nullable FoodComponent getStackAwareFoodComponent(Item instance, ItemStack stack) {
|
||||||
|
return stack.getFoodComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(method = "isBreedingItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/Item;isFood()Z", ordinal = 0))
|
||||||
|
private boolean isStackAwareFood(Item instance, ItemStack stack) {
|
||||||
|
return stack.isFood();
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,17 @@
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"AbstractFurnaceBlockEntityMixin",
|
"AbstractFurnaceBlockEntityMixin",
|
||||||
"ArmorItemMixin",
|
"ArmorItemMixin",
|
||||||
|
"BlockItemMixin",
|
||||||
"BrewingStandBlockEntityMixin",
|
"BrewingStandBlockEntityMixin",
|
||||||
|
"CatEntityMixin",
|
||||||
|
"CookingRecipeJsonBuilderMixin",
|
||||||
|
"FoxEntityMixin",
|
||||||
|
"HungerManagerMixin",
|
||||||
"ItemMixin",
|
"ItemMixin",
|
||||||
"ItemStackMixin",
|
"ItemStackMixin",
|
||||||
"LivingEntityMixin",
|
"LivingEntityMixin",
|
||||||
"RecipeMixin"
|
"RecipeMixin",
|
||||||
|
"WolfEntityMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|
|
@ -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.test.item;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.registry.Registries;
|
||||||
|
import net.minecraft.registry.Registry;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
|
||||||
|
|
||||||
|
public final class FoodGameInitializer implements ModInitializer {
|
||||||
|
public static final Item DAMAGE = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "damage_food"), new DamageFood(new FabricItemSettings().maxDamage(20)));
|
||||||
|
public static final Item NAME = Registry.register(Registries.ITEM, new Identifier("fabric-item-api-v1-testmod", "name_food"), new NameFood(new FabricItemSettings()));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DamageFood extends Item {
|
||||||
|
public DamageFood(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FoodComponent getFoodComponent(ItemStack stack) {
|
||||||
|
return new FoodComponent.Builder()
|
||||||
|
.hunger(20 - 20 * stack.getDamage() / stack.getMaxDamage())
|
||||||
|
.saturationModifier(0.5f)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NameFood extends Item {
|
||||||
|
public NameFood(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FoodComponent getFoodComponent(ItemStack stack) {
|
||||||
|
return Registries.ITEM.get(new Identifier(stack.getName().getString())).getFoodComponent(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* 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.item.gametest;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.passive.WolfEntity;
|
||||||
|
import net.minecraft.entity.player.HungerManager;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.item.FoodComponent;
|
||||||
|
import net.minecraft.item.FoodComponents;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.test.GameTest;
|
||||||
|
import net.minecraft.test.TestContext;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.gametest.v1.FabricGameTest;
|
||||||
|
import net.fabricmc.fabric.test.item.FoodGameInitializer;
|
||||||
|
|
||||||
|
public final class FoodGameTest implements FabricGameTest {
|
||||||
|
@GameTest(templateName = EMPTY_STRUCTURE)
|
||||||
|
public void damageFoodTest(TestContext context) {
|
||||||
|
PlayerEntity player = context.createMockSurvivalPlayer();
|
||||||
|
HungerManager hungerManager = player.getHungerManager();
|
||||||
|
|
||||||
|
for (int damage : new int[]{0, 1, 10, 19}) {
|
||||||
|
hungerManager.setFoodLevel(0);
|
||||||
|
hungerManager.setSaturationLevel(0);
|
||||||
|
ItemStack foodStack = FoodGameInitializer.DAMAGE.getDefaultStack();
|
||||||
|
foodStack.setDamage(damage);
|
||||||
|
player.eatFood(player.getWorld(), foodStack.copy());
|
||||||
|
FoodComponent fc = Objects.requireNonNull(foodStack.getFoodComponent());
|
||||||
|
int foodActual = hungerManager.getFoodLevel();
|
||||||
|
int foodExpect = Math.min(20, fc.getHunger());
|
||||||
|
context.assertTrue(foodActual == foodExpect, "damage=%d, food actual %d, expect %d".formatted(damage, foodActual, foodExpect));
|
||||||
|
float satActual = hungerManager.getSaturationLevel();
|
||||||
|
float satExpect = Math.min(foodExpect, fc.getHunger() * fc.getSaturationModifier() * 2);
|
||||||
|
context.assertTrue(satActual == satExpect, "damage=%d, sat actual %f, expect %f".formatted(damage, satActual, satExpect));
|
||||||
|
}
|
||||||
|
|
||||||
|
context.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GameTest(templateName = EMPTY_STRUCTURE)
|
||||||
|
public void nameFoodTest(TestContext context) {
|
||||||
|
PlayerEntity player = context.createMockSurvivalPlayer();
|
||||||
|
HungerManager hungerManager = player.getHungerManager();
|
||||||
|
hungerManager.setFoodLevel(0);
|
||||||
|
hungerManager.setSaturationLevel(0);
|
||||||
|
ItemStack foodStack = FoodGameInitializer.NAME.getDefaultStack();
|
||||||
|
foodStack.setCustomName(Text.literal("enchanted_golden_apple"));
|
||||||
|
player.eatFood(player.getWorld(), foodStack.copy());
|
||||||
|
FoodComponent fc = FoodComponents.ENCHANTED_GOLDEN_APPLE;
|
||||||
|
int foodActual = hungerManager.getFoodLevel();
|
||||||
|
int foodExpect = Math.min(20, fc.getHunger());
|
||||||
|
context.assertTrue(foodActual == foodExpect, "enchanted_golden_apple, food actual %d, expect %d".formatted(foodActual, foodExpect));
|
||||||
|
float satActual = hungerManager.getSaturationLevel();
|
||||||
|
float satExpect = Math.min(foodExpect, fc.getHunger() * fc.getSaturationModifier() * 2);
|
||||||
|
context.assertTrue(satActual == satExpect, "enchanted_golden_apple, sat actual %f, expect %f".formatted(satActual, satExpect));
|
||||||
|
context.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GameTest(templateName = EMPTY_STRUCTURE)
|
||||||
|
public void nameMeatTest(TestContext context) {
|
||||||
|
PlayerEntity player = context.createMockSurvivalPlayer();
|
||||||
|
WolfEntity wolf = context.spawnEntity(EntityType.WOLF, context.getRelative(Vec3d.ZERO));
|
||||||
|
wolf.setTamed(true);
|
||||||
|
wolf.setOwner(player);
|
||||||
|
wolf.setHealth(1f);
|
||||||
|
ItemStack meat = FoodGameInitializer.NAME.getDefaultStack();
|
||||||
|
meat.setCustomName(Text.of("mutton"));
|
||||||
|
player.setStackInHand(Hand.MAIN_HAND, meat);
|
||||||
|
player.interact(wolf, Hand.MAIN_HAND);
|
||||||
|
float wolfHealth = wolf.getHealth();
|
||||||
|
context.assertTrue(wolfHealth > 0, "actual %f, expect > 0".formatted(wolfHealth));
|
||||||
|
context.complete();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/wooden_pickaxe"
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"parent": "minecraft:item/book"
|
||||||
|
}
|
|
@ -14,7 +14,8 @@
|
||||||
"net.fabricmc.fabric.test.item.FabricItemSettingsTests",
|
"net.fabricmc.fabric.test.item.FabricItemSettingsTests",
|
||||||
"net.fabricmc.fabric.test.item.ItemUpdateAnimationTest",
|
"net.fabricmc.fabric.test.item.ItemUpdateAnimationTest",
|
||||||
"net.fabricmc.fabric.test.item.ModifyItemAttributeModifiersCallbackTest",
|
"net.fabricmc.fabric.test.item.ModifyItemAttributeModifiersCallbackTest",
|
||||||
"net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest"
|
"net.fabricmc.fabric.test.item.ArmorKnockbackResistanceTest",
|
||||||
|
"net.fabricmc.fabric.test.item.FoodGameInitializer"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"net.fabricmc.fabric.test.item.client.TooltipTests"
|
"net.fabricmc.fabric.test.item.client.TooltipTests"
|
||||||
|
@ -22,7 +23,8 @@
|
||||||
"fabric-gametest" : [
|
"fabric-gametest" : [
|
||||||
"net.fabricmc.fabric.test.item.gametest.BrewingStandGameTest",
|
"net.fabricmc.fabric.test.item.gametest.BrewingStandGameTest",
|
||||||
"net.fabricmc.fabric.test.item.gametest.FurnaceGameTest",
|
"net.fabricmc.fabric.test.item.gametest.FurnaceGameTest",
|
||||||
"net.fabricmc.fabric.test.item.gametest.RecipeGameTest"
|
"net.fabricmc.fabric.test.item.gametest.RecipeGameTest",
|
||||||
|
"net.fabricmc.fabric.test.item.gametest.FoodGameTest"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue