blob: 7491037bef5a318f526c59aab9ded2b8e63b9fb0 [file] [log] [blame] [raw]
package li.cil.oc.common.block
import codechicken.lib.vec.Cuboid6
import codechicken.multipart.{JNormalOcclusion, NormalOcclusionTest, TFacePart, TileMultipart}
import cpw.mods.fml.relauncher.{Side, SideOnly}
import li.cil.oc.Settings
import li.cil.oc.api.network.{Environment, SidedEnvironment}
import li.cil.oc.client.Textures
import li.cil.oc.common.multipart.CablePart
import li.cil.oc.common.tileentity
import li.cil.oc.util.Color
import li.cil.oc.util.mods.Mods
import net.minecraft.tileentity.TileEntity
import net.minecraft.util.AxisAlignedBB
import net.minecraft.world.{IBlockAccess, World}
import net.minecraftforge.common.ForgeDirection
class Cable(val parent: SpecialDelegator) extends SpecialDelegate {
override protected def customTextures = Array(
Some("CablePart"),
Some("CablePart"),
Some("CablePart"),
Some("CablePart"),
Some("CablePart"),
Some("CablePart")
)
// ----------------------------------------------------------------------- //
@SideOnly(Side.CLIENT)
override def registerIcons(iconRegister: IconRegister) {
super.registerIcons(iconRegister)
Textures.Cable.iconCap = iconRegister.registerIcon(Settings.resourceDomain + ":CableCap")
}
override def hasTileEntity = true
override def createTileEntity(world: World) = Some(new tileentity.Cable())
// ----------------------------------------------------------------------- //
override def isNormalCube(world: World, x: Int, y: Int, z: Int) = false
override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false
override def opacity(world: World, x: Int, y: Int, z: Int) = 0
override def shouldSideBeRendered(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = true
// ----------------------------------------------------------------------- //
override def neighborBlockChanged(world: World, x: Int, y: Int, z: Int, blockId: Int) {
world.markBlockForRenderUpdate(x, y, z)
super.neighborBlockChanged(world, x, y, z, blockId)
}
override def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) {
parent.setBlockBounds(Cable.bounds(world, x, y, z))
}
}
object Cable {
val cachedBounds = {
// 6 directions = 6 bits = 11111111b >> 2 = 0xFF >> 2
(0 to 0xFF >> 2).map(mask => {
val bounds = AxisAlignedBB.getBoundingBox(-0.125, -0.125, -0.125, 0.125, 0.125, 0.125)
for (side <- ForgeDirection.VALID_DIRECTIONS) {
if ((side.flag & mask) != 0) {
if (side.offsetX < 0) bounds.minX += side.offsetX * 0.375
else bounds.maxX += side.offsetX * 0.375
if (side.offsetY < 0) bounds.minY += side.offsetY * 0.375
else bounds.maxY += side.offsetY * 0.375
if (side.offsetZ < 0) bounds.minZ += side.offsetZ * 0.375
else bounds.maxZ += side.offsetZ * 0.375
}
}
bounds.setBounds(
bounds.minX + 0.5, bounds.minY + 0.5, bounds.minZ + 0.5,
bounds.maxX + 0.5, bounds.maxY + 0.5, bounds.maxZ + 0.5)
}).toArray
}
def neighbors(world: IBlockAccess, x: Int, y: Int, z: Int) = {
var result = 0
val tileEntity = world.getBlockTileEntity(x, y, z)
for (side <- ForgeDirection.VALID_DIRECTIONS) {
val (tx, ty, tz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ)
if (!world.isAirBlock(tx, ty, tz)) {
val neighborTileEntity = world.getBlockTileEntity(tx, ty, tz)
val neighborHasNode = hasNetworkNode(neighborTileEntity, side.getOpposite)
val canConnectColor = canConnectBasedOnColor(tileEntity, neighborTileEntity)
val canConnectFMP = !Mods.ForgeMultipart.isAvailable ||
(canConnectFromSideFMP(tileEntity, side) && canConnectFromSideFMP(neighborTileEntity, side.getOpposite))
val canConnectIM = canConnectFromSideIM(tileEntity, side) && canConnectFromSideIM(neighborTileEntity, side.getOpposite)
if (neighborHasNode && canConnectColor && canConnectFMP && canConnectIM) {
result |= side.flag
}
}
}
result
}
def bounds(world: IBlockAccess, x: Int, y: Int, z: Int) = Cable.cachedBounds(Cable.neighbors(world, x, y, z)).copy()
private def hasNetworkNode(tileEntity: TileEntity, side: ForgeDirection) =
tileEntity match {
case robot: tileentity.RobotProxy => false
case host: SidedEnvironment =>
if (host.getWorldObj.isRemote) host.canConnect(side)
else host.sidedNode(side) != null
case host: Environment => true
case host if Mods.ForgeMultipart.isAvailable => hasMultiPartNode(tileEntity)
case _ => false
}
private def hasMultiPartNode(tileEntity: TileEntity) =
tileEntity match {
case host: TileMultipart => host.partList.exists(_.isInstanceOf[CablePart])
case _ => false
}
private def cableColor(tileEntity: TileEntity) =
tileEntity match {
case cable: tileentity.Cable => cable.color
case _ =>
if (Mods.ForgeMultipart.isAvailable) cableColorFMP(tileEntity)
else Color.LightGray
}
private def cableColorFMP(tileEntity: TileEntity) =
tileEntity match {
case host: TileMultipart => (host.partList collect {
case cable: CablePart => cable.color
}).headOption.getOrElse(Color.LightGray)
case _ => Color.LightGray
}
private def canConnectBasedOnColor(te1: TileEntity, te2: TileEntity) = {
val (c1, c2) = (cableColor(te1), cableColor(te2))
c1 == c2 || c1 == Color.LightGray || c2 == Color.LightGray
}
private def canConnectFromSideFMP(tileEntity: TileEntity, side: ForgeDirection) =
tileEntity match {
case host: TileMultipart =>
host.partList.forall {
case part: JNormalOcclusion if !part.isInstanceOf[CablePart] =>
import scala.collection.convert.WrapAsScala._
val ownBounds = Iterable(new Cuboid6(cachedBounds(side.flag)))
val otherBounds = part.getOcclusionBoxes
NormalOcclusionTest(ownBounds, otherBounds)
case part: TFacePart => !part.solid(side.ordinal) || (part.getSlotMask & codechicken.multipart.PartMap.face(side.ordinal).mask) == 0
case _ => true
}
case _ => true
}
private def canConnectFromSideIM(tileEntity: TileEntity, side: ForgeDirection) =
tileEntity match {
case im: tileentity.traits.ImmibisMicroblock => im.ImmibisMicroblocks_isSideOpen(side.ordinal)
case _ => true
}
}