Skip to content

Commit

Permalink
Move FabricItem implementation to js coremods
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Sep 22, 2023
1 parent 8ba517a commit 4a4df44
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,9 @@

package net.fabricmc.fabric.api.item.v1;

import java.util.function.Consumer;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

import net.fabricmc.fabric.impl.item.FabricItemInternals;

import net.minecraft.entity.LivingEntity;

import net.minecraftforge.common.extensions.IForgeItem;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

import net.minecraft.block.BlockState;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttribute;
Expand All @@ -37,9 +27,8 @@
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;

import net.fabricmc.fabric.impl.client.item.ItemApiClientEventHooks;
import net.fabricmc.fabric.impl.item.ItemExtensions;
import net.minecraftforge.common.extensions.IForgeItem;
import org.jetbrains.annotations.ApiStatus;

/**
* General-purpose Fabric-provided extensions for {@link Item} subclasses.
Expand All @@ -49,7 +38,7 @@
* <p>Note to maintainers: Functions should only be added to this interface if they are general-purpose enough,
* to be evaluated on a case-by-case basis. Otherwise, they are better suited for more specialized APIs.
*/
public interface FabricItem extends IForgeItem {
public interface FabricItem {
/**
* When the NBT of an item stack in the main hand or off hand changes, vanilla runs an "update animation".
* This function is called on the client side when the NBT or count of the stack has changed, but not the item,
Expand All @@ -62,7 +51,7 @@ public interface FabricItem extends IForgeItem {
* @return true to run the vanilla animation, false to cancel it.
*/
default boolean allowNbtUpdateAnimation(PlayerEntity player, Hand hand, ItemStack oldStack, ItemStack newStack) {
return !FabricItemInternals.allowForgeCall() || shouldCauseReequipAnimation(oldStack, newStack, false);
return !FabricItemInternals.allowForgeCall() || ((IForgeItem) this).shouldCauseReequipAnimation(oldStack, newStack, false);
}

/**
Expand All @@ -76,7 +65,7 @@ default boolean allowNbtUpdateAnimation(PlayerEntity player, Hand hand, ItemStac
* @return true to allow continuing block breaking, false to reset the progress.
*/
default boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldStack, ItemStack newStack) {
return FabricItemInternals.allowForgeCall() && !shouldCauseBlockBreakReset(oldStack, newStack);
return FabricItemInternals.allowForgeCall() && !((IForgeItem) this).shouldCauseBlockBreakReset(oldStack, newStack);
}

/**
Expand All @@ -91,7 +80,7 @@ default boolean allowContinuingBlockBreaking(PlayerEntity player, ItemStack oldS
*/
default Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(ItemStack stack, EquipmentSlot slot) {
if (FabricItemInternals.allowForgeCall()) {
return getAttributeModifiers(slot, stack);
return ((IForgeItem) this).getAttributeModifiers(slot, stack);
}
return HashMultimap.create();
}
Expand All @@ -105,7 +94,7 @@ default Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers
* @return true if drops can be harvested
*/
default boolean isSuitableFor(ItemStack stack, BlockState state) {
return FabricItemInternals.allowForgeCall() && isCorrectToolForDrops(stack, state);
return FabricItemInternals.allowForgeCall() && ((IForgeItem) this).isCorrectToolForDrops(stack, state);
}

/**
Expand Down Expand Up @@ -139,69 +128,8 @@ default boolean isSuitableFor(ItemStack stack, BlockState state) {
@ApiStatus.OverrideOnly
default ItemStack getRecipeRemainder(ItemStack stack) {
if (FabricItemInternals.allowForgeCall()) {
return getCraftingRemainingItem(stack);
return ((IForgeItem) this).getCraftingRemainingItem(stack);
}
return ItemStack.EMPTY;
}

// FFAPI: Forge default implementation

@Override
default ItemStack getCraftingRemainingItem(ItemStack stack) {
ItemStack fabricRemainder = FabricItemInternals.nonRecursiveApiCall(() -> getRecipeRemainder(stack));
if (!fabricRemainder.isEmpty()) {
return fabricRemainder;
}
return IForgeItem.super.hasCraftingRemainingItem(stack) ? new ItemStack(((Item) this).getRecipeRemainder()) : ItemStack.EMPTY;
}

@Override
default boolean hasCraftingRemainingItem(ItemStack stack) {
return !FabricItemInternals.nonRecursiveApiCall(() -> getRecipeRemainder(stack)).isEmpty() || IForgeItem.super.hasCraftingRemainingItem(stack);
}

@Override
default Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(EquipmentSlot slot, ItemStack stack) {
// Fetch forge attribute modifiers first
Multimap<EntityAttribute, EntityAttributeModifier> modifiers = HashMultimap.create(IForgeItem.super.getAttributeModifiers(slot, stack));
// Add all fabric attribute modifiers
modifiers.putAll(FabricItemInternals.nonRecursiveApiCall(() -> getAttributeModifiers(stack, slot)));
return modifiers;
}

@Override
default boolean isCorrectToolForDrops(ItemStack stack, BlockState state) {
return FabricItemInternals.nonRecursiveApiCall(() -> isSuitableFor(stack, state)) || IForgeItem.super.isCorrectToolForDrops(stack, state);
}

@Override
default boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
if (IForgeItem.super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged)) {
PlayerEntity player = ItemApiClientEventHooks.getClientPlayerSafely();
Hand hand = oldStack == player.getMainHandStack() ? Hand.MAIN_HAND : Hand.OFF_HAND;
return FabricItemInternals.nonRecursiveApiCall(() -> allowNbtUpdateAnimation(player, hand, oldStack, newStack));
}
return false;
}

@Override
default boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) {
return IForgeItem.super.shouldCauseBlockBreakReset(oldStack, newStack) && FabricItemInternals.nonRecursiveApiCall(() -> !allowContinuingBlockBreaking(ItemApiClientEventHooks.getClientPlayerSafely(), oldStack, newStack));
}

@Override
@Nullable
default EquipmentSlot getEquipmentSlot(ItemStack stack) {
EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider();
return equipmentSlotProvider != null ? equipmentSlotProvider.getPreferredEquipmentSlot(stack) : IForgeItem.super.getEquipmentSlot(stack);
}

@Override
default <T extends LivingEntity> int damageItem(ItemStack stack, int amount, T entity, Consumer<T> onBroken) {
CustomDamageHandler handler = ((ItemExtensions) this).fabric_getCustomDamageHandler();
if (handler != null) {
return handler.damage(stack, amount, entity, (Consumer<LivingEntity>) onBroken);
}
return IForgeItem.super.damageItem(stack, amount, entity, onBroken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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.item;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import net.fabricmc.fabric.api.item.v1.FabricItem;
import net.fabricmc.fabric.impl.client.item.ItemApiClientEventHooks;
import net.minecraft.block.BlockState;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;

@SuppressWarnings("unused")
public final class FabricItemImplHooks {

public static ItemStack getCraftingRemainingItem(FabricItem item, ItemStack stack) {
ItemStack fabricRemainder = FabricItemInternals.nonRecursiveApiCall(() -> item.getRecipeRemainder(stack));
if (!fabricRemainder.isEmpty()) {
return fabricRemainder;
}
return null;
}

public static boolean hasCraftingRemainingItem(FabricItem item, ItemStack stack) {
return !FabricItemInternals.nonRecursiveApiCall(() -> item.getRecipeRemainder(stack)).isEmpty();
}

public static Multimap<EntityAttribute, EntityAttributeModifier> getAttributeModifiers(Multimap<EntityAttribute, EntityAttributeModifier> existing, FabricItem item, EquipmentSlot slot, ItemStack stack) {
// Fetch forge attribute modifiers first
Multimap<EntityAttribute, EntityAttributeModifier> modifiers = HashMultimap.create(existing);
// Add all fabric attribute modifiers
modifiers.putAll(FabricItemInternals.nonRecursiveApiCall(() -> item.getAttributeModifiers(stack, slot)));
return modifiers;
}

public static boolean isCorrectToolForDrops(FabricItem item, ItemStack stack, BlockState state) {
return FabricItemInternals.nonRecursiveApiCall(() -> item.isSuitableFor(stack, state));
}

public static boolean shouldCauseReequipAnimation(FabricItem item, ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
PlayerEntity player = ItemApiClientEventHooks.getClientPlayerSafely();
Hand hand = oldStack == player.getMainHandStack() ? Hand.MAIN_HAND : Hand.OFF_HAND;
return FabricItemInternals.nonRecursiveApiCall(() -> item.allowNbtUpdateAnimation(player, hand, oldStack, newStack));
}

public static boolean shouldCauseBlockBreakReset(boolean original, FabricItem item, ItemStack oldStack, ItemStack newStack) {
return original && FabricItemInternals.nonRecursiveApiCall(() -> !item.allowContinuingBlockBreaking(ItemApiClientEventHooks.getClientPlayerSafely(), oldStack, newStack));
}

private FabricItemImplHooks() {}
}
Loading

0 comments on commit 4a4df44

Please sign in to comment.