diff --git a/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLPlayHandler.java index 4a38b171b..5125c76f5 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 42063be76..ab10cd9d1 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 6f2ce19ed..cb16e7224 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 1369199ee..36e6717da 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