From ff2ca21edb537b2021c60aba4c2019d3582f05f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 26 Mar 2015 07:09:45 +0100 Subject: [PATCH] Added FMP compatibility to 3D prints \o/ --- .../client/renderer/block/BlockRenderer.scala | 2 +- .../cil/oc/client/renderer/block/Print.scala | 15 +- .../scala/li/cil/oc/common/block/Print.scala | 8 +- .../li/cil/oc/common/block/RobotProxy.scala | 6 +- .../li/cil/oc/common/block/SimpleBlock.scala | 8 +- .../cil/oc/integration/fmp/EventHandler.scala | 37 ++- .../integration/fmp/MultipartConverter.scala | 7 +- .../oc/integration/fmp/MultipartFactory.scala | 7 +- .../li/cil/oc/integration/fmp/PrintPart.scala | 275 ++++++++++++++++++ 9 files changed, 343 insertions(+), 22 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/fmp/PrintPart.scala diff --git a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala index 3d05d230b..cfc0394d7 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/BlockRenderer.scala @@ -102,7 +102,7 @@ object BlockRenderer extends ISimpleBlockRenderingHandler { result case print: tileentity.Print => - Print.render(print, x, y, z, block, renderer) + Print.render(print.data, print.state, print.facing, x, y, z, block, renderer) RenderState.checkError(getClass.getName + ".renderWorldBlock: print") diff --git a/src/main/scala/li/cil/oc/client/renderer/block/Print.scala b/src/main/scala/li/cil/oc/client/renderer/block/Print.scala index 32c3c4804..6fac30b2b 100644 --- a/src/main/scala/li/cil/oc/client/renderer/block/Print.scala +++ b/src/main/scala/li/cil/oc/client/renderer/block/Print.scala @@ -2,20 +2,27 @@ package li.cil.oc.client.renderer.block import li.cil.oc.api.Items import li.cil.oc.common.block -import li.cil.oc.common.tileentity +import li.cil.oc.common.item.data.PrintData import li.cil.oc.util.ExtendedAABB._ import net.minecraft.block.Block import net.minecraft.client.Minecraft import net.minecraft.client.renderer.RenderBlocks import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.util.IIcon +import net.minecraftforge.common.util.ForgeDirection object Print { lazy val printBlock = Items.get("print").block().asInstanceOf[block.Print] - def render(print: tileentity.Print, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Unit = { - for (shape <- if (print.state) print.data.stateOn else print.data.stateOff) { - val bounds = shape.bounds.rotateTowards(print.facing) + def render(data: PrintData, state: Boolean, facing: ForgeDirection, x: Int, y: Int, z: Int, block: Block, renderer: RenderBlocks): Unit = { + val shapes = if (state) data.stateOn else data.stateOff + if (shapes.size == 0) { + printBlock.textureOverride = Option(resolveTexture("missingno")) + renderer.setRenderBounds(0, 0, 0, 1, 1, 1) + renderer.renderStandardBlock(block, x, y, z) + } + else for (shape <- shapes) { + val bounds = shape.bounds.rotateTowards(facing) printBlock.colorMultiplierOverride = shape.tint printBlock.textureOverride = Option(resolveTexture(shape.texture)) renderer.setRenderBounds( diff --git a/src/main/scala/li/cil/oc/common/block/Print.scala b/src/main/scala/li/cil/oc/common/block/Print.scala index dd1248e95..9c1c6b333 100644 --- a/src/main/scala/li/cil/oc/common/block/Print.scala +++ b/src/main/scala/li/cil/oc/common/block/Print.scala @@ -102,16 +102,16 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends } } - override protected def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3): MovingObjectPosition = { + override protected def intersect(world: World, x: Int, y: Int, z: Int, start: Vec3, end: Vec3): MovingObjectPosition = { world.getTileEntity(x, y, z) match { case print: tileentity.Print => var closestDistance = Double.PositiveInfinity var closest: Option[MovingObjectPosition] = None for (shape <- if (print.state) print.data.stateOn else print.data.stateOff) { val bounds = shape.bounds.rotateTowards(print.facing).offset(x, y, z) - val hit = bounds.calculateIntercept(origin, direction) + val hit = bounds.calculateIntercept(start, end) if (hit != null) { - val distance = hit.hitVec.distanceTo(origin) + val distance = hit.hitVec.distanceTo(start) if (distance < closestDistance) { closestDistance = distance closest = Option(hit) @@ -119,7 +119,7 @@ class Print(protected implicit val tileTag: ClassTag[tileentity.Print]) extends } } closest.map(hit => new MovingObjectPosition(x, y, z, hit.sideHit, hit.hitVec)).orNull - case _ => super.intersect(world, x, y, z, origin, direction) + case _ => super.intersect(world, x, y, z, start, end) } } diff --git a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala index 987dfee1e..2ec184b1f 100644 --- a/src/main/scala/li/cil/oc/common/block/RobotProxy.scala +++ b/src/main/scala/li/cil/oc/common/block/RobotProxy.scala @@ -166,11 +166,11 @@ class RobotProxy extends RedstoneAware with traits.SpecialBlock with traits.Stat private def gettingDropsForActualDrop = new Exception().getStackTrace.exists(element => getDropForRealDropCallers.contains(element.getClassName + "." + element.getMethodName)) - override def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = { + override def intersect(world: World, x: Int, y: Int, z: Int, start: Vec3, end: Vec3) = { val bounds = getCollisionBoundingBoxFromPool(world, x, y, z) world.getTileEntity(x, y, z) match { - case proxy: tileentity.RobotProxy if proxy.robot.animationTicksLeft <= 0 && bounds.isVecInside(origin) => null - case _ => super.intersect(world, x, y, z, origin, direction) + case proxy: tileentity.RobotProxy if proxy.robot.animationTicksLeft <= 0 && bounds.isVecInside(start) => null + case _ => super.intersect(world, x, y, z, start, end) } } diff --git a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala index 02b30d99a..31d83ee3e 100644 --- a/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala +++ b/src/main/scala/li/cil/oc/common/block/SimpleBlock.scala @@ -207,16 +207,16 @@ class SimpleBlock(material: Material = Material.iron) extends Block(material) { } // NOTE: must not be final for immibis microblocks to work. - override def collisionRayTrace(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = - this.synchronized(intersect(world, x, y, z, origin, direction)) + override def collisionRayTrace(world: World, x: Int, y: Int, z: Int, start: Vec3, end: Vec3) = + this.synchronized(intersect(world, x, y, z, start, end)) override def getCollisionBoundingBoxFromPool(world: World, x: Int, y: Int, z: Int) = this.synchronized { doSetBlockBoundsBasedOnState(world, x, y, z) super.getCollisionBoundingBoxFromPool(world, x, y, z) } - protected def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = - super.collisionRayTrace(world, x, y, z, origin, direction) + protected def intersect(world: World, x: Int, y: Int, z: Int, start: Vec3, end: Vec3) = + super.collisionRayTrace(world, x, y, z, start, end) final override def canPlaceBlockOnSide(world: World, x: Int, y: Int, z: Int, side: Int) = canPlaceBlockOnSide(world, x, y, z, toLocal(world, x, y, z, ForgeDirection.getOrientation(side).getOpposite)) diff --git a/src/main/scala/li/cil/oc/integration/fmp/EventHandler.scala b/src/main/scala/li/cil/oc/integration/fmp/EventHandler.scala index d44acb967..bbfccd8eb 100644 --- a/src/main/scala/li/cil/oc/integration/fmp/EventHandler.scala +++ b/src/main/scala/li/cil/oc/integration/fmp/EventHandler.scala @@ -6,6 +6,7 @@ import codechicken.lib.vec.BlockCoord import codechicken.lib.vec.Vector3 import codechicken.multipart.TileMultipart import cpw.mods.fml.common.eventhandler.SubscribeEvent +import li.cil.oc.Settings import li.cil.oc.api.Items import li.cil.oc.client.PacketSender import li.cil.oc.common.block.SimpleBlock @@ -14,6 +15,7 @@ import net.minecraft.item.ItemBlock import net.minecraft.network.play.client.C08PacketPlayerBlockPlacement import net.minecraft.util.MovingObjectPosition import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.common.util.ForgeDirection import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent import net.minecraftforge.event.entity.player.PlayerInteractEvent import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action @@ -21,6 +23,8 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action object EventHandler { private var currentlyPlacing = false + private val yaw2Direction = Array(ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.NORTH, ForgeDirection.EAST) + @SubscribeEvent def playerInteract(event: PlayerInteractEvent) { this.synchronized { @@ -46,7 +50,17 @@ object EventHandler { if (hit != null && player.getHeldItem != null) player.getHeldItem.getItem match { case itemBlock: ItemBlock => itemBlock.field_150939_a match { - case simpleBlock: SimpleBlock if simpleBlock == Items.get("cable").block() => placeDelegatePart(player, hit, new CablePart()) + case simpleBlock: SimpleBlock => + if (simpleBlock == Items.get("cable").block()) { + placeDelegatePart(player, hit, new CablePart()) + } + else if (simpleBlock == Items.get("print").block()) { + val part = new PrintPart() + part.data.load(player.getHeldItem) + part.facing = yaw2Direction((player.rotationYaw / 360 * 4).round & 3).getOpposite + placeDelegatePart(player, hit, part) + } + else false case _ => false } case _ => false @@ -54,6 +68,7 @@ object EventHandler { else false } + protected def placeDelegatePart(player: EntityPlayer, hit: MovingObjectPosition, part: SimpleBlockPart): Boolean = { val world = player.getEntityWorld if (world.isRemote && !player.isSneaking) { @@ -66,7 +81,7 @@ object EventHandler { hit.blockX, hit.blockY, hit.blockZ, hit.sideHit, player.inventory.getCurrentItem, f.x.toFloat, f.y.toFloat, f.z.toFloat)) - return false + return true } } @@ -75,14 +90,28 @@ object EventHandler { val inside = Option(TileMultipart.getOrConvertTile(world, pos)) val outside = Option(TileMultipart.getOrConvertTile(world, posOutside)) inside match { - case Some(t) if t.canAddPart(part) => placeMultiPart(player, part, pos) + case Some(t) if t.canAddPart(part) && canAddPrint(t, part) => placeMultiPart(player, part, pos) case _ => outside match { - case Some(t) if t.canAddPart(part) => placeMultiPart(player, part, posOutside) + case Some(t) if t.canAddPart(part) && canAddPrint(t, part) => placeMultiPart(player, part, posOutside) case _ => false } } } + protected def canAddPrint(t: TileMultipart, p: SimpleBlockPart): Boolean = p match { + case print: PrintPart => + val (offSum, onSum) = t.partList.foldLeft((print.data.stateOff.size, print.data.stateOn.size))((acc, part) => { + val (offAcc, onAcc) = acc + val (offCount, onCount) = part match { + case innerPrint: PrintPart => (innerPrint.data.stateOff.size, innerPrint.data.stateOn.size) + case _ => (0, 0) + } + (offAcc + offCount, onAcc + onCount) + }) + offSum <= Settings.get.maxPrintComplexity && onSum <= Settings.get.maxPrintComplexity + case _ => true + } + protected def placeMultiPart(player: EntityPlayer, part: SimpleBlockPart, pos: BlockCoord) = { val world = player.getEntityWorld if (world.isRemote) { diff --git a/src/main/scala/li/cil/oc/integration/fmp/MultipartConverter.scala b/src/main/scala/li/cil/oc/integration/fmp/MultipartConverter.scala index 3bd4140a7..00c7571b1 100644 --- a/src/main/scala/li/cil/oc/integration/fmp/MultipartConverter.scala +++ b/src/main/scala/li/cil/oc/integration/fmp/MultipartConverter.scala @@ -7,6 +7,7 @@ import codechicken.multipart.MultiPartRegistry import codechicken.multipart.MultiPartRegistry.IPartConverter import li.cil.oc.api.Items import li.cil.oc.common.tileentity.Cable +import li.cil.oc.common.tileentity.Print import net.minecraft.world.World object MultipartConverter extends IPartConverter { @@ -14,11 +15,15 @@ object MultipartConverter extends IPartConverter { MultiPartRegistry.registerConverter(this) } - override def blockTypes = util.Arrays.asList(Items.get("cable").block) + override def blockTypes = util.Arrays.asList( + Items.get("cable").block, + Items.get("print").block + ) override def convert(world: World, pos: BlockCoord) = { world.getTileEntity(pos.x, pos.y, pos.z) match { case cable: Cable => new CablePart(Some(cable)) + case print: Print => new PrintPart(Some(print)) case _ => null } } diff --git a/src/main/scala/li/cil/oc/integration/fmp/MultipartFactory.scala b/src/main/scala/li/cil/oc/integration/fmp/MultipartFactory.scala index cc517fea7..2f72234fa 100644 --- a/src/main/scala/li/cil/oc/integration/fmp/MultipartFactory.scala +++ b/src/main/scala/li/cil/oc/integration/fmp/MultipartFactory.scala @@ -7,12 +7,17 @@ import li.cil.oc.Settings object MultipartFactory extends IPartFactory { def init() { - MultiPartRegistry.registerParts(MultipartFactory, Array(Settings.namespace + "cable")) + MultiPartRegistry.registerParts(MultipartFactory, Array( + Settings.namespace + "cable", + Settings.namespace + "print" + )) } override def createPart(name: String, client: Boolean): TMultiPart = { if (name.equals(Settings.namespace + "cable")) return new CablePart() + if (name.equals(Settings.namespace + "print")) + return new PrintPart() null } } diff --git a/src/main/scala/li/cil/oc/integration/fmp/PrintPart.scala b/src/main/scala/li/cil/oc/integration/fmp/PrintPart.scala new file mode 100644 index 000000000..f9347674d --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/fmp/PrintPart.scala @@ -0,0 +1,275 @@ +package li.cil.oc.integration.fmp + +import java.lang + +import codechicken.lib.data.MCDataInput +import codechicken.lib.data.MCDataOutput +import codechicken.lib.raytracer.ExtendedMOP +import codechicken.lib.vec.Cuboid6 +import codechicken.lib.vec.Vector3 +import codechicken.multipart.IRedstonePart +import codechicken.multipart.TCuboidPart +import codechicken.multipart.TNormalOcclusion +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import li.cil.oc.Settings +import li.cil.oc.api.Items +import li.cil.oc.client.renderer.block.Print +import li.cil.oc.common.block.Print +import li.cil.oc.common.item.data.PrintData +import li.cil.oc.common.tileentity +import li.cil.oc.integration.Mods +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedAABB +import li.cil.oc.util.ExtendedAABB._ +import li.cil.oc.util.ExtendedNBT._ +import li.cil.oc.util.ExtendedWorld._ +import mods.immibis.redlogic.api.wiring.IRedstoneEmitter +import net.minecraft.client.renderer.OpenGlHelper +import net.minecraft.client.renderer.RenderBlocks +import net.minecraft.client.renderer.RenderGlobal +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.init.Blocks +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.MovingObjectPosition +import net.minecraft.util.Vec3 +import net.minecraftforge.common.util.ForgeDirection +import org.lwjgl.opengl.GL11 + +import scala.collection.convert.WrapAsJava._ + +class PrintPart(val original: Option[tileentity.Print] = None) extends SimpleBlockPart with TCuboidPart with TNormalOcclusion with IRedstonePart { + var facing = ForgeDirection.SOUTH + var data = new PrintData() + + var boundsOff = ExtendedAABB.unitBounds + var boundsOn = ExtendedAABB.unitBounds + var state = false + + original.foreach(print => { + facing = print.facing + data = print.data + boundsOff = print.boundsOff + boundsOn = print.boundsOn + state = print.state + }) + + // ----------------------------------------------------------------------- // + + override def simpleBlock = Items.get("print").block().asInstanceOf[Print] + + def getType = Settings.namespace + "print" + + override def doesTick = false + + override def getBounds = new Cuboid6(if (state) boundsOn else boundsOff) + + override def getOcclusionBoxes = { + val shapes = if (state) data.stateOn else data.stateOff + asJavaIterable(shapes.map(shape => new Cuboid6(shape.bounds.rotateTowards(facing)))) + } + + override def getCollisionBoxes = getOcclusionBoxes + + override def getRenderBounds = getBounds + + // ----------------------------------------------------------------------- // + + override def canConnectRedstone(side: Int): Boolean = true + + override def strongPowerLevel(side: Int): Int = weakPowerLevel(side) + + override def weakPowerLevel(side: Int): Int = if (data.emitRedstone && state) 15 else 0 + + // ----------------------------------------------------------------------- // + + override def activate(player: EntityPlayer, hit: MovingObjectPosition, item: ItemStack): Boolean = { + if (data.stateOn.size > 0) { + if (!state || !data.isButtonMode) { + toggleState() + return true + } + } + false + } + + def toggleState(): Unit = { + if (canToggle) { + state = !state + world.playSoundEffect(x + 0.5, y + 0.5, z + 0.5, "random.click", 0.3F, if (state) 0.6F else 0.5F) + world.notifyBlocksOfNeighborChange(x, y, z, tile.getBlockType) + world.markBlockForUpdate(x, y, z) + if (!world.isRemote) sendDescUpdate() + tile.partList.foreach { + case print: PrintPart if print != this => print.onNeighborChanged() + case _ => + } + if (state && data.isButtonMode) { + scheduleTick(simpleBlock.tickRate(world)) + } + } + } + + def canToggle = { + val toggled = new PrintPart() + toggled.facing = facing + toggled.data = data + toggled.state = !state + toggled.boundsOff = boundsOff + toggled.boundsOn = boundsOn + tile.canReplacePart(this, toggled) + } + + // ----------------------------------------------------------------------- // + + override def scheduledTick(): Unit = if (state) toggleState() + + override def pickItem(hit: MovingObjectPosition): ItemStack = data.createItemStack() + + override def getDrops: lang.Iterable[ItemStack] = asJavaIterable(Iterable(data.createItemStack())) + + override def collisionRayTrace(start: Vec3, end: Vec3): ExtendedMOP = { + val shapes = if (state) data.stateOn else data.stateOff + var closestDistance = Double.PositiveInfinity + var closest: Option[MovingObjectPosition] = None + for (shape <- shapes) { + val bounds = shape.bounds.rotateTowards(facing).offset(x, y, z) + val hit = bounds.calculateIntercept(start, end) + if (hit != null) { + val distance = hit.hitVec.distanceTo(start) + if (distance < closestDistance) { + closestDistance = distance + hit.blockX = x + hit.blockY = y + hit.blockZ = z + closest = Option(hit) + } + } + } + closest.fold(if (shapes.isEmpty) new ExtendedMOP(x, y, z, 0, Vec3.createVectorHelper(0.5, 0.5, 0.5), null) else null)(hit => new ExtendedMOP(hit, null, closestDistance)) + } + + @SideOnly(Side.CLIENT) + override def drawHighlight(hit: MovingObjectPosition, player: EntityPlayer, frame: Float): Boolean = { + val pos = player.getPosition(frame) + val expansion = 0.002f + + // See RenderGlobal.drawSelectionBox. + GL11.glEnable(GL11.GL_BLEND) + OpenGlHelper.glBlendFunc(770, 771, 1, 0) + GL11.glColor4f(0, 0, 0, 0.4f) + GL11.glLineWidth(2) + GL11.glDisable(GL11.GL_TEXTURE_2D) + GL11.glDepthMask(false) + + for (shape <- if (state) data.stateOn else data.stateOff) { + val bounds = shape.bounds.rotateTowards(facing) + RenderGlobal.drawOutlinedBoundingBox(bounds.copy().expand(expansion, expansion, expansion) + .offset(hit.blockX, hit.blockY, hit.blockZ) + .offset(-pos.xCoord, -pos.yCoord, -pos.zCoord), -1) + } + + GL11.glDepthMask(true) + GL11.glEnable(GL11.GL_TEXTURE_2D) + GL11.glDisable(GL11.GL_BLEND) + + true + } + + override def onNeighborChanged(): Unit = { + super.onNeighborChanged() + val inner = tile.partList.foldLeft(false)((powered, part) => part match { + case print: PrintPart => powered || (print.state && print.data.emitRedstone) + case _ => powered + }) + val newMaxValue = if (inner) 15 else ForgeDirection.VALID_DIRECTIONS.map(computeInput).max + if (!data.emitRedstone && data.stateOn.size > 0) { + val newState = newMaxValue > 0 + if (state != newState) { + toggleState() + } + } + } + + protected def computeInput(side: ForgeDirection) = { + val blockPos = BlockPosition(x, y, z).offset(side) + if (!world.blockExists(blockPos)) 0 + else { + // See BlockRedstoneLogic.getInputStrength() for reference. + val vanilla = math.max(world.getIndirectPowerLevelTo(blockPos, side), + if (world.getBlock(blockPos) == Blocks.redstone_wire) world.getBlockMetadata(blockPos) else 0) + val redLogic = if (Mods.RedLogic.isAvailable) { + world.getTileEntity(blockPos) match { + case emitter: IRedstoneEmitter => + var strength = 0 + for (i <- -1 to 5) { + strength = math.max(strength, emitter.getEmittedSignalStrength(i, side.getOpposite.ordinal())) + } + strength + case _ => 0 + } + } + else 0 + math.max(vanilla, redLogic) + } + } + + // ----------------------------------------------------------------------- // + + override def load(nbt: NBTTagCompound) { + super.load(nbt) + facing = nbt.getDirection("facing").getOrElse(facing) + data.load(nbt.getCompoundTag("data")) + state = nbt.getBoolean("state") + updateBounds() + } + + override def save(nbt: NBTTagCompound) { + super.save(nbt) + nbt.setDirection("facing", Option(facing)) + nbt.setNewCompoundTag("data", data.save) + nbt.setBoolean("state", state) + } + + override def readDesc(packet: MCDataInput) { + super.readDesc(packet) + facing = ForgeDirection.getOrientation(packet.readUByte()) + data.load(packet.readNBTTagCompound()) + state = packet.readBoolean() + updateBounds() + if (world != null) { + world.markBlockForUpdate(x, y, z) + } + } + + override def writeDesc(packet: MCDataOutput) { + super.writeDesc(packet) + packet.writeByte(facing.ordinal().toByte) + val nbt = new NBTTagCompound() + data.save(nbt) + packet.writeNBTTagCompound(nbt) + packet.writeBoolean(state) + } + + def updateBounds(): Unit = { + boundsOff = data.stateOff.drop(1).foldLeft(data.stateOff.headOption.fold(ExtendedAABB.unitBounds)(_.bounds))((a, b) => a.func_111270_a(b.bounds)) + if (boundsOff.volume == 0) boundsOff = ExtendedAABB.unitBounds + else boundsOff = boundsOff.rotateTowards(facing) + boundsOn = data.stateOn.drop(1).foldLeft(data.stateOn.headOption.fold(ExtendedAABB.unitBounds)(_.bounds))((a, b) => a.func_111270_a(b.bounds)) + if (boundsOn.volume == 0) boundsOn = ExtendedAABB.unitBounds + else boundsOn = boundsOn.rotateTowards(facing) + } + + // ----------------------------------------------------------------------- // + + @SideOnly(Side.CLIENT) + override def renderStatic(pos: Vector3, pass: Int) = { + val (x, y, z) = (pos.x.toInt, pos.y.toInt, pos.z.toInt) + val renderer = RenderBlocks.getInstance + renderer.blockAccess = world + Print.render(data, state, facing, x, y, z, simpleBlock, renderer) + true + } + +}