diff --git a/src/main/java/net/minecraftforge/fml/DeferredWorkQueue.java b/src/main/java/net/minecraftforge/fml/DeferredWorkQueue.java index 3a513007e2..8227193a64 100644 --- a/src/main/java/net/minecraftforge/fml/DeferredWorkQueue.java +++ b/src/main/java/net/minecraftforge/fml/DeferredWorkQueue.java @@ -109,7 +109,7 @@ public class DeferredWorkQueue * @return A {@link CompletableFuture} that completes at said time */ public static CompletableFuture runLater(Runnable workToEnqueue) { - currentOwner.set(ModThreadContext.get().getActiveContainer()); + currentOwner.set(ModLoadingContext.get().getActiveContainer()); return CompletableFuture.runAsync(workToEnqueue, deferredExecutor).exceptionally(DeferredWorkQueue.handleException()); } @@ -154,7 +154,7 @@ public class DeferredWorkQueue * @return A {@link CompletableFuture} that completes at said time */ public static CompletableFuture getLater(Supplier workToEnqueue) { - currentOwner.set(ModThreadContext.get().getActiveContainer()); + currentOwner.set(ModLoadingContext.get().getActiveContainer()); return CompletableFuture.supplyAsync(workToEnqueue, deferredExecutor).exceptionally(DeferredWorkQueue.handleException()); } diff --git a/src/main/java/net/minecraftforge/fml/ExtensionPoint.java b/src/main/java/net/minecraftforge/fml/ExtensionPoint.java index d087bc07fc..9cce0bab11 100644 --- a/src/main/java/net/minecraftforge/fml/ExtensionPoint.java +++ b/src/main/java/net/minecraftforge/fml/ExtensionPoint.java @@ -22,14 +22,23 @@ package net.minecraftforge.fml; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.resources.IResourcePack; +import net.minecraftforge.fml.network.FMLPlayMessages; import net.minecraftforge.fml.packs.ModFileResourcePack; import java.util.function.BiFunction; +import java.util.function.Function; public class ExtensionPoint { - public static final ExtensionPoint> GUIFACTORY = new ExtensionPoint<>(); + public static final ExtensionPoint> CONFIGGUIFACTORY = new ExtensionPoint<>(); public static final ExtensionPoint> RESOURCEPACK = new ExtensionPoint<>(); + + /** + * Register with {@link ModLoadingContext#} + */ + public static final ExtensionPoint> GUIFACTORY = new ExtensionPoint<>(); + + private Class type; private ExtensionPoint() { diff --git a/src/main/java/net/minecraftforge/fml/ModContainer.java b/src/main/java/net/minecraftforge/fml/ModContainer.java index 4afbf87a30..92a7c7adaa 100644 --- a/src/main/java/net/minecraftforge/fml/ModContainer.java +++ b/src/main/java/net/minecraftforge/fml/ModContainer.java @@ -115,11 +115,11 @@ public abstract class ModContainer } @SuppressWarnings("unchecked") - public Optional getCustomExtension(ExtensionPoint point) { + public Optional getCustomExtension(ExtensionPoint point) { return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get()); } - public void registerExtensionPoint(ExtensionPoint point, Supplier extension) + public void registerExtensionPoint(ExtensionPoint point, Supplier extension) { extensionPoints.put(point, extension); } diff --git a/src/main/java/net/minecraftforge/fml/ModThreadContext.java b/src/main/java/net/minecraftforge/fml/ModLoadingContext.java similarity index 63% rename from src/main/java/net/minecraftforge/fml/ModThreadContext.java rename to src/main/java/net/minecraftforge/fml/ModLoadingContext.java index 9bf7e8f3f9..d654666a98 100644 --- a/src/main/java/net/minecraftforge/fml/ModThreadContext.java +++ b/src/main/java/net/minecraftforge/fml/ModLoadingContext.java @@ -19,11 +19,13 @@ package net.minecraftforge.fml; -public class ModThreadContext -{ - private static ThreadLocal context = ThreadLocal.withInitial(ModThreadContext::new); +import java.util.function.Supplier; - public static ModThreadContext get() { +public class ModLoadingContext +{ + private static ThreadLocal context = ThreadLocal.withInitial(ModLoadingContext::new); + + public static ModLoadingContext get() { return context.get(); } @@ -36,4 +38,15 @@ public class ModThreadContext public ModContainer getActiveContainer() { return activeContainer == null ? DefaultModContainers.MINECRAFT : activeContainer; } + + /** + * Register an {@link ExtensionPoint} with the mod container. + * @param point The extension point to register + * @param extension An extension operator + * @param The type signature of the extension operator + */ + public void registerExtensionPoint(ExtensionPoint point, Supplier extension) { + getActiveContainer().registerExtensionPoint(point, extension); + } + } diff --git a/src/main/java/net/minecraftforge/fml/client/ConfigGuiHandler.java b/src/main/java/net/minecraftforge/fml/client/ConfigGuiHandler.java index b258b4c603..c12d63f3fb 100644 --- a/src/main/java/net/minecraftforge/fml/client/ConfigGuiHandler.java +++ b/src/main/java/net/minecraftforge/fml/client/ConfigGuiHandler.java @@ -33,6 +33,6 @@ public class ConfigGuiHandler public static Optional> getGuiFactoryFor(ModInfo selectedMod) { return ModList.get().getModContainerById(selectedMod.getModId()). - flatMap(mc -> mc.getCustomExtension(ExtensionPoint.GUIFACTORY)); + flatMap(mc -> mc.getCustomExtension(ExtensionPoint.CONFIGGUIFACTORY)); } } diff --git a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModContainer.java b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModContainer.java index af476136f7..e226229260 100644 --- a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModContainer.java +++ b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModContainer.java @@ -28,7 +28,7 @@ import net.minecraftforge.fml.LifecycleEventProvider; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingException; import net.minecraftforge.fml.ModLoadingStage; -import net.minecraftforge.fml.ModThreadContext; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.forgespi.language.IModInfo; import net.minecraftforge.forgespi.language.ModFileScanData; @@ -94,7 +94,7 @@ public class FMLModContainer extends ModContainer private void beforeEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent) { FMLModLoadingContext.get().setActiveContainer(this); - ModThreadContext.get().setActiveContainer(this); + ModLoadingContext.get().setActiveContainer(this); } private void fireEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent) { @@ -113,7 +113,7 @@ public class FMLModContainer extends ModContainer } private void afterEvent(LifecycleEventProvider.LifecycleEvent lifecycleEvent) { - ModThreadContext.get().setActiveContainer(null); + ModLoadingContext.get().setActiveContainer(null); FMLModLoadingContext.get().setActiveContainer(null); if (getCurrentState() == ModLoadingStage.ERROR) { LOGGER.error(LOADING,"An error occurred while dispatching event {} to {}", lifecycleEvent.fromStage(), getModId()); diff --git a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModLoadingContext.java b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModLoadingContext.java index 2c4459abf9..3a6cfd7605 100644 --- a/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModLoadingContext.java +++ b/src/main/java/net/minecraftforge/fml/javafmlmod/FMLModLoadingContext.java @@ -34,23 +34,26 @@ public class FMLModLoadingContext return context.get(); } - public void registerExtensionPoint(ExtensionPoint point, Supplier extension) { - getActiveContainer().registerExtensionPoint(point, extension); - } - public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec) { - activeContainer.addConfig(new ModConfig(type, spec, activeContainer)); + getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer())); } public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec, String fileName) { - activeContainer.addConfig(new ModConfig(type, spec, activeContainer, fileName)); + getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer(), fileName)); } + /** + * @return The mod's event bus, to allow subscription to Mod specific events + */ public IEventBus getModEventBus() { return getActiveContainer().getEventBus(); } + /** + * Only valid during {@link net.minecraftforge.fml.event.lifecycle.ModLifecycleEvent} dispatch and Mod construction + * @return the active FML container + */ public FMLModContainer getActiveContainer() { return activeContainer; diff --git a/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java b/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java index ab10cd9d15..34436eeb9d 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLPlayMessages.java @@ -19,20 +19,19 @@ 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.ExtensionPoint; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import java.util.UUID; -import java.util.function.Function; import java.util.function.Supplier; public class FMLPlayMessages @@ -166,9 +165,9 @@ public class FMLPlayMessages { private final ResourceLocation id; private final int windowId; - private final byte[] additionalData; + private final PacketBuffer additionalData; - public OpenContainer(ResourceLocation id, int windowId, byte[] additionalData) + OpenContainer(ResourceLocation id, int windowId, PacketBuffer additionalData) { this.id = id; this.windowId = windowId; @@ -179,27 +178,34 @@ public class FMLPlayMessages { buf.writeResourceLocation(msg.id); buf.writeVarInt(msg.windowId); - buf.writeByteArray(msg.additionalData); + buf.writeBytes(msg.additionalData); } public static OpenContainer decode(PacketBuffer buf) { - return new OpenContainer(buf.readResourceLocation(), buf.readVarInt(), buf.readByteArray()); + return new OpenContainer(buf.readResourceLocation(), buf.readVarInt(), new PacketBuffer(Unpooled.wrappedBuffer(buf.readByteArray(32600)))); } 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().enqueueWork(() -> ModList.get().getModContainerById(msg.id.getNamespace()).ifPresent(mc-> + mc.getCustomExtension(ExtensionPoint.GUIFACTORY).map(f -> f.apply(msg)).ifPresent(gui-> { + Minecraft.getInstance().displayGuiScreen(gui); + Minecraft.getInstance().player.openContainer.windowId = msg.windowId; + }))); ctx.get().setPacketHandled(true); } + + public final ResourceLocation getId() { + return this.id; + } + + public int getWindowId() { + return windowId; + } + + public PacketBuffer getAdditionalData() { + return additionalData; + } } } diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java index cb16e72243..20131bb7a5 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkHooks.java @@ -19,13 +19,14 @@ package net.minecraftforge.fml.network; -import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; 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.PacketBuffer; import net.minecraft.network.handshake.client.CPacketHandshake; import net.minecraft.server.network.NetHandlerLoginServer; import net.minecraft.util.ResourceLocation; @@ -87,10 +88,22 @@ public class NetworkHooks return FMLHandshakeHandler.tickLogin(networkManager); } - public static void openGui(EntityPlayerMP player, IInteractionObject container, @Nullable ByteBuf extraData) + /** + * Server method to tell the client to open a GUI on behalf of the server + * + * The {@link IInteractionObject#getGuiID()} is treated as a {@link ResourceLocation}. + * It should refer to a valid modId namespace, to trigger opening on the client. + * The namespace is directly used to lookup the modId in the client side. + * + * @param player The player to open the GUI for + * @param containerSupplier The Container Supplier + * @param extraData Additional data for the GUI + */ + public static void openGui(EntityPlayerMP player, IInteractionObject containerSupplier, @Nullable PacketBuffer extraData) { - ResourceLocation id = new ResourceLocation(container.getGuiID()); - Container c = container.createContainer(player.inventory, player); + if (player.world.isRemote) return; + ResourceLocation id = new ResourceLocation(containerSupplier.getGuiID()); + Container c = containerSupplier.createContainer(player.inventory, player); player.closeScreen(); player.getNextWindowId(); player.openContainer = c; @@ -98,14 +111,13 @@ public class NetworkHooks 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); + extraData = new PacketBuffer(Unpooled.buffer()); } - FMLPlayMessages.OpenContainer msg = new FMLPlayMessages.OpenContainer(id, player.currentWindowId, additional); + if (extraData.readableBytes() > 32600) { + throw new IllegalArgumentException("GUI Open packet too large : "+ extraData.readableBytes()); + } + FMLPlayMessages.OpenContainer msg = new FMLPlayMessages.OpenContainer(id, player.currentWindowId, extraData); 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 36e6717da9..41a60c4977 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java @@ -19,8 +19,6 @@ 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; @@ -34,10 +32,12 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; 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; @@ -51,21 +51,6 @@ 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 diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java index a9c3bf9b24..d259c3b66a 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java @@ -28,13 +28,12 @@ import java.util.Map; import java.util.Map.Entry; import javax.annotation.Nonnull; -import net.minecraftforge.fml.ModThreadContext; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.loading.AdvancedLogMessageAdapter; import org.apache.commons.lang3.Validate; import java.util.Set; -import java.util.stream.Collectors; import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; @@ -280,7 +279,7 @@ public class ForgeRegistry> implements IForgeRe int add(int id, V value) { - final String owner = ModThreadContext.get().getActiveContainer().getNamespace(); + final String owner = ModLoadingContext.get().getActiveContainer().getNamespace(); return add(id, value, owner); } diff --git a/src/main/java/net/minecraftforge/registries/GameData.java b/src/main/java/net/minecraftforge/registries/GameData.java index 24203a51da..7cdbd6b94e 100644 --- a/src/main/java/net/minecraftforge/registries/GameData.java +++ b/src/main/java/net/minecraftforge/registries/GameData.java @@ -42,7 +42,7 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent.MissingMappings; import net.minecraftforge.fml.LifecycleEventProvider; -import net.minecraftforge.fml.ModThreadContext; +import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.StartupQuery; import net.minecraftforge.fml.common.EnhancedRuntimeException; import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession; @@ -51,8 +51,6 @@ import net.minecraftforge.fml.loading.AdvancedLogMessageAdapter; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.MarkerManager; import javax.annotation.Nullable; import java.lang.reflect.Field; @@ -66,7 +64,6 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; -import static net.minecraftforge.fml.Logging.CORE; import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES; /** @@ -828,7 +825,7 @@ public class GameData int index = name.lastIndexOf(':'); String oldPrefix = index == -1 ? "" : name.substring(0, index).toLowerCase(Locale.ROOT); name = index == -1 ? name : name.substring(index + 1); - String prefix = ModThreadContext.get().getActiveContainer().getNamespace(); + String prefix = ModLoadingContext.get().getActiveContainer().getNamespace(); if (!oldPrefix.equals(prefix) && oldPrefix.length() > 0) { LogManager.getLogger().info("Potentially Dangerous alternative prefix `{}` for name `{}`, expected `{}`. This could be a intended override, but in most cases indicates a broken mod.", oldPrefix, name, prefix);