/* * 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 . */ 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.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.network.IGuiHandler; import net.minecraftforge.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.AEPartLocation; import appeng.api.util.DimensionalCoord; import appeng.client.gui.AEBaseGui; 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.ContainerSecurityStation; 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.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.TileSecurityStation; 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( ContainerSecurityStation.class, TileSecurityStation.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( final Class containerClass, final 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() ) { AEBaseGui.class.getName(); final String start = this.containerClass.getName(); final 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( final Class containerClass, final Class tileClass, final GuiHostType type, final SecurityPermissions requiredPermission ) { this.requiredPermission = requiredPermission; this.containerClass = containerClass; this.type = type; this.tileClass = tileClass; this.getGui(); } @Override public Object getServerGuiElement( final int ordinal, final EntityPlayer player, final World w, final int x, final int y, final int z ) { final AEPartLocation side = AEPartLocation.fromOrdinal( ordinal & 0x07 ); final GuiBridge ID = values()[ordinal >> 4]; final 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 ); } final 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() ) { final TileEntity TE = w.getTileEntity( new BlockPos( x, y, z ) ); if( TE instanceof IPartHost ) { ( (IPartHost) TE ).getPart( side ); final 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( final ItemStack it, final EntityPlayer player, final World w, final int x, final int y, final int z ) { if( it != null ) { if( it.getItem() instanceof IGuiItem ) { return ( (IGuiItem) it.getItem() ).getGuiObject( it, w, new BlockPos( x, y, z ) ); } final 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( final Object tE ) { if( this.tileClass == null ) { throw new IllegalArgumentException( "This Gui Cannot use the standard Handler." ); } return this.tileClass.isInstance( tE ); } private Object updateGui( final Object newContainer, final World w, final int x, final int y, final int z, final AEPartLocation side, final Object myItem ) { if( newContainer instanceof AEBaseContainer ) { final AEBaseContainer bc = (AEBaseContainer) newContainer; bc.setOpenContext( new ContainerOpenContext( myItem ) ); bc.getOpenContext().setWorld( w ); bc.getOpenContext().setX( x ); bc.getOpenContext().setY( y ); bc.getOpenContext().setZ( z ); bc.getOpenContext().setSide( side ); } return newContainer; } public Object ConstructContainer( final InventoryPlayer inventory, final AEPartLocation side, final Object tE ) { try { final Constructor[] c = this.containerClass.getConstructors(); if( c.length == 0 ) { throw new AppEngException( "Invalid Gui Class" ); } final Constructor target = this.findConstructor( c, inventory, tE ); if( target == null ) { throw new IllegalStateException( "Cannot find " + this.containerClass.getName() + "( " + this.typeName( inventory ) + ", " + this.typeName( tE ) + " )" ); } final Object o = target.newInstance( inventory, tE ); /** * triggers achievement when the player sees presses. */ if( o instanceof AEBaseContainer ) { final AEBaseContainer bc = (AEBaseContainer) o; for( final Object so : bc.inventorySlots ) { if( so instanceof Slot ) { final ItemStack is = ( (Slot) so ).getStack(); final IMaterials materials = AEApi.instance().definitions().materials(); this.addPressAchievementToPlayer( is, materials, inventory.player ); } } } return o; } catch( final Throwable t ) { throw new IllegalStateException( t ); } } private Constructor findConstructor( final Constructor[] c, final InventoryPlayer inventory, final Object tE ) { for( final Constructor con : c ) { final 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( final Object inventory ) { if( inventory == null ) { return "NULL"; } return inventory.getClass().getName(); } private void addPressAchievementToPlayer( final ItemStack newItem, final IMaterials possibleMaterials, final EntityPlayer player ) { final IComparableDefinition logic = possibleMaterials.logicProcessorPress(); final IComparableDefinition eng = possibleMaterials.engProcessorPress(); final IComparableDefinition calc = possibleMaterials.calcProcessorPress(); final IComparableDefinition silicon = possibleMaterials.siliconPress(); final List presses = Lists.newArrayList( logic, eng, calc, silicon ); for( final IComparableDefinition press : presses ) { if( press.isSameAs( newItem ) ) { Achievements.Presses.addToPlayer( player ); return; } } } @Override public Object getClientGuiElement( final int ordinal, final EntityPlayer player, final World w, final int x, final int y, final int z ) { final AEPartLocation side = AEPartLocation.fromOrdinal( ordinal & 0x07 ); final GuiBridge ID = values()[ordinal >> 4]; final 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 ); } final 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() ) { final TileEntity TE = w.getTileEntity( new BlockPos( x, y, z ) ); if( TE instanceof IPartHost ) { ( (IPartHost) TE ).getPart( side ); final 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( final InventoryPlayer inventory, final AEPartLocation side, final Object tE ) { try { final Constructor[] c = this.guiClass.getConstructors(); if( c.length == 0 ) { throw new AppEngException( "Invalid Gui Class" ); } final 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( final Throwable t ) { throw new IllegalStateException( t ); } } public boolean hasPermissions( final TileEntity te, final int x, final int y, final int z, final AEPartLocation side, final EntityPlayer player ) { final World w = player.getEntityWorld(); final BlockPos pos = new BlockPos( x, y, z ); if( Platform.hasPermissions( te != null ? new DimensionalCoord( te ) : new DimensionalCoord( player.worldObj, pos ), player ) ) { if( this.type.isItem() ) { final ItemStack it = player.inventory.getCurrentItem(); if( it != null && it.getItem() instanceof IGuiItem ) { final Object myItem = ( (IGuiItem) it.getItem() ).getGuiObject( it, w, pos ); if( this.CorrectTileOrPart( myItem ) ) { return true; } } } if( this.type.isTile() ) { final TileEntity TE = w.getTileEntity( pos ); if( TE instanceof IPartHost ) { ( (IPartHost) TE ).getPart( side ); final 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( final Object te, final EntityPlayer player ) { if( te instanceof IActionHost && this.requiredPermission != null ) { final IGridNode gn = ( (IActionHost) te ).getActionableNode(); if( gn != null ) { final IGrid g = gn.getGrid(); if( g != null ) { final boolean requirePower = false; if( requirePower ) { final IEnergyGrid eg = g.getCache( IEnergyGrid.class ); if( !eg.isNetworkPowered() ) { return false; } } final ISecurityGrid sg = g.getCache( ISecurityGrid.class ); if( sg.hasPermission( player, this.requiredPermission ) ) { return true; } } } return false; } return true; } public GuiHostType getType() { return this.type; } }