mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 08:17:35 +00:00
Implements Lazy ItemStack Capabilities (#7879)
This commit is contained in:
1 parent
2c36b306a4
commit
111d3ec5d5
4 files changed
+260
-21
No files matched your search
@@ -19,33 +19,29 @@
|
||||
private static final Logger field_199558_c = LogManager.getLogger();
|
||||
public static final ItemStack field_190927_a = new ItemStack((Item)null);
|
||||
public static final DecimalFormat field_111284_a = Util.func_200696_a(new DecimalFormat("#.##"), (p_234699_0_) -> {
|
||||
@@ -109,14 +_,19 @@
|
||||
@@ -109,10 +_,15 @@
|
||||
p_i231596_3_.ifPresent(this::func_77982_d);
|
||||
}
|
||||
|
||||
- public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_) {
|
||||
+ public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_) { this(p_i48204_1_, p_i48204_2_, (CompoundNBT) null); }
|
||||
+ public ItemStack(IItemProvider p_i48204_1_, int p_i48204_2_, @Nullable CompoundNBT capNBT) {
|
||||
+ super(ItemStack.class);
|
||||
+ super(ItemStack.class, true);
|
||||
+ this.capNBT = capNBT;
|
||||
this.field_151002_e = p_i48204_1_ == null ? null : p_i48204_1_.func_199767_j();
|
||||
+ this.delegate = p_i48204_1_ == null ? null : p_i48204_1_.func_199767_j().delegate;
|
||||
this.field_77994_a = p_i48204_2_;
|
||||
- if (this.field_151002_e != null && this.field_151002_e.func_77645_m()) {
|
||||
+ this.forgeInit();
|
||||
+ if (this.field_151002_e != null && this.field_151002_e.isDamageable(this)) {
|
||||
this.func_196085_b(this.func_77952_i());
|
||||
}
|
||||
|
||||
this.func_190923_F();
|
||||
+ this.forgeInit();
|
||||
}
|
||||
|
||||
private void func_190923_F() {
|
||||
@@ -125,18 +_,23 @@
|
||||
@@ -125,14 +_,18 @@
|
||||
}
|
||||
|
||||
private ItemStack(CompoundNBT p_i47263_1_) {
|
||||
+ super(ItemStack.class);
|
||||
+ super(ItemStack.class, true);
|
||||
+ this.capNBT = p_i47263_1_.func_74764_b("ForgeCaps") ? p_i47263_1_.func_74775_l("ForgeCaps") : null;
|
||||
+ Item rawItem =
|
||||
this.field_151002_e = Registry.field_212630_s.func_82594_a(new ResourceLocation(p_i47263_1_.func_74779_i("id")));
|
||||
@@ -55,17 +51,13 @@
|
||||
this.field_77990_d = p_i47263_1_.func_74775_l("tag");
|
||||
this.func_77973_b().func_179215_a(p_i47263_1_);
|
||||
}
|
||||
|
||||
-
|
||||
- if (this.func_77973_b().func_77645_m()) {
|
||||
+ this.forgeInit();
|
||||
+ if (this.func_77973_b().isDamageable(this)) {
|
||||
this.func_196085_b(this.func_77952_i());
|
||||
}
|
||||
|
||||
this.func_190923_F();
|
||||
+ this.forgeInit();
|
||||
}
|
||||
|
||||
public static ItemStack func_199557_a(CompoundNBT p_199557_0_) {
|
||||
@@ -167,10 +_,19 @@
|
||||
}
|
||||
|
||||
@@ -220,7 +212,7 @@
|
||||
return multimap;
|
||||
}
|
||||
|
||||
@@ -952,6 +_,24 @@
|
||||
@@ -952,6 +_,23 @@
|
||||
|
||||
public boolean func_222117_E() {
|
||||
return this.func_77973_b().func_219971_r();
|
||||
@@ -238,8 +230,7 @@
|
||||
+ */
|
||||
+ private void forgeInit() {
|
||||
+ if (this.delegate != null) {
|
||||
+ net.minecraftforge.common.capabilities.ICapabilityProvider provider = field_151002_e.initCapabilities(this, this.capNBT);
|
||||
+ this.gatherCapabilities(provider);
|
||||
+ this.gatherCapabilities(() -> field_151002_e.initCapabilities(this, this.capNBT));
|
||||
+ if (this.capNBT != null) deserializeCaps(this.capNBT);
|
||||
+ }
|
||||
}
|
||||
|
||||
@@ -22,35 +22,80 @@ package net.minecraftforge.common.capabilities;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import mcp.MethodsReturnNonnullByDefault;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@MethodsReturnNonnullByDefault
|
||||
@ParametersAreNonnullByDefault
|
||||
public abstract class CapabilityProvider<B extends CapabilityProvider<B>> implements ICapabilityProvider
|
||||
{
|
||||
@VisibleForTesting
|
||||
static boolean SUPPORTS_LAZY_CAPABILITIES = true;
|
||||
|
||||
private final @Nonnull Class<B> baseClass;
|
||||
private @Nullable CapabilityDispatcher capabilities;
|
||||
private boolean valid = true;
|
||||
|
||||
private boolean isLazy = false;
|
||||
private Supplier<ICapabilityProvider> lazyParentSupplier = null;
|
||||
private CompoundNBT lazyData = null;
|
||||
private boolean initialized = false;
|
||||
|
||||
protected CapabilityProvider(Class<B> baseClass)
|
||||
{
|
||||
this.baseClass = baseClass;
|
||||
this(baseClass, false);
|
||||
}
|
||||
|
||||
protected final void gatherCapabilities() { gatherCapabilities(null); }
|
||||
protected CapabilityProvider(final Class<B> baseClass, final boolean isLazy)
|
||||
{
|
||||
this.baseClass = baseClass;
|
||||
this.isLazy = SUPPORTS_LAZY_CAPABILITIES && isLazy;
|
||||
}
|
||||
|
||||
protected final void gatherCapabilities()
|
||||
{
|
||||
gatherCapabilities(() -> null);
|
||||
}
|
||||
|
||||
protected final void gatherCapabilities(@Nullable ICapabilityProvider parent)
|
||||
{
|
||||
gatherCapabilities(() -> parent);
|
||||
}
|
||||
|
||||
protected final void gatherCapabilities(@Nullable Supplier<ICapabilityProvider> parent)
|
||||
{
|
||||
if (isLazy && !initialized)
|
||||
{
|
||||
lazyParentSupplier = parent == null ? () -> null : parent;
|
||||
return;
|
||||
}
|
||||
|
||||
doGatherCapabilities(parent == null ? null : parent.get());
|
||||
}
|
||||
|
||||
private void doGatherCapabilities(@Nullable ICapabilityProvider parent)
|
||||
{
|
||||
this.capabilities = ForgeEventFactory.gatherCapabilities(baseClass, this, parent);
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
protected final @Nullable CapabilityDispatcher getCapabilities()
|
||||
{
|
||||
return this.capabilities;
|
||||
if(isLazy && !initialized)
|
||||
{
|
||||
doGatherCapabilities(lazyParentSupplier == null ? null : lazyParentSupplier.get());
|
||||
if (lazyData != null)
|
||||
{
|
||||
deserializeCaps(lazyData);
|
||||
}
|
||||
}
|
||||
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public final boolean areCapsCompatible(CapabilityProvider<B> other)
|
||||
@@ -80,6 +125,11 @@ public abstract class CapabilityProvider<B extends CapabilityProvider<B>> implem
|
||||
|
||||
protected final @Nullable CompoundNBT serializeCaps()
|
||||
{
|
||||
if(isLazy && !initialized)
|
||||
{
|
||||
return lazyData;
|
||||
}
|
||||
|
||||
final CapabilityDispatcher disp = getCapabilities();
|
||||
if (disp != null)
|
||||
{
|
||||
@@ -90,6 +140,12 @@ public abstract class CapabilityProvider<B extends CapabilityProvider<B>> implem
|
||||
|
||||
protected final void deserializeCaps(CompoundNBT tag)
|
||||
{
|
||||
if (isLazy && !initialized)
|
||||
{
|
||||
lazyData = tag;
|
||||
return;
|
||||
}
|
||||
|
||||
final CapabilityDispatcher disp = getCapabilities();
|
||||
if (disp != null)
|
||||
{
|
||||
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2021.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.capabilities;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullLazy;
|
||||
import net.minecraftforge.common.util.TablePrinter;
|
||||
import net.minecraftforge.common.util.TextTable;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStackSimple;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minecraftforge.common.util.TextTable.column;
|
||||
|
||||
@Mod(LazyCapabilitiesOnItemsTest.MOD_ID)
|
||||
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, modid = LazyCapabilitiesOnItemsTest.MOD_ID)
|
||||
public class LazyCapabilitiesOnItemsTest
|
||||
{
|
||||
public static final String MOD_ID = "lazy_capabilities_on_items";
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final boolean ENABLED = true;
|
||||
private static final int SAMPLE_SIZE = 100000;
|
||||
|
||||
private static final List<ItemStack> WARMUP_RESULTS = new ArrayList<>(SAMPLE_SIZE * 4);
|
||||
private static final List<ItemStack> NO_CAPS_DISABLED_RESULTS = new ArrayList<>(SAMPLE_SIZE);
|
||||
private static final List<ItemStack> WITH_CAPS_DISABLED_RESULTS = new ArrayList<>(SAMPLE_SIZE);
|
||||
private static final List<ItemStack> NO_CAPS_ENABLED_RESULTS = new ArrayList<>(SAMPLE_SIZE);
|
||||
private static final List<ItemStack> WITH_CAPS_ENABLED_RESULTS = new ArrayList<>(SAMPLE_SIZE);
|
||||
|
||||
public LazyCapabilitiesOnItemsTest()
|
||||
{
|
||||
if (!ENABLED)
|
||||
return;
|
||||
|
||||
final IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
modBus.addListener(this::onCommonSetup);
|
||||
}
|
||||
|
||||
private void onCommonSetup(FMLCommonSetupEvent event)
|
||||
{
|
||||
try
|
||||
{
|
||||
final Field supportsFlagField = CapabilityProvider.class.getDeclaredField("SUPPORTS_LAZY_CAPABILITIES");
|
||||
supportsFlagField.setAccessible(true);
|
||||
supportsFlagField.set(null, false);
|
||||
|
||||
final Stopwatch timer = Stopwatch.createUnstarted();
|
||||
final IEventBus bus = MinecraftForge.EVENT_BUS;
|
||||
|
||||
final ResourceLocation testCapId = new ResourceLocation(MOD_ID, "test");
|
||||
final Consumer<AttachCapabilitiesEvent<ItemStack>> capAttachmentHandler = e -> {
|
||||
//Example capability we make everything a bucket :D
|
||||
e.addCapability(testCapId, new FluidHandlerItemStackSimple(e.getObject(), SAMPLE_SIZE));
|
||||
};
|
||||
|
||||
//Warmup:
|
||||
for (int i = 0; i < (SAMPLE_SIZE); i++)
|
||||
{
|
||||
WARMUP_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
///First test: SAMPLE_SIZE itemstacks which do not have a capability attached.
|
||||
timer.start();
|
||||
for (int i = 0; i < SAMPLE_SIZE; i++)
|
||||
{
|
||||
NO_CAPS_DISABLED_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
timer.stop();
|
||||
|
||||
final long simpleNoCapsLazyDisabledElapsed = timer.elapsed(TimeUnit.MICROSECONDS);
|
||||
timer.reset();
|
||||
|
||||
///Second test: SAMPLE_SIZE itemstacks with a capability attached.
|
||||
bus.addGenericListener(ItemStack.class, capAttachmentHandler);
|
||||
//Warmup:
|
||||
for (int i = 0; i < (SAMPLE_SIZE); i++)
|
||||
{
|
||||
WARMUP_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
timer.start();
|
||||
for (int i = 0; i < SAMPLE_SIZE; i++)
|
||||
{
|
||||
WITH_CAPS_DISABLED_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
timer.stop();
|
||||
|
||||
final long withCapsLazyDisabledElapsed = timer.elapsed(TimeUnit.MICROSECONDS);
|
||||
timer.reset();
|
||||
bus.unregister(capAttachmentHandler);
|
||||
|
||||
///Third test: SAMPLE_SIZE itemstacks which do not have a capability attached.
|
||||
supportsFlagField.set(null, true);
|
||||
//Warmup:
|
||||
for (int i = 0; i < (SAMPLE_SIZE); i++)
|
||||
{
|
||||
WARMUP_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
timer.start();
|
||||
for (int i = 0; i < SAMPLE_SIZE; i++)
|
||||
{
|
||||
NO_CAPS_ENABLED_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
timer.stop();
|
||||
|
||||
final long simpleNoCapsLazyEnabledElapsed = timer.elapsed(TimeUnit.MICROSECONDS);
|
||||
timer.reset();
|
||||
|
||||
///Fourth test: SAMPLE_SIZE itemstacks with a capability attached.
|
||||
bus.addGenericListener(ItemStack.class, capAttachmentHandler);
|
||||
//Warmup:
|
||||
for (int i = 0; i < (SAMPLE_SIZE); i++)
|
||||
{
|
||||
WARMUP_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
|
||||
timer.start();
|
||||
for (int i = 0; i < SAMPLE_SIZE; i++)
|
||||
{
|
||||
WITH_CAPS_ENABLED_RESULTS.add(new ItemStack(Items.WATER_BUCKET));
|
||||
}
|
||||
timer.stop();
|
||||
|
||||
final long withCapsLazyEnabledElapsed = timer.elapsed(TimeUnit.MICROSECONDS);
|
||||
timer.reset();
|
||||
bus.unregister(capAttachmentHandler);
|
||||
|
||||
TextTable table = new TextTable(Lists.newArrayList(
|
||||
column("Test type", TextTable.Alignment.LEFT),
|
||||
column("Total time", TextTable.Alignment.CENTER)
|
||||
));
|
||||
|
||||
table.add("Lazy: Disabled / Caps: None", simpleNoCapsLazyDisabledElapsed + " ms.");
|
||||
table.add("Lazy: Disabled / Caps: One", withCapsLazyDisabledElapsed + " ms.");
|
||||
table.add("Lazy: Enabled / Caps: None", simpleNoCapsLazyEnabledElapsed + " ms.");
|
||||
table.add("Lazy: Enabled / Caps: One", withCapsLazyEnabledElapsed + " ms.");
|
||||
|
||||
final String[] resultData = table.build("\n").split("\n");
|
||||
for (final String line : resultData)
|
||||
{
|
||||
LOGGER.warn(line);
|
||||
}
|
||||
}
|
||||
catch (NoSuchFieldException | IllegalAccessException e)
|
||||
{
|
||||
LOGGER.error("Failed to run capabilities on items test!");
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,6 +138,8 @@ license="LGPL v2.1"
|
||||
modId="dimension_settings_test"
|
||||
[[mods]]
|
||||
modId="player_attack_knockback_test"
|
||||
[[mods]]
|
||||
modId="lazy_capabilities_on_items"
|
||||
[[mods]]
|
||||
modId="send_datapacks_to_client"
|
||||
[[mods]]
|
||||
|
||||
Reference in new issue
Block a user