Implement a GUI packet and GUIFACTORY for triggering from the server.
Signed-off-by: cpw <cpw+github@weeksfamily.ca>
This commit is contained in:
parent
31c0a70f8e
commit
586c24f9d6
12 changed files with 98 additions and 74 deletions
|
@ -109,7 +109,7 @@ public class DeferredWorkQueue
|
|||
* @return A {@link CompletableFuture} that completes at said time
|
||||
*/
|
||||
public static CompletableFuture<Void> 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 <T> CompletableFuture<T> getLater(Supplier<T> workToEnqueue) {
|
||||
currentOwner.set(ModThreadContext.get().getActiveContainer());
|
||||
currentOwner.set(ModLoadingContext.get().getActiveContainer());
|
||||
return CompletableFuture.supplyAsync(workToEnqueue, deferredExecutor).exceptionally(DeferredWorkQueue.handleException());
|
||||
}
|
||||
|
||||
|
|
|
@ -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<T>
|
||||
{
|
||||
public static final ExtensionPoint<BiFunction<Minecraft, GuiScreen, GuiScreen>> GUIFACTORY = new ExtensionPoint<>();
|
||||
public static final ExtensionPoint<BiFunction<Minecraft, GuiScreen, GuiScreen>> CONFIGGUIFACTORY = new ExtensionPoint<>();
|
||||
public static final ExtensionPoint<BiFunction<Minecraft, ModFileResourcePack, IResourcePack>> RESOURCEPACK = new ExtensionPoint<>();
|
||||
|
||||
/**
|
||||
* Register with {@link ModLoadingContext#}
|
||||
*/
|
||||
public static final ExtensionPoint<Function<FMLPlayMessages.OpenContainer, GuiScreen>> GUIFACTORY = new ExtensionPoint<>();
|
||||
|
||||
|
||||
private Class<T> type;
|
||||
|
||||
private ExtensionPoint() {
|
||||
|
|
|
@ -115,11 +115,11 @@ public abstract class ModContainer
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Optional<T> getCustomExtension(ExtensionPoint point) {
|
||||
public <T> Optional<T> getCustomExtension(ExtensionPoint<T> point) {
|
||||
return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get());
|
||||
}
|
||||
|
||||
public <T> void registerExtensionPoint(ExtensionPoint point, Supplier<T> extension)
|
||||
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension)
|
||||
{
|
||||
extensionPoints.put(point, extension);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
|
||||
package net.minecraftforge.fml;
|
||||
|
||||
public class ModThreadContext
|
||||
{
|
||||
private static ThreadLocal<ModThreadContext> context = ThreadLocal.withInitial(ModThreadContext::new);
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public static ModThreadContext get() {
|
||||
public class ModLoadingContext
|
||||
{
|
||||
private static ThreadLocal<ModLoadingContext> 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 <T> The type signature of the extension operator
|
||||
*/
|
||||
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension) {
|
||||
getActiveContainer().registerExtensionPoint(point, extension);
|
||||
}
|
||||
|
||||
}
|
|
@ -33,6 +33,6 @@ public class ConfigGuiHandler
|
|||
public static Optional<BiFunction<Minecraft, GuiScreen, GuiScreen>> getGuiFactoryFor(ModInfo selectedMod)
|
||||
{
|
||||
return ModList.get().getModContainerById(selectedMod.getModId()).
|
||||
flatMap(mc -> mc.getCustomExtension(ExtensionPoint.GUIFACTORY));
|
||||
flatMap(mc -> mc.getCustomExtension(ExtensionPoint.CONFIGGUIFACTORY));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -34,23 +34,26 @@ public class FMLModLoadingContext
|
|||
return context.get();
|
||||
}
|
||||
|
||||
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> 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;
|
||||
|
|
|
@ -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<NetworkEvent.Context> ctx)
|
||||
{
|
||||
ctx.get().enqueueWork(() -> {
|
||||
Supplier<Function<ByteBuf, GuiScreen>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ResourceLocation, NetworkInstance> instances = new HashMap<>();
|
||||
static final Map<ResourceLocation, Supplier<Function<ByteBuf, GuiScreen>>> 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<Function<ByteBuf, GuiScreen>> handler)
|
||||
{
|
||||
guiHandlers.put(id, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special value for clientAcceptedVersions and serverAcceptedVersions predicates indicating the other side lacks
|
||||
|
|
|
@ -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<V extends IForgeRegistryEntry<V>> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue