Applied-Energistics-2-tiler.../src/main/java/appeng/core/sync/GuiBridge.java
yueh 5aaaeb6d42 Closes #12 Added visual lock state to monitors
Some general refactoring of every monitor including panels and terminals.
Disabled glPushAttrib and glPopAttrib for StorageMonitor as this can be a
performance issue.
2015-06-06 17:00:52 +02:00

584 lines
19 KiB
Java

/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.sync;
import java.lang.reflect.Constructor;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.network.IGuiHandler;
import cpw.mods.fml.relauncher.ReflectionHelper;
import appeng.api.AEApi;
import appeng.api.config.SecurityPermissions;
import appeng.api.definitions.IComparableDefinition;
import appeng.api.definitions.IMaterials;
import appeng.api.exceptions.AppEngException;
import appeng.api.features.IWirelessTermHandler;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.implementations.guiobjects.IGuiItem;
import appeng.api.implementations.guiobjects.INetworkTool;
import appeng.api.implementations.guiobjects.IPortableCell;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergyGrid;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.ISecurityGrid;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartHost;
import appeng.api.storage.ITerminalHost;
import appeng.api.util.DimensionalCoord;
import appeng.client.gui.GuiNull;
import appeng.container.AEBaseContainer;
import appeng.container.ContainerNull;
import appeng.container.ContainerOpenContext;
import appeng.container.implementations.ContainerCellWorkbench;
import appeng.container.implementations.ContainerChest;
import appeng.container.implementations.ContainerCondenser;
import appeng.container.implementations.ContainerCraftAmount;
import appeng.container.implementations.ContainerCraftConfirm;
import appeng.container.implementations.ContainerCraftingCPU;
import appeng.container.implementations.ContainerCraftingStatus;
import appeng.container.implementations.ContainerCraftingTerm;
import appeng.container.implementations.ContainerDrive;
import appeng.container.implementations.ContainerFormationPlane;
import appeng.container.implementations.ContainerGrinder;
import appeng.container.implementations.ContainerIOPort;
import appeng.container.implementations.ContainerInscriber;
import appeng.container.implementations.ContainerInterface;
import appeng.container.implementations.ContainerInterfaceTerminal;
import appeng.container.implementations.ContainerLevelEmitter;
import appeng.container.implementations.ContainerMAC;
import appeng.container.implementations.ContainerMEMonitorable;
import appeng.container.implementations.ContainerMEPortableCell;
import appeng.container.implementations.ContainerNetworkStatus;
import appeng.container.implementations.ContainerNetworkTool;
import appeng.container.implementations.ContainerPatternTerm;
import appeng.container.implementations.ContainerPriority;
import appeng.container.implementations.ContainerQNB;
import appeng.container.implementations.ContainerQuartzKnife;
import appeng.container.implementations.ContainerSecurity;
import appeng.container.implementations.ContainerSkyChest;
import appeng.container.implementations.ContainerSpatialIOPort;
import appeng.container.implementations.ContainerStorageBus;
import appeng.container.implementations.ContainerUpgradeable;
import appeng.container.implementations.ContainerVibrationChamber;
import appeng.container.implementations.ContainerWireless;
import appeng.container.implementations.ContainerWirelessTerm;
import appeng.core.stats.Achievements;
import appeng.helpers.IInterfaceHost;
import appeng.helpers.IPriorityHost;
import appeng.helpers.WirelessTerminalGuiObject;
import appeng.items.contents.QuartzKnifeObj;
import appeng.parts.automation.PartFormationPlane;
import appeng.parts.automation.PartLevelEmitter;
import appeng.parts.misc.PartStorageBus;
import appeng.parts.reporting.PartCraftingTerminal;
import appeng.parts.reporting.PartInterfaceTerminal;
import appeng.parts.reporting.PartPanel;
import appeng.parts.reporting.PartPatternTerminal;
import appeng.tile.crafting.TileCraftingTile;
import appeng.tile.crafting.TileMolecularAssembler;
import appeng.tile.grindstone.TileGrinder;
import appeng.tile.misc.TileCellWorkbench;
import appeng.tile.misc.TileCondenser;
import appeng.tile.misc.TileInscriber;
import appeng.tile.misc.TileSecurity;
import appeng.tile.misc.TileVibrationChamber;
import appeng.tile.networking.TileWireless;
import appeng.tile.qnb.TileQuantumBridge;
import appeng.tile.spatial.TileSpatialIOPort;
import appeng.tile.storage.TileChest;
import appeng.tile.storage.TileDrive;
import appeng.tile.storage.TileIOPort;
import appeng.tile.storage.TileSkyChest;
import appeng.util.Platform;
public enum GuiBridge implements IGuiHandler
{
GUI_Handler(),
GUI_GRINDER( ContainerGrinder.class, TileGrinder.class, GuiHostType.WORLD, null ),
GUI_QNB( ContainerQNB.class, TileQuantumBridge.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_SKYCHEST( ContainerSkyChest.class, TileSkyChest.class, GuiHostType.WORLD, null ),
GUI_CHEST( ContainerChest.class, TileChest.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_WIRELESS( ContainerWireless.class, TileWireless.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_ME( ContainerMEMonitorable.class, ITerminalHost.class, GuiHostType.WORLD, null ),
GUI_PORTABLE_CELL( ContainerMEPortableCell.class, IPortableCell.class, GuiHostType.ITEM, null ),
GUI_WIRELESS_TERM( ContainerWirelessTerm.class, WirelessTerminalGuiObject.class, GuiHostType.ITEM, null ),
GUI_NETWORK_STATUS( ContainerNetworkStatus.class, INetworkTool.class, GuiHostType.ITEM, null ),
GUI_CRAFTING_CPU( ContainerCraftingCPU.class, TileCraftingTile.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ),
GUI_NETWORK_TOOL( ContainerNetworkTool.class, INetworkTool.class, GuiHostType.ITEM, null ),
GUI_QUARTZ_KNIFE( ContainerQuartzKnife.class, QuartzKnifeObj.class, GuiHostType.ITEM, null ),
GUI_DRIVE( ContainerDrive.class, TileDrive.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_VIBRATION_CHAMBER( ContainerVibrationChamber.class, TileVibrationChamber.class, GuiHostType.WORLD, null ),
GUI_CONDENSER( ContainerCondenser.class, TileCondenser.class, GuiHostType.WORLD, null ),
GUI_INTERFACE( ContainerInterface.class, IInterfaceHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_BUS( ContainerUpgradeable.class, IUpgradeableHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_IOPORT( ContainerIOPort.class, TileIOPort.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_STORAGEBUS( ContainerStorageBus.class, PartStorageBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_FORMATION_PLANE( ContainerFormationPlane.class, PartFormationPlane.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_PRIORITY( ContainerPriority.class, IPriorityHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_SECURITY( ContainerSecurity.class, TileSecurity.class, GuiHostType.WORLD, SecurityPermissions.SECURITY ),
GUI_CRAFTING_TERMINAL( ContainerCraftingTerm.class, PartCraftingTerminal.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ),
GUI_PATTERN_TERMINAL( ContainerPatternTerm.class, PartPatternTerminal.class, GuiHostType.WORLD, SecurityPermissions.CRAFT ),
// extends (Container/Gui) + Bus
GUI_LEVEL_EMITTER( ContainerLevelEmitter.class, PartLevelEmitter.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_SPATIAL_IO_PORT( ContainerSpatialIOPort.class, TileSpatialIOPort.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_INSCRIBER( ContainerInscriber.class, TileInscriber.class, GuiHostType.WORLD, null ),
GUI_CELL_WORKBENCH( ContainerCellWorkbench.class, TileCellWorkbench.class, GuiHostType.WORLD, null ),
GUI_MAC( ContainerMAC.class, TileMolecularAssembler.class, GuiHostType.WORLD, null ),
GUI_CRAFTING_AMOUNT( ContainerCraftAmount.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD, SecurityPermissions.CRAFT ),
GUI_CRAFTING_CONFIRM( ContainerCraftConfirm.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD, SecurityPermissions.CRAFT ),
GUI_INTERFACE_TERMINAL( ContainerInterfaceTerminal.class, PartInterfaceTerminal.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_CRAFTING_STATUS( ContainerCraftingStatus.class, ITerminalHost.class, GuiHostType.ITEM_OR_WORLD, SecurityPermissions.CRAFT );
private final Class tileClass;
private final Class containerClass;
private Class guiClass;
private GuiHostType type;
private SecurityPermissions requiredPermission;
GuiBridge()
{
this.tileClass = null;
this.guiClass = null;
this.containerClass = null;
}
GuiBridge( Class containerClass, SecurityPermissions requiredPermission )
{
this.requiredPermission = requiredPermission;
this.containerClass = containerClass;
this.tileClass = null;
this.getGui();
}
/**
* I honestly wish I could just use the GuiClass Names myself, but I can't access them without MC's Server
* Exploding.
*/
private void getGui()
{
if( Platform.isClient() )
{
final String start = this.containerClass.getName();
String guiClass = start.replaceFirst( "container.", "client.gui." ).replace( ".Container", ".Gui" );
if( start.equals( guiClass ) )
{
throw new IllegalStateException( "Unable to find gui class" );
}
this.guiClass = ReflectionHelper.getClass( this.getClass().getClassLoader(), guiClass );
if( this.guiClass == null )
{
throw new IllegalStateException( "Cannot Load class: " + guiClass );
}
}
}
GuiBridge( Class containerClass, Class tileClass, GuiHostType type, SecurityPermissions requiredPermission )
{
this.requiredPermission = requiredPermission;
this.containerClass = containerClass;
this.type = type;
this.tileClass = tileClass;
this.getGui();
}
@Override
public Object getServerGuiElement( int ordinal, EntityPlayer player, World w, int x, int y, int z )
{
ForgeDirection side = ForgeDirection.getOrientation( ordinal & 0x07 );
GuiBridge ID = values()[ordinal >> 4];
boolean stem = ( ( ordinal >> 3 ) & 1 ) == 1;
if( ID.type.isItem() )
{
ItemStack it = null;
if( stem )
{
it = player.inventory.getCurrentItem();
}
else if( x >= 0 && x < player.inventory.mainInventory.length )
{
it = player.inventory.getStackInSlot( x );
}
Object myItem = this.getGuiObject( it, player, w, x, y, z );
if( myItem != null && ID.CorrectTileOrPart( myItem ) )
{
return this.updateGui( ID.ConstructContainer( player.inventory, side, myItem ), w, x, y, z, side, myItem );
}
}
if( ID.type.isTile() )
{
TileEntity TE = w.getTileEntity( x, y, z );
if( TE instanceof IPartHost )
{
( (IPartHost) TE ).getPart( side );
IPart part = ( (IPartHost) TE ).getPart( side );
if( ID.CorrectTileOrPart( part ) )
{
return this.updateGui( ID.ConstructContainer( player.inventory, side, part ), w, x, y, z, side, part );
}
}
else
{
if( ID.CorrectTileOrPart( TE ) )
{
return this.updateGui( ID.ConstructContainer( player.inventory, side, TE ), w, x, y, z, side, TE );
}
}
}
return new ContainerNull();
}
private Object getGuiObject( ItemStack it, EntityPlayer player, World w, int x, int y, int z )
{
if( it != null )
{
if( it.getItem() instanceof IGuiItem )
{
return ( (IGuiItem) it.getItem() ).getGuiObject( it, w, x, y, z );
}
IWirelessTermHandler wh = AEApi.instance().registries().wireless().getWirelessTerminalHandler( it );
if( wh != null )
{
return new WirelessTerminalGuiObject( wh, it, player, w, x, y, z );
}
}
return null;
}
public boolean CorrectTileOrPart( Object tE )
{
if( this.tileClass == null )
{
throw new IllegalArgumentException( "This Gui Cannot use the standard Handler." );
}
return this.tileClass.isInstance( tE );
}
private Object updateGui( Object newContainer, World w, int x, int y, int z, ForgeDirection side, Object myItem )
{
if( newContainer instanceof AEBaseContainer )
{
AEBaseContainer bc = (AEBaseContainer) newContainer;
bc.openContext = new ContainerOpenContext( myItem );
bc.openContext.w = w;
bc.openContext.x = x;
bc.openContext.y = y;
bc.openContext.z = z;
bc.openContext.side = side;
}
return newContainer;
}
public Object ConstructContainer( InventoryPlayer inventory, ForgeDirection side, Object tE )
{
try
{
Constructor[] c = this.containerClass.getConstructors();
if( c.length == 0 )
{
throw new AppEngException( "Invalid Gui Class" );
}
Constructor target = this.findConstructor( c, inventory, tE );
if( target == null )
{
throw new IllegalStateException( "Cannot find " + this.containerClass.getName() + "( " + this.typeName( inventory ) + ", " + this.typeName( tE ) + " )" );
}
Object o = target.newInstance( inventory, tE );
/**
* triggers achievement when the player sees presses.
*/
if( o instanceof AEBaseContainer )
{
AEBaseContainer bc = (AEBaseContainer) o;
for( Object so : bc.inventorySlots )
{
if( so instanceof Slot )
{
ItemStack is = ( (Slot) so ).getStack();
final IMaterials materials = AEApi.instance().definitions().materials();
this.addPressAchievementToPlayer( is, materials, inventory.player );
}
}
}
return o;
}
catch( Throwable t )
{
throw new IllegalStateException( t );
}
}
private Constructor findConstructor( Constructor[] c, InventoryPlayer inventory, Object tE )
{
for( Constructor con : c )
{
Class[] types = con.getParameterTypes();
if( types.length == 2 )
{
if( types[0].isAssignableFrom( inventory.getClass() ) && types[1].isAssignableFrom( tE.getClass() ) )
{
return con;
}
}
}
return null;
}
private String typeName( Object inventory )
{
if( inventory == null )
{
return "NULL";
}
return inventory.getClass().getName();
}
private void addPressAchievementToPlayer( ItemStack newItem, IMaterials possibleMaterials, EntityPlayer player )
{
final IComparableDefinition logic = possibleMaterials.logicProcessorPress();
final IComparableDefinition eng = possibleMaterials.engProcessorPress();
final IComparableDefinition calc = possibleMaterials.calcProcessorPress();
final IComparableDefinition silicon = possibleMaterials.siliconPress();
final List<IComparableDefinition> presses = Lists.newArrayList( logic, eng, calc, silicon );
for( IComparableDefinition press : presses )
{
if( press.isSameAs( newItem ) )
{
Achievements.Presses.addToPlayer( player );
return;
}
}
}
@Override
public Object getClientGuiElement( int ordinal, EntityPlayer player, World w, int x, int y, int z )
{
ForgeDirection side = ForgeDirection.getOrientation( ordinal & 0x07 );
GuiBridge ID = values()[ordinal >> 4];
boolean stem = ( ( ordinal >> 3 ) & 1 ) == 1;
if( ID.type.isItem() )
{
ItemStack it = null;
if( stem )
{
it = player.inventory.getCurrentItem();
}
else if( x >= 0 && x < player.inventory.mainInventory.length )
{
it = player.inventory.getStackInSlot( x );
}
Object myItem = this.getGuiObject( it, player, w, x, y, z );
if( myItem != null && ID.CorrectTileOrPart( myItem ) )
{
return ID.ConstructGui( player.inventory, side, myItem );
}
}
if( ID.type.isTile() )
{
TileEntity TE = w.getTileEntity( x, y, z );
if( TE instanceof IPartHost )
{
( (IPartHost) TE ).getPart( side );
IPart part = ( (IPartHost) TE ).getPart( side );
if( ID.CorrectTileOrPart( part ) )
{
return ID.ConstructGui( player.inventory, side, part );
}
}
else
{
if( ID.CorrectTileOrPart( TE ) )
{
return ID.ConstructGui( player.inventory, side, TE );
}
}
}
return new GuiNull( new ContainerNull() );
}
public Object ConstructGui( InventoryPlayer inventory, ForgeDirection side, Object tE )
{
try
{
Constructor[] c = this.guiClass.getConstructors();
if( c.length == 0 )
{
throw new AppEngException( "Invalid Gui Class" );
}
Constructor target = this.findConstructor( c, inventory, tE );
if( target == null )
{
throw new IllegalStateException( "Cannot find " + this.containerClass.getName() + "( " + this.typeName( inventory ) + ", " + this.typeName( tE ) + " )" );
}
return target.newInstance( inventory, tE );
}
catch( Throwable t )
{
throw new IllegalStateException( t );
}
}
public boolean hasPermissions( TileEntity te, int x, int y, int z, ForgeDirection side, EntityPlayer player )
{
World w = player.getEntityWorld();
if( Platform.hasPermissions( te != null ? new DimensionalCoord( te ) : new DimensionalCoord( player.worldObj, x, y, z ), player ) )
{
if( this.type.isItem() )
{
ItemStack it = player.inventory.getCurrentItem();
if( it != null && it.getItem() instanceof IGuiItem )
{
Object myItem = ( (IGuiItem) it.getItem() ).getGuiObject( it, w, x, y, z );
if( this.CorrectTileOrPart( myItem ) )
{
return true;
}
}
}
if( this.type.isTile() )
{
TileEntity TE = w.getTileEntity( x, y, z );
if( TE instanceof IPartHost )
{
( (IPartHost) TE ).getPart( side );
IPart part = ( (IPartHost) TE ).getPart( side );
if( this.CorrectTileOrPart( part ) )
{
return this.securityCheck( part, player );
}
}
else
{
if( this.CorrectTileOrPart( TE ) )
{
return this.securityCheck( TE, player );
}
}
}
}
return false;
}
private boolean securityCheck( Object te, EntityPlayer player )
{
if( te instanceof IActionHost && this.requiredPermission != null )
{
boolean requirePower = false;
IGridNode gn = ( (IActionHost) te ).getActionableNode();
if( gn != null )
{
IGrid g = gn.getGrid();
if( g != null )
{
if( requirePower )
{
IEnergyGrid eg = g.getCache( IEnergyGrid.class );
if( !eg.isNetworkPowered() )
{
return false;
}
}
ISecurityGrid sg = g.getCache( ISecurityGrid.class );
if( sg.hasPermission( player, this.requiredPermission ) )
{
return true;
}
}
}
return false;
}
return true;
}
public GuiHostType getType()
{
return this.type;
}
}