diff --git a/src/main/java/cr0s/warpdrive/compat/CompatPneumaticCraft.java b/src/main/java/cr0s/warpdrive/compat/CompatPneumaticCraft.java index f4b50df1..c463a4eb 100644 --- a/src/main/java/cr0s/warpdrive/compat/CompatPneumaticCraft.java +++ b/src/main/java/cr0s/warpdrive/compat/CompatPneumaticCraft.java @@ -1,11 +1,16 @@ package cr0s.warpdrive.compat; +import cr0s.warpdrive.WarpDrive; import cr0s.warpdrive.api.IBlockTransformer; import cr0s.warpdrive.api.ITransformation; import cr0s.warpdrive.api.WarpDriveText; import cr0s.warpdrive.config.WarpDriveConfig; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; @@ -15,20 +20,31 @@ import net.minecraft.world.World; public class CompatPneumaticCraft implements IBlockTransformer { - private static Class classTileEntityBase; + private static Class classBlockPneumaticCraft; + private static Method methodBlockPneumaticCraft_isRotatable; // many blocks are rotatable, many are not => it's more efficient to read the property to differentiate them + + private static Class classBlockPneumaticDoor; + private static Class classBlockPressureChamberWall; + private static Class classBlockPressureChamberValve; public static void register() { try { - classTileEntityBase = Class.forName("pneumaticCraft.common.tileentity.TileEntityBase"); + classBlockPneumaticCraft = Class.forName("me.desht.pneumaticcraft.common.block.BlockPneumaticCraft"); + methodBlockPneumaticCraft_isRotatable = classBlockPneumaticCraft.getMethod("isRotatable"); + + classBlockPneumaticDoor = Class.forName("me.desht.pneumaticcraft.common.block.BlockPneumaticDoor"); + classBlockPressureChamberWall = Class.forName("me.desht.pneumaticcraft.common.block.BlockPressureChamberWall"); + classBlockPressureChamberValve = Class.forName("me.desht.pneumaticcraft.common.block.BlockPressureChamberValve"); + WarpDriveConfig.registerBlockTransformer("pneumaticcraft", new CompatPneumaticCraft()); - } catch(final ClassNotFoundException exception) { + } catch(final ClassNotFoundException | NoSuchMethodException exception) { exception.printStackTrace(); } } @Override public boolean isApplicable(final Block block, final int metadata, final TileEntity tileEntity) { - return classTileEntityBase.isInstance(tileEntity); + return classBlockPneumaticCraft.isInstance(block); } @Override @@ -48,9 +64,12 @@ public class CompatPneumaticCraft implements IBlockTransformer { // nothing to do } - private static final byte[] mrotForgeDirection = { 0, 1, 5, 4, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - private static final byte[] mrotTextRotation = { 1, 2, 3, 0 }; - private static final byte[] mrotDoor = { 0, 1, 5, 4, 2, 3, 6, 7, 11, 10, 8, 9, 12, 13, 14, 15 }; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + private static final byte[] mrotFacing = { 0, 1, 5, 4, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // Chamber interface & Omnidirectional hopper + private static final byte[] mrotChamberWall = { 0, 1, 3, 2, 4, 8, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15 }; // Chamber wall + private static final byte[] mrotChamberValve = { 0, 1, 5, 4, 2, 3, 6, 7, 11, 10, 8, 9, 12, 13, 14, 15 }; // Chamber valve + private static final byte[] mrotPneumaticDoor = { 0, 1, 5, 4, 2, 3, 6, 7, 11, 10, 8, 9, 12, 13, 14, 15 }; // Pressure door + private static final byte[] mrotTextRotation = { 1, 2, 3, 0 }; @Override public int rotate(final Block block, final int metadata, final NBTTagCompound nbtTileEntity, final ITransformation transformation) { @@ -61,75 +80,75 @@ public class CompatPneumaticCraft implements IBlockTransformer { return metadata; } - // hoppers + // Aphorism signs + // @todo the sign has no text after ship movement in single player until chunk is reloaded? + if (nbtTileEntity.hasKey("textRot")) { + if (metadata == 0 || metadata == 1) {// sign is horizontal, only the text needs to be rotated + final int textRotation = nbtTileEntity.getInteger("textRot"); + switch (rotationSteps) { + case 1: + nbtTileEntity.setInteger("textRot", mrotTextRotation[textRotation]); + return metadata; + case 2: + nbtTileEntity.setInteger("textRot", mrotTextRotation[mrotTextRotation[textRotation]]); + return metadata; + case 3: + nbtTileEntity.setInteger("textRot", mrotTextRotation[mrotTextRotation[mrotTextRotation[textRotation]]]); + return metadata; + default: + return metadata; + } + } else {// sign is vertical, only the block itself is rotating + switch (rotationSteps) { + case 1: + return mrotFacing[metadata]; + case 2: + return mrotFacing[mrotFacing[metadata]]; + case 3: + return mrotFacing[mrotFacing[mrotFacing[metadata]]]; + default: + return metadata; + } + } + } + + // Omnidirectional hoppers if (nbtTileEntity.hasKey("inputDir")) { final int inputDir = nbtTileEntity.getInteger("inputDir"); + final int outputDir = nbtTileEntity.getInteger("outputDir"); switch (rotationSteps) { case 1: - nbtTileEntity.setInteger("inputDir", mrotForgeDirection[inputDir]); - return mrotForgeDirection[metadata]; + nbtTileEntity.setInteger("inputDir", mrotFacing[inputDir]); + nbtTileEntity.setInteger("outputDir", mrotFacing[outputDir]); + return mrotFacing[metadata]; case 2: - nbtTileEntity.setInteger("inputDir", mrotForgeDirection[mrotForgeDirection[inputDir]]); - return mrotForgeDirection[mrotForgeDirection[metadata]]; + nbtTileEntity.setInteger("inputDir", mrotFacing[mrotFacing[inputDir]]); + nbtTileEntity.setInteger("outputDir", mrotFacing[mrotFacing[outputDir]]); + return mrotFacing[mrotFacing[metadata]]; case 3: - nbtTileEntity.setInteger("inputDir", mrotForgeDirection[mrotForgeDirection[mrotForgeDirection[inputDir]]]); - return mrotForgeDirection[mrotForgeDirection[mrotForgeDirection[metadata]]]; + nbtTileEntity.setInteger("inputDir", mrotFacing[mrotFacing[mrotFacing[inputDir]]]); + nbtTileEntity.setInteger("outputDir", mrotFacing[mrotFacing[mrotFacing[outputDir]]]); + return mrotFacing[mrotFacing[mrotFacing[metadata]]]; default: return metadata; } } - // Aphorism signs - if (nbtTileEntity.hasKey("textRotation")) { - final int textRotation = nbtTileEntity.getInteger("textRotation"); + // Pneumatic door is facing + top/down on modulo (6 or 8 ?) + if (classBlockPneumaticDoor.isInstance(block)) { switch (rotationSteps) { case 1: - nbtTileEntity.setInteger("textRotation", mrotTextRotation[textRotation]); - return mrotForgeDirection[metadata]; + return mrotPneumaticDoor[metadata]; case 2: - nbtTileEntity.setInteger("textRotation", mrotTextRotation[mrotTextRotation[textRotation]]); - return mrotForgeDirection[mrotForgeDirection[metadata]]; + return mrotPneumaticDoor[mrotPneumaticDoor[metadata]]; case 3: - nbtTileEntity.setInteger("textRotation", mrotTextRotation[mrotTextRotation[mrotTextRotation[textRotation]]]); - return mrotForgeDirection[mrotForgeDirection[mrotForgeDirection[metadata]]]; + return mrotPneumaticDoor[mrotPneumaticDoor[mrotPneumaticDoor[metadata]]]; default: return metadata; } } - // door base - if (nbtTileEntity.hasKey("orientation")) { - final int orientation = nbtTileEntity.getInteger("orientation"); - switch (rotationSteps) { - case 1: - nbtTileEntity.setInteger("orientation", mrotTextRotation[orientation]); - return metadata; - case 2: - nbtTileEntity.setInteger("orientation", mrotTextRotation[mrotTextRotation[orientation]]); - return metadata; - case 3: - nbtTileEntity.setInteger("orientation", mrotTextRotation[mrotTextRotation[mrotTextRotation[orientation]]]); - return metadata; - default: - return metadata; - } - } - - // door - if (nbtTileEntity.getString("id").equals("TileEntityPneumaticDoor")) { - switch (rotationSteps) { - case 1: - return mrotDoor[metadata]; - case 2: - return mrotDoor[mrotDoor[metadata]]; - case 3: - return mrotDoor[mrotDoor[mrotDoor[metadata]]]; - default: - return metadata; - } - } - - // pressure chamber wall, pressure chamber window, pressure chamber interface + // pressure chamber blocks (wall, glass, valve, interface) if (nbtTileEntity.hasKey("valveX")) { final BlockPos target = transformation.apply( nbtTileEntity.getInteger("valveX"), @@ -143,21 +162,25 @@ public class CompatPneumaticCraft implements IBlockTransformer { // pressure chamber valve if (nbtTileEntity.hasKey("multiBlockX")) { - final BlockPos sourceMin = new BlockPos( - nbtTileEntity.getInteger("multiBlockX"), - nbtTileEntity.getInteger("multiBlockY"), - nbtTileEntity.getInteger("multiBlockZ")); + // multiBlockXYZ only makes sense when size is non null, even if they are part of the multiblock (yes, it's weird) final int multiBlockSize = nbtTileEntity.getInteger("multiBlockSize"); - final BlockPos sourceMax = new BlockPos( - sourceMin.getX() + multiBlockSize - 1, - sourceMin.getY() + multiBlockSize - 1, - sourceMin.getZ() + multiBlockSize - 1); - final BlockPos target1 = transformation.apply(sourceMin); - final BlockPos target2 = transformation.apply(sourceMax); - nbtTileEntity.setInteger("multiBlockX", Math.min(target1.getX(), target2.getX())); - nbtTileEntity.setInteger("multiBlockY", Math.min(target1.getY(), target2.getY())); - nbtTileEntity.setInteger("multiBlockZ", Math.min(target1.getZ(), target2.getZ())); + if (multiBlockSize != 0) { + final BlockPos sourceMin = new BlockPos( + nbtTileEntity.getInteger("multiBlockX"), + nbtTileEntity.getInteger("multiBlockY"), + nbtTileEntity.getInteger("multiBlockZ")); + final BlockPos sourceMax = new BlockPos( + sourceMin.getX() + multiBlockSize - 1, + sourceMin.getY() + multiBlockSize - 1, + sourceMin.getZ() + multiBlockSize - 1); + final BlockPos target1 = transformation.apply(sourceMin); + final BlockPos target2 = transformation.apply(sourceMax); + nbtTileEntity.setInteger("multiBlockX", Math.min(target1.getX(), target2.getX())); + nbtTileEntity.setInteger("multiBlockY", Math.min(target1.getY(), target2.getY())); + nbtTileEntity.setInteger("multiBlockZ", Math.min(target1.getZ(), target2.getZ())); + } + // Valves coordinates to each valves final NBTTagList tagListOld = nbtTileEntity.getTagList("Valves", 10); final NBTTagList tagListNew = new NBTTagList(); for (int index = 0; index < tagListOld.tagCount(); index++) { @@ -177,22 +200,117 @@ public class CompatPneumaticCraft implements IBlockTransformer { // use default metadata rotation } - // all other tile entities: security station, programmer, pneumatic dynamo, charging station, air cannon, elevator caller, air compressor - switch (rotationSteps) { - case 1: - return mrotForgeDirection[metadata]; - case 2: - return mrotForgeDirection[mrotForgeDirection[metadata]]; - case 3: - return mrotForgeDirection[mrotForgeDirection[mrotForgeDirection[metadata]]]; - default: + // elevator base, pipe + if (nbtTileEntity.hasKey("sideConnected0")) { + final byte[] connectedOldSides = new byte[6]; + for (int side = 2; side < 6; side++) { + connectedOldSides[side] = nbtTileEntity.getByte("sideConnected" + side); + } + for (int side = 2; side < 6; side++) { + final byte connected = connectedOldSides[side]; + switch (rotationSteps) { + case 1: + nbtTileEntity.setByte("sideConnected" + mrotFacing[side], connected); + break; + case 2: + nbtTileEntity.setByte("sideConnected" + mrotFacing[mrotFacing[side]], connected); + break; + case 3: + nbtTileEntity.setByte("sideConnected" + mrotFacing[mrotFacing[mrotFacing[side]]], connected); + break; + default: + break; + } + } + if (nbtTileEntity.hasKey("sideClosed0")) { + final byte[] closedOldSides = new byte[6]; + for (int side = 2; side < 6; side++) { + closedOldSides[side] = nbtTileEntity.getByte("sideClosed" + side); + } + for (int side = 2; side < 6; side++) { + final byte connected = closedOldSides[side]; + switch (rotationSteps) { + case 1: + nbtTileEntity.setByte("sideClosed" + mrotFacing[side], connected); + break; + case 2: + nbtTileEntity.setByte("sideClosed" + mrotFacing[mrotFacing[side]], connected); + break; + case 3: + nbtTileEntity.setByte("sideClosed" + mrotFacing[mrotFacing[mrotFacing[side]]], connected); + break; + default: + break; + } + } + } + } + + + // Pressure chamber wall has its own logic: NONE, CENTER, XEDGE, ZEDGE, YEDGE, XMIN_YMIN_ZMIN, XMIN_YMIN_ZMAX, XMIN_YMAX_ZMIN, XMIN_YMAX_ZMAX + if (classBlockPressureChamberWall.isInstance(block)) { + switch (rotationSteps) { + case 1: + return mrotChamberWall[metadata]; + case 2: + return mrotChamberWall[mrotChamberWall[metadata]]; + case 3: + return mrotChamberWall[mrotChamberWall[mrotChamberWall[metadata]]]; + default: + return metadata; + } + } + + if (classBlockPressureChamberValve.isInstance(block)) { + switch (rotationSteps) { + case 1: + return mrotChamberValve[metadata]; + case 2: + return mrotChamberValve[mrotChamberValve[metadata]]; + case 3: + return mrotChamberValve[mrotChamberValve[mrotChamberValve[metadata]]]; + default: + return metadata; + } + } + + // all other tile entities we need to check the Rotatable state + // this includes many blocks like security station, programmer, pneumatic dynamo, charging station, air cannon, elevator caller, air compressor, etc. + final boolean isRotatable; + try { + final Object object = methodBlockPneumaticCraft_isRotatable.invoke(block); + if (object instanceof Boolean) { + isRotatable = (Boolean) object; + } else { + WarpDrive.logger.error(String.format("Block %s has invalid non-Boolean return value to isRotatable: %s", + block.getRegistryName(), object)); + return metadata; + } + } catch (final IllegalAccessException | InvocationTargetException exception) { + exception.printStackTrace(); + return metadata; + } + WarpDrive.logger.info(String.format("Block %s isRotatable %s", + block.getRegistryName(), isRotatable)); + if (isRotatable) { + switch (rotationSteps) { + case 1: + return mrotFacing[metadata]; + case 2: + return mrotFacing[mrotFacing[metadata]]; + case 3: + return mrotFacing[mrotFacing[mrotFacing[metadata]]]; + default: + return metadata; + } + } else { return metadata; } } @Override - public void restoreExternals(final World world, final int x, final int y, final int z, - final Block block, final int blockMeta, final TileEntity tileEntity, + public void restoreExternals(final World world, final BlockPos blockPos, + final IBlockState blockState, final TileEntity tileEntity, final ITransformation transformation, final NBTBase nbtBase) { // nothing to do }