Allow third-party addons to register custom GUIs via GuiBridge (#402)

This commit is contained in:
Yang Xizhi
2024-05-24 20:05:29 +08:00
committed by GitHub
parent 529ea5e239
commit 07eb6c1238
3 changed files with 141 additions and 3 deletions
+22 -3
View File
@@ -43,7 +43,6 @@ import appeng.container.AEBaseContainer;
import appeng.container.ContainerNull;
import appeng.container.ContainerOpenContext;
import appeng.container.implementations.*;
import appeng.container.interfaces.IInventorySlotAware;
import appeng.fluids.container.*;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.parts.PartFluidFormationPlane;
@@ -59,11 +58,20 @@ import appeng.parts.automation.PartFormationPlane;
import appeng.parts.automation.PartLevelEmitter;
import appeng.parts.misc.PartOreDicStorageBus;
import appeng.parts.misc.PartStorageBus;
import appeng.parts.reporting.*;
import appeng.parts.reporting.PartCraftingTerminal;
import appeng.parts.reporting.PartExpandedProcessingPatternTerminal;
import appeng.parts.reporting.PartFluidInterfaceConfigurationTerminal;
import appeng.parts.reporting.PartInterfaceConfigurationTerminal;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.parts.reporting.PartPatternTerminal;
import appeng.tile.crafting.TileCraftingTile;
import appeng.tile.crafting.TileMolecularAssembler;
import appeng.tile.grindstone.TileGrinder;
import appeng.tile.misc.*;
import appeng.tile.misc.TileCellWorkbench;
import appeng.tile.misc.TileCondenser;
import appeng.tile.misc.TileInscriber;
import appeng.tile.misc.TileSecurityStation;
import appeng.tile.misc.TileVibrationChamber;
import appeng.tile.networking.TileWireless;
import appeng.tile.qnb.TileQuantumBridge;
import appeng.tile.spatial.TileSpatialIOPort;
@@ -185,6 +193,7 @@ public enum GuiBridge implements IGuiHandler {
private Class guiClass;
private GuiHostType type;
private SecurityPermissions requiredPermission;
private GuiWrapper.IExternalGui externalGui = null;
GuiBridge() {
this.tileClass = null;
@@ -192,6 +201,16 @@ public enum GuiBridge implements IGuiHandler {
this.containerClass = null;
}
GuiBridge(GuiWrapper.IExternalGui obj) {
this.tileClass = null;
this.containerClass = null;
this.externalGui = obj;
}
public GuiWrapper.IExternalGui getExternalGui() {
return this.externalGui;
}
GuiBridge(final Class containerClass, final SecurityPermissions requiredPermission) {
this.requiredPermission = requiredPermission;
this.containerClass = containerClass;
@@ -0,0 +1,90 @@
package appeng.core.sync;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.EnumHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Allow to register custom GuiBridge from third-party
*/
public class GuiWrapper {
public static final GuiWrapper INSTANCE = new GuiWrapper();
private GuiWrapper() {
// NO-OP
}
private final Object2ObjectMap<ResourceLocation, Opener> openers = new Object2ObjectOpenHashMap<>();
private final Object2ObjectMap<IExternalGui, GuiBridge> externalGuis = new Object2ObjectOpenCustomHashMap<>(new Hash.Strategy<IExternalGui>() {
@Override
public int hashCode(IExternalGui o) {
return o.getID().hashCode();
}
@Override
public boolean equals(@Nullable IExternalGui a, @Nullable IExternalGui b) {
return a == b || (a != null && b != null && a.getID().equals(b.getID()));
}
});
public synchronized void registerExternalGuiHandler(@Nonnull ResourceLocation id, @Nonnull Opener opener) {
openers.put(id, opener);
}
@Nullable
public Opener getOpener(ResourceLocation id) {
return openers.get(id);
}
public GuiBridge wrap(IExternalGui obj) {
return externalGuis.computeIfAbsent(obj, this::create);
}
private GuiBridge create(IExternalGui obj) {
return EnumHelper.addEnum(GuiBridge.class, obj.getID().toString(), new Class<?>[] {IExternalGui.class}, obj);
}
@FunctionalInterface
public interface Opener {
<T extends IExternalGui> void open(T obj, GuiContext context);
}
public interface IExternalGui {
ResourceLocation getID();
}
public static class GuiContext {
public final World world;
public final EntityPlayer player;
public final BlockPos pos;
public final EnumFacing facing;
public final NBTTagCompound extra;
public GuiContext(World world, EntityPlayer player, BlockPos pos, EnumFacing face, NBTTagCompound extra) {
this.world = world;
this.player = player;
this.pos = pos;
this.facing = face;
this.extra = extra;
}
}
}
+29
View File
@@ -53,6 +53,7 @@ import appeng.core.features.AEFeature;
import appeng.core.stats.Stats;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.GuiHostType;
import appeng.core.sync.GuiWrapper;
import appeng.fluids.util.AEFluidStack;
import appeng.hooks.TickHandler;
import appeng.integration.Integrations;
@@ -323,6 +324,20 @@ public class Platform {
return;
}
if (type.getExternalGui() != null) {
GuiWrapper.IExternalGui obj = type.getExternalGui();
GuiWrapper.Opener opener = GuiWrapper.INSTANCE.getOpener(obj.getID());
if (opener == null) {
AELog.warn("External Gui with ID: %s is missing a opener.", obj.getID());
} else {
World world = tile == null ? p.world : tile.getWorld();
BlockPos pos = tile == null ? null : tile.getPos();
EnumFacing face = side == null ? null : side.getFacing();
opener.open(obj, new GuiWrapper.GuiContext(world, p, pos, face, null));
}
return;
}
int x = 0;
int y = 0;
int z = Integer.MIN_VALUE;
@@ -360,6 +375,20 @@ public class Platform {
return;
}
if (type.getExternalGui() != null) {
GuiWrapper.IExternalGui obj = type.getExternalGui();
GuiWrapper.Opener opener = GuiWrapper.INSTANCE.getOpener(obj.getID());
if (opener == null) {
AELog.warn("External Gui with ID: %s is missing a opener.", obj.getID());
} else {
NBTTagCompound extra = new NBTTagCompound();
extra.setInteger("slot", slot);
extra.setBoolean("isBauble", isBauble);
opener.open(obj, new GuiWrapper.GuiContext(p.world, p, null, null, extra));
}
return;
}
if (type.getType().isItem()) {
p.openGui(AppEng.instance(), type.ordinal() << 4, p.getEntityWorld(), slot, isBauble ? 1 : 0, Integer.MIN_VALUE);
}