From 153e7a1806f4241d9ab0cc3f9088d14b81f9a9a0 Mon Sep 17 00:00:00 2001 From: Vincent Lee Date: Thu, 7 Feb 2019 20:31:17 -0600 Subject: [PATCH] Tentatively reintroduce a container-opening system --- .../entity/player/EntityPlayer.java.patch | 13 +++++- .../fml/network/FMLPlayHandler.java | 1 + .../fml/network/FMLPlayMessages.java | 46 +++++++++++++++++++ .../fml/network/NetworkHooks.java | 28 +++++++++++ .../fml/network/NetworkRegistry.java | 19 ++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch index eb5c04b49..f721dce3a 100644 --- a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch +++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch @@ -500,7 +500,7 @@ if (this.func_70608_bn()) { f = 0.2F; } else if (!this.func_203007_ba() && !this.func_184613_cA() && this.field_70131_O != 0.6F) { -@@ -1967,6 +2096,30 @@ +@@ -1967,6 +2096,41 @@ return this.field_71075_bZ.field_75098_d && this.func_184840_I() >= 2; } @@ -527,6 +527,17 @@ + public Collection getSuffixes() { + return this.suffixes; + } ++ ++ /** ++ * Opens a modded container, based on {@code container.getGuiID} ++ * Container.getGuiID must return a valid ResourceLocation in String form. Vanilla follows this, but does not enforce it. ++ * @param container The container provider. The container will be obtained using {@link IInteractionObject#createContainer}. ++ * @param extraData Any extra data to communicate to the client ++ */ ++ public void openGui(IInteractionObject container, @Nullable io.netty.buffer.ByteBuf extraData) ++ { ++ if (!field_70170_p.field_72995_K) net.minecraftforge.fml.network.NetworkHooks.openGui((EntityPlayerMP) this, container, extraData); ++ } + public static enum EnumChatVisibility { FULL(0, "options.chat.visibility.full"), diff --git a/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java index 06f611c49..ccb2cb874 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java @@ -33,5 +33,6 @@ public class FMLPlayHandler static { channel.registerMessage(0, FMLPlayMessages.SpawnEntity.class, FMLPlayMessages.SpawnEntity::encode, FMLPlayMessages.SpawnEntity::decode, FMLPlayMessages.SpawnEntity::handle); + channel.registerMessage(1, FMLPlayMessages.OpenContainer.class, FMLPlayMessages.OpenContainer::encode, FMLPlayMessages.OpenContainer::decode, FMLPlayMessages.OpenContainer::handle); } } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java b/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java index 01d0eb456..67c24ceea 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java @@ -19,15 +19,20 @@ package net.minecraftforge.fml.network; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityTracker; import net.minecraft.entity.EntityType; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import java.util.UUID; +import java.util.function.Function; import java.util.function.Supplier; public class FMLPlayMessages @@ -156,4 +161,45 @@ public class FMLPlayMessages ctx.get().setPacketHandled(true); } } + + public static class OpenContainer + { + private final ResourceLocation id; + private final int windowId; + private final byte[] additionalData; + + public OpenContainer(ResourceLocation id, int windowId, byte[] additionalData) + { + this.id = id; + this.windowId = windowId; + this.additionalData = additionalData; + } + + public static void encode(OpenContainer msg, PacketBuffer buf) + { + buf.writeResourceLocation(msg.id); + buf.writeVarInt(msg.windowId); + buf.writeByteArray(msg.additionalData); + } + + public static OpenContainer decode(PacketBuffer buf) + { + return new OpenContainer(buf.readResourceLocation(), buf.readVarInt(), buf.readByteArray()); + } + + public static void handle(OpenContainer msg, Supplier ctx) + { + ctx.get().enqueueWork(() -> { + Supplier> sup = NetworkRegistry.guiHandlers.get(msg.id); + if (sup != null) { + GuiScreen gui = sup.get().apply(Unpooled.wrappedBuffer(msg.additionalData)); + if (gui != null) { + Minecraft.getInstance().displayGuiScreen(gui); + Minecraft.getInstance().player.openContainer.windowId = msg.windowId; + } + } + }); + ctx.get().setPacketHandled(true); + } + } } diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java index 76948c245..d4974408c 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java @@ -19,15 +19,21 @@ package net.minecraftforge.fml.network; +import io.netty.buffer.ByteBuf; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.inventory.Container; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.NetworkManager; import net.minecraft.network.Packet; import net.minecraft.network.handshake.client.CPacketHandshake; import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.IInteractionObject; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerContainerEvent; +import javax.annotation.Nullable; import java.util.Objects; public class NetworkHooks @@ -80,4 +86,26 @@ public class NetworkHooks { return FMLHandshakeHandler.tickLogin(networkManager); } + + public static void openGui(EntityPlayerMP player, IInteractionObject container, @Nullable ByteBuf extraData) + { + ResourceLocation id = new ResourceLocation(container.getGuiID()); + Container c = container.createContainer(player.inventory, player); + player.closeScreen(); + player.getNextWindowId(); + player.openContainer = c; + player.openContainer.windowId = player.currentWindowId; + player.openContainer.addListener(player); + MinecraftForge.EVENT_BUS.post(new PlayerContainerEvent.Open(player, c)); + + byte[] additional; + if (extraData == null) { + additional = new byte[0]; + } else { + additional = new byte[extraData.readableBytes()]; + extraData.readBytes(additional); + } + FMLPlayMessages.OpenContainer msg = new FMLPlayMessages.OpenContainer(id, player.currentWindowId, additional); + FMLPlayHandler.channel.sendTo(msg, player.connection.getNetworkManager(), NetworkDirection.PLAY_TO_CLIENT); + } } diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java b/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java index dd27ebb46..c63259b4f 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java @@ -19,6 +19,8 @@ package net.minecraftforge.fml.network; +import io.netty.buffer.ByteBuf; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.network.NetworkManager; @@ -33,7 +35,9 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -47,6 +51,21 @@ public class NetworkRegistry private static final Marker NETREGISTRY = MarkerManager.getMarker("NETREGISTRY"); private static Map instances = new HashMap<>(); + static final Map>> guiHandlers = new ConcurrentHashMap<>(); + + /** + * Registers a client-side GUI handler for the given ID. + * The function takes any extra data provided to {@link net.minecraft.entity.player.EntityPlayer#openGui} + * and returns a {@link GuiScreen} to display. + * Call this during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}. + * This method is safe to call in parallel mod loading + * @param id + * @param handler + */ + public static void registerGui(ResourceLocation id, Supplier> handler) + { + guiHandlers.put(id, handler); + } /** * Special value for clientAcceptedVersions and serverAcceptedVersions predicates indicating the other side lacks