From 1b7bdc3ec6ff349f9a69b694a55520bee99db395 Mon Sep 17 00:00:00 2001 From: gigaherz Date: Thu, 2 Dec 2021 01:59:10 +0100 Subject: [PATCH] Fix LevelChunk capability attach crash. Fix client chunks not having capability providers attached. Add capability attach tests. --- .../world/level/chunk/LevelChunk.java.patch | 12 +- .../capabilities/CapabilityProvider.java | 24 ++- .../capabilities/ICapabilityProviderImpl.java | 19 +++ .../debug/CapabilitiesTest.java | 147 ++++++++++++++++++ src/test/resources/META-INF/mods.toml | 2 + 5 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 src/test/java/net/minecraftforge/debug/CapabilitiesTest.java diff --git a/patches/minecraft/net/minecraft/world/level/chunk/LevelChunk.java.patch b/patches/minecraft/net/minecraft/world/level/chunk/LevelChunk.java.patch index 56c56df560..e79302ed1c 100644 --- a/patches/minecraft/net/minecraft/world/level/chunk/LevelChunk.java.patch +++ b/patches/minecraft/net/minecraft/world/level/chunk/LevelChunk.java.patch @@ -9,14 +9,14 @@ static final Logger f_62771_ = LogManager.getLogger(); private static final TickingBlockEntity f_156361_ = new TickingBlockEntity() { public void m_142224_() { -@@ -123,6 +_,7 @@ - - this.m_8094_(p_196851_.m_6332_()); - this.f_187603_ = true; +@@ -97,6 +_,7 @@ + this.f_62791_ = p_196861_; + this.f_62784_ = p_196857_; + this.f_187943_ = p_196858_; + this.capProvider.initInternal(); } - public TickContainerAccess m_183531_() { + public LevelChunk(ServerLevel p_196850_, ProtoChunk p_196851_, @Nullable LevelChunk.PostLoadProcessor p_196852_) { @@ -233,14 +_,14 @@ boolean flag2 = blockstate.m_155947_(); if (!this.f_62776_.f_46443_) { @@ -108,7 +108,7 @@ } + // FORGE START -+ private final net.minecraftforge.common.capabilities.CapabilityProvider.AsField capProvider = new net.minecraftforge.common.capabilities.CapabilityProvider.AsField<>(LevelChunk.class); ++ private final net.minecraftforge.common.capabilities.CapabilityProvider.AsField capProvider = new net.minecraftforge.common.capabilities.CapabilityProvider.AsField<>(LevelChunk.class, this); + + @org.jetbrains.annotations.NotNull + @Override diff --git a/src/main/java/net/minecraftforge/common/capabilities/CapabilityProvider.java b/src/main/java/net/minecraftforge/common/capabilities/CapabilityProvider.java index 84c7c2ece3..90cc6434d4 100644 --- a/src/main/java/net/minecraftforge/common/capabilities/CapabilityProvider.java +++ b/src/main/java/net/minecraftforge/common/capabilities/CapabilityProvider.java @@ -30,6 +30,7 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.event.ForgeEventFactory; +import org.jetbrains.annotations.NotNull; import java.util.function.Supplier; @@ -83,10 +84,16 @@ public abstract class CapabilityProvider> i private void doGatherCapabilities(@Nullable ICapabilityProvider parent) { - this.capabilities = ForgeEventFactory.gatherCapabilities(baseClass, this, parent); + this.capabilities = ForgeEventFactory.gatherCapabilities(baseClass, getProvider(), parent); this.initialized = true; } + @NotNull + B getProvider() + { + return (B)this; + } + protected final @Nullable CapabilityDispatcher getCapabilities() { if (isLazy && !initialized) @@ -196,14 +203,18 @@ public abstract class CapabilityProvider> i */ public static class AsField> extends CapabilityProvider { - public AsField(Class baseClass) + private final B owner; + + public AsField(Class baseClass, B owner) { super(baseClass); + this.owner = owner; } - public AsField(Class baseClass, boolean isLazy) + public AsField(Class baseClass, B owner, boolean isLazy) { super(baseClass, isLazy); + this.owner = owner; } public void initInternal() @@ -221,6 +232,13 @@ public abstract class CapabilityProvider> i { deserializeCaps(tag); } + + @Override + @NotNull + B getProvider() + { + return owner; + } }; } diff --git a/src/main/java/net/minecraftforge/common/capabilities/ICapabilityProviderImpl.java b/src/main/java/net/minecraftforge/common/capabilities/ICapabilityProviderImpl.java index 0248dc9c2c..6801781cd8 100644 --- a/src/main/java/net/minecraftforge/common/capabilities/ICapabilityProviderImpl.java +++ b/src/main/java/net/minecraftforge/common/capabilities/ICapabilityProviderImpl.java @@ -1,3 +1,22 @@ +/* + * 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 javax.annotation.Nullable; diff --git a/src/test/java/net/minecraftforge/debug/CapabilitiesTest.java b/src/test/java/net/minecraftforge/debug/CapabilitiesTest.java new file mode 100644 index 0000000000..8e65e13725 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/CapabilitiesTest.java @@ -0,0 +1,147 @@ +/* + * 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.debug; + +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.core.Direction; +import net.minecraft.nbt.IntTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.capabilities.*; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.util.thread.EffectiveSide; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.ConcurrentLinkedQueue; + +@Mod(CapabilitiesTest.MODID) +public class CapabilitiesTest +{ + public static final String MODID = "capabilities_test"; + + private static final boolean ENABLED = false; + + public static Capability INSTANCE = CapabilityManager.get(new CapabilityToken<>(){}); + + private static ResourceLocation TEST_CAP_ID = new ResourceLocation("capabilities_test:test"); + + private static final ConcurrentLinkedQueue messages = new ConcurrentLinkedQueue<>(); + + public CapabilitiesTest() + { + if (ENABLED) + { + new AttachTest<>(BlockEntity.class); + new AttachTest<>(Entity.class); + new AttachTest<>(ItemStack.class); + new AttachTest<>(LevelChunk.class); + new AttachTest<>(Level.class); + } + } + + public static class CapClass + { + private final Object o; + + public CapClass(Object o) + { + this.o = o; + } + } + + public static class AttachTest> + { + private final Class cls; + + public AttachTest(Class cls) + { + this.cls = cls; + + MinecraftForge.EVENT_BUS.addGenericListener(cls, this::attach); + } + + public void attach(AttachCapabilitiesEvent event) + { + event.addCapability(TEST_CAP_ID, new ICapabilitySerializable<>() + { + final LazyOptional instance = LazyOptional.of(() -> new CapClass(this)); + + @Override + public Tag serializeNBT() + { + return IntTag.valueOf(1); + } + + @Override + public void deserializeNBT(Tag nbt) + { + if (nbt.getId() != Tag.TAG_INT) + throw new IllegalStateException("Unexpected tag type"); + if (!(nbt instanceof IntTag it)) + throw new IllegalStateException("Unexpected tag class"); + if(it.getAsInt() != 1) + throw new IllegalStateException("Unexpected tag type"); + } + + @NotNull + @Override + public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) + { + if (cap == INSTANCE) + return instance.cast(); + return LazyOptional.empty(); + } + }); + + messages.add(String.format("Attached capability to %s in %s", event.getObject().getClass(), EffectiveSide.get())); + } + } + + @Mod.EventBusSubscriber(value= Dist.CLIENT, modid = CapabilitiesTest.MODID, bus= Mod.EventBusSubscriber.Bus.FORGE) + public static class ClientEvents + { + @SubscribeEvent + public static void clientTick(TickEvent.ClientTickEvent event) + { + if (event.phase == TickEvent.Phase.END) + { + while(messages.size() > 0) + { + Minecraft.getInstance().gui.handleChat(ChatType.SYSTEM, new TextComponent(messages.poll()), Util.NIL_UUID); + } + } + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index cd863b5cd9..0644ea22bf 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -170,5 +170,7 @@ license="LGPL v2.1" modId="full_pots_accessor_demo" [[mods]] modId="part_entity_test" +[[mods]] + modId="capabilities_test" # ADD ABOVE THIS LINE