mirror of
https://github.com/MinecraftForge/MinecraftForge
synced 2026-08-22 04:26:10 -04:00
Re-introduce ItemStack Capabilities (#10362)
Co-authored-by: RealMangoRage <64402114+RealMangorage@users.noreply.github.com> Co-authored-by: LexManos <LexManos@gmail.com>
This commit is contained in:
parent
056360b050
commit
979abb2b93
3 changed files with 193 additions and 1 deletions
|
|
@ -5,10 +5,27 @@
|
|||
import org.slf4j.Logger;
|
||||
|
||||
-public final class ItemStack implements DataComponentHolder {
|
||||
+public final class ItemStack implements DataComponentHolder, net.minecraftforge.common.extensions.IForgeItemStack {
|
||||
+public final class ItemStack extends net.minecraftforge.common.capabilities.CapabilityProvider<ItemStack> implements DataComponentHolder, net.minecraftforge.common.extensions.IForgeItemStack {
|
||||
public static final Codec<ItemStack> CODEC = Codec.lazyInitialized(
|
||||
() -> RecordCodecBuilder.create(
|
||||
p_359412_ -> p_359412_.group(
|
||||
@@ -252,13 +_,16 @@
|
||||
}
|
||||
|
||||
private ItemStack(ItemLike p_331826_, int p_332766_, PatchedDataComponentMap p_333722_) {
|
||||
+ super(ItemStack.class, true);
|
||||
this.item = p_331826_.asItem();
|
||||
this.count = p_332766_;
|
||||
this.components = p_333722_;
|
||||
this.getItem().verifyComponentsAfterLoad(this);
|
||||
+ gatherCapabilities(() -> this.item.getCapabilityProvider(this));
|
||||
}
|
||||
|
||||
private ItemStack(@Nullable Void p_282703_) {
|
||||
+ super(ItemStack.class, false);
|
||||
this.item = null;
|
||||
this.components = new PatchedDataComponentMap(DataComponentMap.EMPTY);
|
||||
}
|
||||
@@ -348,13 +_,22 @@
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import net.minecraft.world.level.Level;
|
|||
import net.minecraftforge.common.ForgeHooks;
|
||||
import net.minecraftforge.common.ToolAction;
|
||||
import net.minecraftforge.common.ToolActions;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
|
@ -611,4 +612,12 @@ public interface IForgeItem {
|
|||
default boolean canGrindstoneRepair(ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Default Capability Provider for this item, if any, accounting for the given itemstack.
|
||||
*/
|
||||
@Nullable
|
||||
default ICapabilityProvider getCapabilityProvider(ItemStack stack) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.debug.gameplay.item;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.component.DataComponentType;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestHelper;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.energy.EnergyStorage;
|
||||
import net.minecraftforge.energy.IEnergyStorage;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.gametest.GameTestHolder;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import net.minecraftforge.test.BaseTestMod;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@GameTestHolder("forge." + ItemCapabilityTest.MOD_ID)
|
||||
@Mod(ItemCapabilityTest.MOD_ID)
|
||||
public class ItemCapabilityTest extends BaseTestMod {
|
||||
public static final String MOD_ID = "item_caps";
|
||||
|
||||
public static final DeferredRegister<DataComponentType<?>> DATA_COMPONENTS = DeferredRegister.create(Registries.DATA_COMPONENT_TYPE, MOD_ID);
|
||||
public static final RegistryObject<DataComponentType<Integer>> STORAGE = DATA_COMPONENTS.register("energy_storage", () ->
|
||||
DataComponentType.<Integer>builder()
|
||||
.persistent(ExtraCodecs.POSITIVE_INT)
|
||||
.networkSynchronized(ByteBufCodecs.VAR_INT)
|
||||
.build()
|
||||
);
|
||||
|
||||
public ItemCapabilityTest(FMLJavaModLoadingContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onEvent(AttachCapabilitiesEvent<ItemStack> event) {
|
||||
if (event.getObject().getItem() == Items.COPPER_INGOT) {
|
||||
event.addCapability(
|
||||
ResourceLocation.fromNamespaceAndPath("forge", "test"),
|
||||
new MyProvider(event.getObject())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@GameTest(template = "forge:empty3x3x3")
|
||||
public static void testItemCap(GameTestHelper helper) {
|
||||
|
||||
helper.registerEventListener(ItemCapabilityTest.class);
|
||||
|
||||
ItemStack stack = new ItemStack(Items.COPPER_INGOT);
|
||||
AtomicReference<IEnergyStorage> storageAtomicReference = new AtomicReference<>();
|
||||
|
||||
stack.getCapability(ForgeCapabilities.ENERGY).ifPresent(storage -> {
|
||||
storage.receiveEnergy(1, false);
|
||||
storageAtomicReference.set(storage);
|
||||
});
|
||||
|
||||
helper.assertTrue(
|
||||
storageAtomicReference.get() != null,
|
||||
"Unable to find ForgeCapabilities.ENERGY Capability"
|
||||
);
|
||||
|
||||
var registry = RegistryFriendlyByteBuf.decorator(helper.getLevel().registryAccess()).apply(new FriendlyByteBuf(Unpooled.buffer()));
|
||||
|
||||
ItemStack.STREAM_CODEC.encode(registry, stack);
|
||||
var stackOverWire = ItemStack.STREAM_CODEC.decode(registry);
|
||||
|
||||
AtomicReference<IEnergyStorage> storage = new AtomicReference<>();
|
||||
stackOverWire.getCapability(ForgeCapabilities.ENERGY).ifPresent(storage::set);
|
||||
|
||||
helper.assertValueEqual(
|
||||
storage.get() == null ? -1 : storage.get().getEnergyStored(),
|
||||
11,
|
||||
"Value did not Sync to client"
|
||||
);
|
||||
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
public static final class MyEnergyStorage extends EnergyStorage {
|
||||
|
||||
private final Consumer<EnergyStorage> consumer;
|
||||
|
||||
public MyEnergyStorage(int capacity, Consumer<EnergyStorage> consumer) {
|
||||
super(capacity);
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public MyEnergyStorage(int capacity, int maxTransfer, Consumer<EnergyStorage> consumer) {
|
||||
super(capacity, maxTransfer);
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public MyEnergyStorage(int capacity, int maxReceive, int maxExtract, Consumer<EnergyStorage> consumer) {
|
||||
super(capacity, maxReceive, maxExtract);
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public MyEnergyStorage(int capacity, int maxReceive, int maxExtract, int energy, Consumer<EnergyStorage> consumer) {
|
||||
super(capacity, maxReceive, maxExtract, energy);
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
static <T, V> T doAndReturn(T value, V value2, Consumer<V> consumer) {
|
||||
consumer.accept(value2);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int receiveEnergy(int maxReceive, boolean simulate) {
|
||||
return doAndReturn(super.receiveEnergy(maxReceive, simulate), this, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extractEnergy(int maxExtract, boolean simulate) {
|
||||
return doAndReturn(super.extractEnergy(maxExtract, simulate), this, consumer);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MyProvider implements ICapabilityProvider {
|
||||
private final ItemStack stack;
|
||||
private final EnergyStorage storage;
|
||||
private final LazyOptional<EnergyStorage> storageLazyOptional;
|
||||
|
||||
public MyProvider(ItemStack stack) {
|
||||
this.stack = stack;
|
||||
this.storage = new MyEnergyStorage(1000, 10, 10, stack.getOrDefault(STORAGE.get(), 10), storage -> {
|
||||
stack.set(STORAGE.get(), storage.getEnergyStored());
|
||||
});
|
||||
this.storageLazyOptional = LazyOptional.of(() -> storage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == ForgeCapabilities.ENERGY) {
|
||||
return storageLazyOptional.cast();
|
||||
}
|
||||
return LazyOptional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue