From 4829ec8286d16e1d3fe50c6f54fa2065c332e6e4 Mon Sep 17 00:00:00 2001 From: Serenibyss <10861407+serenibyss@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:52:05 -0600 Subject: [PATCH] Remove part layer api in favor of capabilities (#355) --- .../java/appeng/api/parts/IPartHelper.java | 26 -- src/api/java/appeng/api/parts/IPartHost.java | 9 +- src/api/java/appeng/api/parts/LayerBase.java | 98 ------ src/api/java/appeng/api/parts/LayerFlags.java | 35 --- .../block/networking/BlockCableBus.java | 23 +- src/main/java/appeng/core/api/ApiPart.java | 293 ------------------ .../java/appeng/parts/CableBusContainer.java | 6 - .../appeng/tile/networking/TileCableBus.java | 9 +- .../tile/networking/TileCableBusTESR.java | 5 +- 9 files changed, 8 insertions(+), 496 deletions(-) delete mode 100644 src/api/java/appeng/api/parts/LayerBase.java delete mode 100644 src/api/java/appeng/api/parts/LayerFlags.java diff --git a/src/api/java/appeng/api/parts/IPartHelper.java b/src/api/java/appeng/api/parts/IPartHelper.java index d8ed38ff6..d38272be5 100644 --- a/src/api/java/appeng/api/parts/IPartHelper.java +++ b/src/api/java/appeng/api/parts/IPartHelper.java @@ -35,32 +35,6 @@ import net.minecraft.world.World; public interface IPartHelper { - /** - * Register a new layer with the part layer system, this allows you to write an in between between tile entities and - * parts. - * - * AE By Default includes, - * - * 1. ISidedInventory ( and by extension IInventory. ) - * - * 2. IFluidHandler Forge Fluids - * - * 3. IPowerEmitter BC Power output. - * - * 4. IPowerReceptor BC Power input. - * - * 5. IEnergySink IC2 Power input. - * - * 6. IEnergySource IC2 Power output. - * - * 7. IPipeConnection BC Pipe Connections - * - * As long as a valid layer is registered for a interface you can simply implement that interface on a part get - * implement it. - * - * @return true on success, false on failure, usually a error will be logged as well. - */ - boolean registerNewLayer( String string, String layerInterface ); /** * use in use item, to try and place a IBusItem diff --git a/src/api/java/appeng/api/parts/IPartHost.java b/src/api/java/appeng/api/parts/IPartHost.java index a8e0c8581..f9c05fcf9 100644 --- a/src/api/java/appeng/api/parts/IPartHost.java +++ b/src/api/java/appeng/api/parts/IPartHost.java @@ -151,7 +151,7 @@ public interface IPartHost extends ICustomCableConnection void markForSave(); /** - * part of the {@link LayerBase} + * called when parts are added or removed */ void partChanged(); @@ -169,11 +169,6 @@ public interface IPartHost extends ICustomCableConnection */ boolean isEmpty(); - /** - * @return a mutable list of flags you can adjust to track state. - */ - Set getLayerFlags(); - /** * remove host from world... */ @@ -191,4 +186,4 @@ public interface IPartHost extends ICustomCableConnection */ boolean isInWorld(); -} \ No newline at end of file +} diff --git a/src/api/java/appeng/api/parts/LayerBase.java b/src/api/java/appeng/api/parts/LayerBase.java deleted file mode 100644 index a5c1df88e..000000000 --- a/src/api/java/appeng/api/parts/LayerBase.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2013 AlgorithmX2 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package appeng.api.parts; - - -import java.util.Set; - -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; - -import appeng.api.util.AEPartLocation; - - -/** - * All Layers must extends this, this get part implementation is provided to interface with the parts, however a real - * implementation will be used at runtime. - * - * TODO: Consider removing and replacing with capabilities. - */ -public abstract class LayerBase extends TileEntity // implements IPartHost -{ - - /** - * Grants access for the layer to the parts of the host. - * - * This Method looks silly, that is because its not used at runtime, a real implementation will be used instead. - * - * @param side side of part - * - * @return the part for the requested side. - */ - public IPart getPart( final AEPartLocation side ) - { - return null; // place holder. - } - - /** - * Grants access for the layer to the parts of the host. - * - * This Method looks silly, that is because its not used at runtime, a real implementation will be used instead. - * - * @param side side of part - * - * @return the part for the requested side. - */ - public IPart getPart( final EnumFacing side ) - { - return null; // place holder. - } - - /** - * called when the parts change in the container, YOU MUST CALL super.PartChanged(); - */ - public void notifyNeighbors() - { - } - - /** - * called when the parts change in the container, YOU MUST CALL super.PartChanged(); - */ - public void partChanged() - { - } - - /** - * @return a mutable list of flags you can adjust to track state. - */ - public Set getLayerFlags() - { - return null; // place holder. - } - - public void markForSave() - { - // something! - } -} diff --git a/src/api/java/appeng/api/parts/LayerFlags.java b/src/api/java/appeng/api/parts/LayerFlags.java deleted file mode 100644 index 1995a5aa9..000000000 --- a/src/api/java/appeng/api/parts/LayerFlags.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2013 AlgorithmX2 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package appeng.api.parts; - - -/** - * TODO: Consider removing and replacing with capabilities. - */ -public enum LayerFlags -{ - - IC2_ENET - -} diff --git a/src/main/java/appeng/block/networking/BlockCableBus.java b/src/main/java/appeng/block/networking/BlockCableBus.java index 9e6850e39..99957f70b 100644 --- a/src/main/java/appeng/block/networking/BlockCableBus.java +++ b/src/main/java/appeng/block/networking/BlockCableBus.java @@ -29,7 +29,6 @@ import appeng.block.AEBaseTileBlock; import appeng.client.UnlistedProperty; import appeng.client.render.cablebus.CableBusBakedModel; import appeng.client.render.cablebus.CableBusRenderState; -import appeng.core.Api; import appeng.core.AppEng; import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.packets.PacketClick; @@ -91,10 +90,6 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade { private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer(); - private static Class noTesrTile; - - private static Class tesrTile; - public BlockCableBus() { super(AEGlassMaterial.INSTANCE); this.setLightOpacity(0); @@ -378,10 +373,9 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade { } public void setupTile() { - noTesrTile = Api.INSTANCE.partHelper().getCombinedInstance(TileCableBus.class); - this.setTileEntity(noTesrTile); + this.setTileEntity(TileCableBus.class); - GameRegistry.registerTileEntity(noTesrTile, AppEng.MOD_ID.toLowerCase() + ":" + "BlockCableBus"); + GameRegistry.registerTileEntity(TileCableBus.class, AppEng.MOD_ID.toLowerCase() + ":" + "BlockCableBus"); if (Platform.isClient()) { setupTesr(); @@ -390,9 +384,8 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade { @SideOnly(Side.CLIENT) private static void setupTesr() { - tesrTile = Api.INSTANCE.partHelper().getCombinedInstance(TileCableBusTESR.class); - GameRegistry.registerTileEntity(tesrTile, AppEng.MOD_ID.toLowerCase() + ":" + "ClientOnly_TESR_CableBus"); - ClientRegistry.bindTileEntitySpecialRenderer(BlockCableBus.getTesrTile(), new CableBusTESR()); + GameRegistry.registerTileEntity(TileCableBusTESR.class, AppEng.MOD_ID.toLowerCase() + ":" + "ClientOnly_TESR_CableBus"); + ClientRegistry.bindTileEntitySpecialRenderer(TileCableBusTESR.class, new CableBusTESR()); } @Override @@ -438,14 +431,6 @@ public class BlockCableBus extends AEBaseTileBlock implements IAEFacade { super.onEntityWalk(world, pos, entityIn); } - public static Class getNoTesrTile() { - return noTesrTile; - } - - public static Class getTesrTile() { - return tesrTile; - } - // Helper to get access to the protected constructor @SideOnly(Side.CLIENT) private static class DestroyFX extends ParticleDigging { diff --git a/src/main/java/appeng/core/api/ApiPart.java b/src/main/java/appeng/core/api/ApiPart.java index 34a6ad7b0..c55390e86 100644 --- a/src/main/java/appeng/core/api/ApiPart.java +++ b/src/main/java/appeng/core/api/ApiPart.java @@ -21,258 +21,19 @@ package appeng.core.api; import appeng.api.parts.CableRenderMode; import appeng.api.parts.IPartHelper; -import appeng.api.parts.LayerBase; -import appeng.core.AELog; import appeng.core.AppEng; import appeng.parts.PartPlacement; -import appeng.tile.AEBaseTile; -import appeng.tile.networking.TileCableBus; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableList; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; -import org.objectweb.asm.tree.AbstractInsnNode; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.MethodInsnNode; -import org.objectweb.asm.tree.MethodNode; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.util.*; public class ApiPart implements IPartHelper { - private final LoadingCache> cache = CacheBuilder.newBuilder() - .build(new CacheLoader>() { - @Override - public Class load(CacheKey key) throws Exception { - return ApiPart.this.generateCombinedClass(key); - } - }); - - private final Map, String> interfaces2Layer = new HashMap<>(); - private final List desc = new ArrayList<>(); - - /** - * Conceptually this method will build a new class hierarchy that is rooted at the given base class, and includes a - * chain of all registered layers. - *

- * To accomplish this, it takes the first registered layer, replaces it's inheritance from LayerBase with an - * inheritance from the given baseClass, - * and uses the resulting class as the parent class for the next registered layer, for which it repeats this - * process. This process is then repeated - * until a class hierarchy of all layers is formed. While janking out the inheritance from LayerBase, it'll make - * also sure that calls to that - * classes method will instead be forwarded to the superclass that was inserted as part of the described process. - *

- * Example: If layers A and B are registered, and TileCableBus is passed in as the baseClass, a synthetic class - * A_B_TileCableBus should be returned, - * which has A_B_TileCableBus -extends-> B_TileCableBus -extends-> TileCableBus as it's class hierarchy, where - * A_B_TileCableBus has been generated - * from A, and B_TileCableBus has been generated from B. - */ - public Class getCombinedInstance(final Class baseClass) { - if (this.desc.isEmpty()) { - // No layers registered... - return baseClass; - } - - return this.cache.getUnchecked(new CacheKey(baseClass, this.desc)); - } - - private Class generateCombinedClass(CacheKey cacheKey) { - final Class parentClass; - - // Get the list of interfaces that still need to be implemented beyond the current one - List remainingInterfaces = cacheKey.getInterfaces().subList(1, cacheKey.getInterfaces().size()); - - // We are not at the root of the class hierarchy yet - if (!remainingInterfaces.isEmpty()) { - CacheKey parentKey = new CacheKey(cacheKey.getBaseClass(), remainingInterfaces); - parentClass = this.cache.getUnchecked(parentKey); - } else { - parentClass = cacheKey.getBaseClass(); - } - - // Which interface should be implemented in this layer? - String interfaceName = cacheKey.getInterfaces().get(0); - - try { - // This is the particular interface that this layer was registered for. Loading the class may fail if i.e. - // an API is broken or not present - // and in this case, the layer will be skipped! - Class interfaceClass = Class.forName(interfaceName); - String layerImpl = this.interfaces2Layer.get(interfaceClass); - - return this.getClassByDesc(parentClass, layerImpl); - } catch (final Throwable t) { - AELog.warn("Error loading " + interfaceName); - AELog.debug(t); - return parentClass; - } - - } - - @SuppressWarnings("unchecked") - private Class getClassByDesc(Class baseClass, final String next) { - final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - final ClassNode n = this.getReader(next); - final String originalName = n.name; - - try { - n.name = n.name + '_' + baseClass.getSimpleName(); - n.superName = baseClass.getName().replace('.', '/'); - } catch (final Throwable t) { - AELog.debug(t); - } - - for (final MethodNode mn : n.methods) { - final Iterator i = mn.instructions.iterator(); - while (i.hasNext()) { - this.processNode(i.next(), n.superName); - } - } - - final DefaultPackageClassNameRemapper remapper = new DefaultPackageClassNameRemapper(); - remapper.inputOutput.put("appeng/api/parts/LayerBase", n.superName); - remapper.inputOutput.put(originalName, n.name); - n.accept(new ClassRemapper(cw, remapper)); - // n.accept( cw ); - - // n.accept( new TraceClassVisitor( new PrintWriter( System.out ) ) ); - final byte[] byteArray = cw.toByteArray(); - final int size = byteArray.length; - final Class clazz = this.loadClass(n.name.replace("/", "."), byteArray); - - try { - final Object fish = clazz.newInstance(); - - boolean hasError = false; - - if (!baseClass.isInstance(fish)) { - hasError = true; - AELog.error("Error, Expected layer to implement " + baseClass + " did not."); - } - - if (fish instanceof LayerBase) { - hasError = true; - AELog.error("Error, Expected layer to NOT implement LayerBase but it DID."); - } - - if (!(fish instanceof TileCableBus)) { - hasError = true; - AELog.error("Error, Expected layer to implement TileCableBus did not."); - } - - if (!(fish instanceof TileEntity)) { - hasError = true; - AELog.error("Error, Expected layer to implement TileEntity did not."); - } - - if (!hasError) { - AELog.info("Layer: " + n.name + " loaded successfully - " + size + " bytes"); - } - } catch (final Throwable t) { - AELog.error("Layer: " + n.name + " Failed."); - AELog.debug(t); - } - - return clazz; - } - - private ClassNode getReader(final String name) { - final String path = '/' + name.replace(".", "/") + ".class"; - final InputStream is = this.getClass().getResourceAsStream(path); - try { - final ClassReader cr = new ClassReader(is); - - final ClassNode cn = new ClassNode(); - cr.accept(cn, ClassReader.EXPAND_FRAMES); - - return cn; - } catch (final IOException e) { - throw new IllegalStateException("Error loading " + name, e); - } - } - - private void processNode(final AbstractInsnNode next, final String nePar) { - if (next instanceof MethodInsnNode) { - final MethodInsnNode min = (MethodInsnNode) next; - if (min.owner.equals("appeng/api/parts/LayerBase")) { - min.owner = nePar; - } - } - } - - private Class loadClass(final String name, byte[] b) { - // override classDefine (as it is protected) and define the class. - Class clazz = null; - try { - final ClassLoader loader = this.getClass().getClassLoader();// ClassLoader.getSystemClassLoader(); - final Class root = ClassLoader.class; - final Class cls = loader.getClass(); - final Method defineClassMethod = root.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - final Method runTransformersMethod = cls.getDeclaredMethod("runTransformers", String.class, String.class, byte[].class); - - runTransformersMethod.setAccessible(true); - defineClassMethod.setAccessible(true); - try { - final Object[] argsA = { - name, - name, - b - }; - b = (byte[]) runTransformersMethod.invoke(loader, argsA); - - final Object[] args = { - name, - b, - 0, - b.length - }; - clazz = (Class) defineClassMethod.invoke(loader, args); - } finally { - runTransformersMethod.setAccessible(false); - defineClassMethod.setAccessible(false); - } - } catch (final Exception e) { - AELog.debug(e); - throw new IllegalStateException("Unable to manage part API.", e); - } - return clazz; - } - - @Override - public boolean registerNewLayer(final String layer, final String layerInterface) { - try { - final Class layerInterfaceClass = Class.forName(layerInterface); - if (this.interfaces2Layer.get(layerInterfaceClass) == null) { - this.interfaces2Layer.put(layerInterfaceClass, layer); - this.desc.add(layerInterface); - return true; - } else { - AELog.info("Layer " + layer + " not registered, " + layerInterface + " already has a layer."); - } - } catch (final Throwable ignored) { - } - - return false; - } - @Override public EnumActionResult placeBus(final ItemStack is, final BlockPos pos, final EnumFacing side, final EntityPlayer player, final EnumHand hand, final World w) { return PartPlacement.place(is, pos, side, player, hand, w, PartPlacement.PlaceType.PLACE_ITEM, 0); @@ -282,58 +43,4 @@ public class ApiPart implements IPartHelper { public CableRenderMode getCableRenderMode() { return AppEng.proxy.getRenderMode(); } - - private static class DefaultPackageClassNameRemapper extends Remapper { - - private final HashMap inputOutput = new HashMap<>(); - - @Override - public String map(final String typeName) { - final String o = this.inputOutput.get(typeName); - if (o == null) { - return typeName; - } - return o; - } - } - - private static class CacheKey { - private final Class baseClass; - - private final List interfaces; - - private CacheKey(Class baseClass, List interfaces) { - this.baseClass = baseClass; - this.interfaces = ImmutableList.copyOf(interfaces); - } - - private Class getBaseClass() { - return this.baseClass; - } - - private List getInterfaces() { - return this.interfaces; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || this.getClass() != o.getClass()) { - return false; - } - - CacheKey cacheKey = (CacheKey) o; - - return this.baseClass.equals(cacheKey.baseClass) && this.interfaces.equals(cacheKey.interfaces); - } - - @Override - public int hashCode() { - int result = this.baseClass.hashCode(); - result = 31 * result + this.interfaces.hashCode(); - return result; - } - } } diff --git a/src/main/java/appeng/parts/CableBusContainer.java b/src/main/java/appeng/parts/CableBusContainer.java index 1806c972f..9a382ba99 100644 --- a/src/main/java/appeng/parts/CableBusContainer.java +++ b/src/main/java/appeng/parts/CableBusContainer.java @@ -65,7 +65,6 @@ import java.util.*; public class CableBusContainer extends CableBusStorage implements AEMultiTile, ICableBusContainer { private static final ThreadLocal IS_LOADING = new ThreadLocal<>(); - private final EnumSet myLayerFlags = EnumSet.noneOf(LayerFlags.class); private YesNo hasRedstone = YesNo.UNDECIDED; private IPartHost tcb; // TODO 1.10.2-R - does somebody seriously want to make parts TESR??? Hope not. @@ -424,11 +423,6 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I return true; } - @Override - public Set getLayerFlags() { - return this.myLayerFlags; - } - @Override public void cleanup() { this.tcb.cleanup(); diff --git a/src/main/java/appeng/tile/networking/TileCableBus.java b/src/main/java/appeng/tile/networking/TileCableBus.java index ca93af3a4..9e4bdd531 100644 --- a/src/main/java/appeng/tile/networking/TileCableBus.java +++ b/src/main/java/appeng/tile/networking/TileCableBus.java @@ -22,13 +22,11 @@ package appeng.tile.networking; import appeng.api.networking.IGridNode; import appeng.api.parts.IFacadeContainer; import appeng.api.parts.IPart; -import appeng.api.parts.LayerFlags; import appeng.api.parts.SelectedPart; import appeng.api.util.AECableType; import appeng.api.util.AEColor; import appeng.api.util.AEPartLocation; import appeng.api.util.DimensionalCoord; -import appeng.block.networking.BlockCableBus; import appeng.helpers.AEMultiTile; import appeng.helpers.ICustomCollision; import appeng.hooks.TickHandler; @@ -101,7 +99,7 @@ public class TileCableBus extends AEBaseTile implements AEMultiTile, ICustomColl protected void updateTileSetting() { if (this.getCableBus().isRequiresDynamicRender()) { try { - final TileCableBus tcb = (TileCableBus) BlockCableBus.getTesrTile().newInstance(); + final TileCableBus tcb = TileCableBusTESR.class.newInstance(); tcb.copyFrom(this); this.getWorld().setTileEntity(this.pos, tcb); } catch (final Throwable ignored) { @@ -283,11 +281,6 @@ public class TileCableBus extends AEBaseTile implements AEMultiTile, ICustomColl return this.getCableBus().isEmpty(); } - @Override - public Set getLayerFlags() { - return this.getCableBus().getLayerFlags(); - } - @Override public void cleanup() { this.getWorld().setBlockToAir(this.pos); diff --git a/src/main/java/appeng/tile/networking/TileCableBusTESR.java b/src/main/java/appeng/tile/networking/TileCableBusTESR.java index 3c4cd91e6..6c6b5eb53 100644 --- a/src/main/java/appeng/tile/networking/TileCableBusTESR.java +++ b/src/main/java/appeng/tile/networking/TileCableBusTESR.java @@ -19,9 +19,6 @@ package appeng.tile.networking; -import appeng.block.networking.BlockCableBus; - - public class TileCableBusTESR extends TileCableBus { /** @@ -31,7 +28,7 @@ public class TileCableBusTESR extends TileCableBus { protected void updateTileSetting() { if (!this.getCableBus().isRequiresDynamicRender()) { try { - final TileCableBus tcb = (TileCableBus) BlockCableBus.getNoTesrTile().newInstance(); + final TileCableBus tcb = TileCableBus.class.newInstance(); tcb.copyFrom(this); this.getWorld().setTileEntity(this.pos, tcb); } catch (final Throwable ignored) {